diff --git a/.gitignore b/.gitignore index f483db0..d283acd 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,5 @@ node_modules/ # build directory /dist/ + +*.db* diff --git a/Makefile b/Makefile index cfae937..69ede60 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ run: # disable inlining go test -benchmem -bench=. -gcflags '-l' github.com/skerkour/go-benchmarks/cgo go test -benchmem -bench=. github.com/skerkour/go-benchmarks/encoding + go test -cpu=5000 -bench=. github.com/skerkour/go-benchmarks/pointer_swap .PHONY: run_docker run_docker: diff --git a/encoding/encoding_test.go b/encoding/encoding_test.go index d14cf34..47694c3 100644 --- a/encoding/encoding_test.go +++ b/encoding/encoding_test.go @@ -7,8 +7,8 @@ import ( "fmt" "testing" - stdxbase32 "git.sr.ht/~pingoo/stdx/base32" akamenskybase58 "github.com/akamensky/base58" + stdxbase32 "github.com/bloom42/stdx/base32" mrtronbase58 "github.com/mr-tron/base58" "github.com/skerkour/go-benchmarks/utils" ) diff --git a/encryption_aead/encryption_test.go b/encryption_aead/encryption_test.go index 3764f76..31683ae 100644 --- a/encryption_aead/encryption_test.go +++ b/encryption_aead/encryption_test.go @@ -6,10 +6,10 @@ import ( "fmt" "testing" - "git.sr.ht/~pingoo/stdx/crypto/bchacha20blake3" - "git.sr.ht/~pingoo/stdx/crypto/chacha20" - "git.sr.ht/~pingoo/stdx/crypto/chacha20blake3" - "git.sr.ht/~pingoo/stdx/crypto/schacha20blake3" + "github.com/bloom42/stdx/crypto/bchacha20blake3" + "github.com/bloom42/stdx/crypto/chacha20" + "github.com/bloom42/stdx/crypto/chacha20blake3" + "github.com/bloom42/stdx/crypto/schacha20blake3" "github.com/skerkour/go-benchmarks/utils" "golang.org/x/crypto/chacha20poly1305" ) diff --git a/encryption_unauthenticated/encryption_test.go b/encryption_unauthenticated/encryption_test.go index 7817a68..dcad95f 100644 --- a/encryption_unauthenticated/encryption_test.go +++ b/encryption_unauthenticated/encryption_test.go @@ -8,8 +8,8 @@ import ( "fmt" "testing" - "git.sr.ht/~pingoo/stdx/crypto/chacha" - "git.sr.ht/~pingoo/stdx/crypto/chacha20" + "github.com/bloom42/stdx/crypto/chacha" + "github.com/bloom42/stdx/crypto/chacha20" "github.com/skerkour/go-benchmarks/utils" "golang.org/x/crypto/chacha20poly1305" ) diff --git a/go.mod b/go.mod index 739ca69..076ee4f 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.22 toolchain go1.22.0 require ( - git.sr.ht/~pingoo/stdx v0.0.0-20240217105719-1fd78f676abd github.com/DataDog/zstd v1.5.5 github.com/akamensky/base58 v0.0.0-20210829145138-ce8bf8802e8f + github.com/bloom42/stdx v0.0.0-20240218143014-e4c67700e2a4 github.com/cespare/xxhash/v2 v2.2.0 github.com/golang/snappy v0.0.4 github.com/google/uuid v1.6.0 diff --git a/go.sum b/go.sum index 48b73d8..5fb6049 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -git.sr.ht/~pingoo/stdx v0.0.0-20240217105719-1fd78f676abd h1:U+GKt+LdItrnZ2ecv5ZRrVyidm3YorMWLKAXkwNI6GM= -git.sr.ht/~pingoo/stdx v0.0.0-20240217105719-1fd78f676abd/go.mod h1:Ms7ttIDy+TIfF2khURNDiOVEVgxhMbUoaXf0+MxUqgM= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/akamensky/base58 v0.0.0-20210829145138-ce8bf8802e8f h1:z8MkSJCUyTmW5YQlxsMLBlwA7GmjxC7L4ooicxqnhz8= github.com/akamensky/base58 v0.0.0-20210829145138-ce8bf8802e8f/go.mod h1:UdUwYgAXBiL+kLfcqxoQJYkHA/vl937/PbFhZM34aZs= +github.com/bloom42/stdx v0.0.0-20240218143014-e4c67700e2a4 h1:MUjoNZoxFWXSIG3sOqgt5EBm9KyFHolBPuoAD3TllF8= +github.com/bloom42/stdx v0.0.0-20240218143014-e4c67700e2a4/go.mod h1:05zc5Smz6IZebUjC6ejRZ4s6BuMjW0yi1rHdWYKr96s= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= diff --git a/kdf/kdf_test.go b/kdf/kdf_test.go index 3c3d9b9..58d4830 100644 --- a/kdf/kdf_test.go +++ b/kdf/kdf_test.go @@ -7,7 +7,7 @@ import ( "io" "testing" - "git.sr.ht/~pingoo/stdx/crypto/chacha20" + "github.com/bloom42/stdx/crypto/chacha20" "github.com/skerkour/go-benchmarks/utils" zeeboblake3 "github.com/zeebo/blake3" "golang.org/x/crypto/hkdf" diff --git a/pointer_swap/swap_test.go b/pointer_swap/swap_test.go new file mode 100644 index 0000000..9dd764a --- /dev/null +++ b/pointer_swap/swap_test.go @@ -0,0 +1,50 @@ +package swap + +import ( + "sync" + "sync/atomic" + "testing" + "unsafe" +) + +func BenchmarkParallelAtomicPointerRead(b *testing.B) { + var ptr unsafe.Pointer + data := make(map[int]int) + data[1] = 1 + atomic.StorePointer(&ptr, unsafe.Pointer(&data)) + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + localData := (*map[int]int)(atomic.LoadPointer(&ptr)) + _ = (*localData)[1] + } + }) +} + +func BenchmarkParallelAtomicValueRead(b *testing.B) { + var ptr atomic.Value + data := make(map[int]int) + data[1] = 1 + ptr.Store(data) + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + localData := ptr.Load().(map[int]int) + _ = localData[1] + } + }) +} + +func BenchmarkParallelRWMutexRead(b *testing.B) { + var mutex sync.RWMutex + data := make(map[int]int) + data[1] = 1 + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + mutex.RLock() + _ = data[1] + mutex.RUnlock() + } + }) +} diff --git a/pointers/pointers_test.go b/pointers/pointers_test.go new file mode 100644 index 0000000..566fb18 --- /dev/null +++ b/pointers/pointers_test.go @@ -0,0 +1,354 @@ +// from https://github.com/learning-go-book-2e/ch06/blob/main/sample_code/pointer_perf/perf_test.go +package pointers + +import "testing" + +var x byte + +//go:noinline +func BenchmarkPointer_10_In(b *testing.B) { + var v v10 + for i := 0; i < b.N; i++ { + readMiddle10p(&v) + } +} + +//go:noinline +func BenchmarkValue_10_In(b *testing.B) { + var v v10 + for i := 0; i < b.N; i++ { + readMiddle10(v) + } +} + +//go:noinline +func BenchmarkPointer_10_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get10p() + x = v.data[5] + } +} + +//go:noinline +func BenchmarkValue_10_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get10v() + x = v.data[5] + } +} + +type v10 struct { + data [10]byte +} + +//go:noinline +func readMiddle10(v v10) { + x = v.data[5] +} + +//go:noinline +func readMiddle10p(v *v10) { + x = v.data[5] +} + +//go:noinline +func get10p() *v10 { + var v v10 + return &v +} + +//go:noinline +func get10v() v10 { + var v v10 + return v +} + +//go:noinline +func BenchmarkPointer_100_In(b *testing.B) { + var v v100 + for i := 0; i < b.N; i++ { + readMiddle100p(&v) + } +} + +//go:noinline +func BenchmarkValue_100_In(b *testing.B) { + var v v100 + for i := 0; i < b.N; i++ { + readMiddle100(v) + } +} + +//go:noinline +func BenchmarkPointer_100_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get100p() + x = v.data[50] + } +} + +//go:noinline +func BenchmarkValue_100_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get100v() + x = v.data[50] + } +} + +type v100 struct { + data [100]byte +} + +//go:noinline +func readMiddle100(v v100) { + x = v.data[50] +} + +//go:noinline +func readMiddle100p(v *v100) { + x = v.data[50] +} + +//go:noinline +func get100p() *v100 { + var v v100 + return &v +} + +//go:noinline +func get100v() v100 { + var v v100 + return v +} + +//go:noinline +func BenchmarkPointer_1_000_In(b *testing.B) { + var v v1_000 + for i := 0; i < b.N; i++ { + readMiddle1_000p(&v) + } +} + +//go:noinline +func BenchmarkValue_1_000_In(b *testing.B) { + var v v1_000 + for i := 0; i < b.N; i++ { + readMiddle1_000(v) + } +} + +//go:noinline +func BenchmarkPointer_1_000_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get1_000p() + x = v.data[500] + } +} + +//go:noinline +func BenchmarkValue_1_000_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get1_000v() + x = v.data[500] + } +} + +type v1_000 struct { + data [1_000]byte +} + +//go:noinline +func readMiddle1_000(v v1_000) { + x = v.data[500] +} + +//go:noinline +func readMiddle1_000p(v *v1_000) { + x = v.data[500] +} + +//go:noinline +func get1_000p() *v1_000 { + var v v1_000 + return &v +} + +//go:noinline +func get1_000v() v1_000 { + var v v1_000 + return v +} + +//go:noinline +func BenchmarkPointer_100_000_In(b *testing.B) { + var v v100_000 + for i := 0; i < b.N; i++ { + readMiddle100_000p(&v) + } +} + +//go:noinline +func BenchmarkValue_100_000_In(b *testing.B) { + var v v100_000 + for i := 0; i < b.N; i++ { + readMiddle100_000(v) + } +} + +//go:noinline +func BenchmarkPointer_100_000_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get100_000p() + x = v.data[50_000] + } +} + +//go:noinline +func BenchmarkValue_100_000_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get100_000v() + x = v.data[50_000] + } +} + +type v100_000 struct { + data [100_000]byte +} + +//go:noinline +func readMiddle100_000(v v100_000) { + x = v.data[50_000] +} + +//go:noinline +func readMiddle100_000p(v *v100_000) { + x = v.data[50_000] +} + +//go:noinline +func get100_000p() *v100_000 { + var v v100_000 + return &v +} + +//go:noinline +func get100_000v() v100_000 { + var v v100_000 + return v +} + +//go:noinline +func BenchmarkPointer_1_000_000_In(b *testing.B) { + var v v1_000_000 + for i := 0; i < b.N; i++ { + readMiddle1_000_000p(&v) + } +} + +//go:noinline +func BenchmarkValue_1_000_000_In(b *testing.B) { + var v v1_000_000 + for i := 0; i < b.N; i++ { + readMiddle1_000_000(v) + } +} + +//go:noinline +func BenchmarkPointer_1_000_000_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get1_000_000p() + x = v.data[500_000] + } +} + +//go:noinline +func BenchmarkValue_1_000_000_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get1_000_000v() + x = v.data[500_000] + } +} + +type v1_000_000 struct { + data [1_000_000]byte +} + +//go:noinline +func readMiddle1_000_000(v v1_000_000) { + x = v.data[500_000] +} + +//go:noinline +func readMiddle1_000_000p(v *v1_000_000) { + x = v.data[500_000] +} + +//go:noinline +func get1_000_000p() *v1_000_000 { + var v v1_000_000 + return &v +} + +//go:noinline +func get1_000_000v() v1_000_000 { + var v v1_000_000 + return v +} + +//go:noinline +func BenchmarkPointer_10_000_000_In(b *testing.B) { + var v v10_000_000 + for i := 0; i < b.N; i++ { + readMiddle10_000_000p(&v) + } +} + +//go:noinline +func BenchmarkValue_10_000_000_In(b *testing.B) { + var v v10_000_000 + for i := 0; i < b.N; i++ { + readMiddle10_000_000(v) + } +} + +//go:noinline +func BenchmarkPointer_10_000_000_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get10_000_000p() + x = v.data[5_000_000] + } +} + +//go:noinline +func BenchmarkValue_10_000_000_Out(b *testing.B) { + for i := 0; i < b.N; i++ { + v := get10_000_000v() + x = v.data[5_000_000] + } +} + +type v10_000_000 struct { + data [10_000_000]byte +} + +//go:noinline +func readMiddle10_000_000(v v10_000_000) { + x = v.data[5_000_000] +} + +//go:noinline +func readMiddle10_000_000p(v *v10_000_000) { + x = v.data[5_000_000] +} + +//go:noinline +func get10_000_000p() *v10_000_000 { + var v v10_000_000 + return &v +} + +//go:noinline +func get10_000_000v() v10_000_000 { + var v v10_000_000 + return v +} diff --git a/sqlite/main.go b/sqlite/main.go index 9779575..4c53cdd 100644 --- a/sqlite/main.go +++ b/sqlite/main.go @@ -42,7 +42,7 @@ func (t *Time) Value() (driver.Value, error) { type entity struct { ID uuid.UUID - CreatedAt Time + Timestamp Time Counter int64 } @@ -68,9 +68,8 @@ func setupSqlite(db *sql.DB) (err error) { } func main() { - os.RemoveAll("./test.db") - os.RemoveAll("./test.db-shm") - os.RemoveAll("./test.db-wal") + cleanup() + defer cleanup() uuid.EnableRandPool() @@ -81,12 +80,9 @@ func main() { connectionUrlParams.Add("_synchronous", "NORMAL") connectionUrlParams.Add("_cache_size", "1000000000") connectionUrlParams.Add("_foreign_keys", "true") - connectionUrl, err := url.Parse("./test.db?" + connectionUrlParams.Encode()) - if err != nil { - log.Fatal(err) - } + connectionUrl := "./test.db?" + connectionUrlParams.Encode() - writeDB, err := sql.Open("sqlite3", connectionUrl.String()) + writeDB, err := sql.Open("sqlite3", connectionUrl) if err != nil { log.Fatal(err) } @@ -97,7 +93,7 @@ func main() { log.Fatal(err) } - readDB, err := sql.Open("sqlite3", connectionUrl.String()) + readDB, err := sql.Open("sqlite3", connectionUrl) if err != nil { log.Fatal(err) } @@ -110,7 +106,7 @@ func main() { _, err = writeDB.Exec(`CREATE TABLE test ( id BLOB NOT NULL PRIMARY KEY, - created_at INTEGER NOT NULL, + timestamp INTEGER NOT NULL, counter INT NOT NULL ) STRICT`) if err != nil { @@ -130,11 +126,11 @@ func main() { wg.Add(concurrentReaders) for c := 0; c < concurrentReaders; c += 1 { go func() { - // we use a goroutine-local counter to avoid the performance impact of updating an atomic counter + // we use a goroutine-local counter to avoid the performance impact of updating a shared atomic counter var readsLocal int64 for { - var something entity + var record entity if len(ticker.C) > 0 { break @@ -149,7 +145,7 @@ func main() { continue } - rows.Scan(&something.ID, &something.CreatedAt, &something.Counter) + rows.Scan(&record.ID, &record.Timestamp, &record.Counter) rows.Close() readsLocal += 1 } @@ -161,8 +157,8 @@ func main() { wg.Add(concurrentWriters) for c := 0; c < concurrentWriters; c += 1 { go func() { - startUnixMilliseconds := start.UnixMilli() - // we use a goroutine-local counter to avoid the performance impact of updating an atomic counter + timestamp := start.UnixMilli() + // we use a goroutine-local counter to avoid the performance impact of updating a shared atomic counter var writesLocal int64 for { @@ -170,10 +166,10 @@ func main() { break } - uu := uuid.New() + recordID := uuid.Must(uuid.NewV7()) _, err = writeDB.Exec(`INSERT INTO test - (id, created_at, counter) VALUES (?, ?, ?)`, uu[:], startUnixMilliseconds, writes.Load()) + (id, timestamp, counter) VALUES (?, ?, ?)`, recordID[:], timestamp, 1) if err != nil { log.Fatal(err) } @@ -202,3 +198,9 @@ func main() { throughputWrite := float64(writes.Load()) / float64(elapsed.Seconds()) log.Printf("%f writes/s\n", throughputWrite) } + +func cleanup() { + os.RemoveAll("./test.db") + os.RemoveAll("./test.db-shm") + os.RemoveAll("./test.db-wal") +} diff --git a/tools/system_info/main.go b/tools/system_info/main.go index 203d706..fc2f913 100644 --- a/tools/system_info/main.go +++ b/tools/system_info/main.go @@ -5,7 +5,7 @@ import ( "runtime" "time" - "git.sr.ht/~pingoo/stdx/cpuinfo" + "github.com/bloom42/stdx/cpuinfo" "golang.org/x/sys/cpu" )