diff --git a/bench/encode_decode_test.go b/bench/encode_decode_test.go new file mode 100644 index 0000000..4178c42 --- /dev/null +++ b/bench/encode_decode_test.go @@ -0,0 +1,141 @@ +package bench + +import ( + "testing" + "time" + + "github.com/zikwall/clickhouse-buffer/v3/src/cx" +) + +type row struct { + id int + uuid string + insertTS time.Time +} + +func (r *row) Row() cx.Vector { + return cx.Vector{r.id, r.uuid, r.insertTS.Format(time.RFC822)} +} + +// goos: linux +// goarch: amd64 +// pkg: github.com/zikwall/clickhouse-buffer/v3/bench +// cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz +// BenchmarkEncodeRow/1000000-12 100 30361854 ns/op 15847294 B/op 240014 allocs/op +// BenchmarkEncodeRow/100000-12 100 2946954 ns/op 1584748 B/op 24001 allocs/op +// BenchmarkEncodeRow/10000-12 100 289346 ns/op 158465 B/op 2400 allocs/op +// BenchmarkEncodeRow/1000-12 100 31659 ns/op 15857 B/op 240 allocs/op +// BenchmarkEncodeRow/100-12 100 3089 ns/op 1584 B/op 24 allocs/op +// BenchmarkEncodeRow/10-12 100 383.0 ns/op 158 B/op 2 allocs/op +// PASS +// ok +// nolint:dupl // it's OK +func BenchmarkEncodeRow(b *testing.B) { + b.Run("1000000", func(b *testing.B) { + for i := 0; i < b.N; i++ { + encode(1000000, b) + } + }) + b.Run("100000", func(b *testing.B) { + for i := 0; i < b.N; i++ { + encode(100000, b) + } + }) + b.Run("10000", func(b *testing.B) { + for i := 0; i < b.N; i++ { + encode(10000, b) + } + }) + b.Run("1000", func(b *testing.B) { + for i := 0; i < b.N; i++ { + encode(1000, b) + } + }) + b.Run("100", func(b *testing.B) { + for i := 0; i < b.N; i++ { + encode(100, b) + } + }) + b.Run("10", func(b *testing.B) { + for i := 0; i < b.N; i++ { + encode(10, b) + } + }) +} + +// goos: linux +// goarch: amd64 +// pkg: github.com/zikwall/clickhouse-buffer/v3/bench +// cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz +// BenchmarkDecodeRow/100000-12 100 17739535 ns/op 7653390 B/op 200064 allocs/op +// BenchmarkDecodeRow/10000-12 100 1867818 ns/op 765345 B/op 20006 allocs/op +// BenchmarkDecodeRow/1000-12 100 181877 ns/op 76521 B/op 2000 allocs/op +// BenchmarkDecodeRow/100-12 100 16230 ns/op 7656 B/op 200 allocs/op +// BenchmarkDecodeRow/10-12 100 1661 ns/op 764 B/op 20 allocs/op +// BenchmarkDecodeRow/1-12 100 227.0 ns/op 76 B/op 2 allocs/op +// PASS +// ok +// nolint:dupl // it's OK +func BenchmarkDecodeRow(b *testing.B) { + b.Run("100000", func(b *testing.B) { + for i := 0; i < b.N; i++ { + decode(100000, b) + } + }) + b.Run("10000", func(b *testing.B) { + for i := 0; i < b.N; i++ { + decode(10000, b) + } + }) + b.Run("1000", func(b *testing.B) { + for i := 0; i < b.N; i++ { + decode(1000, b) + } + }) + b.Run("100", func(b *testing.B) { + for i := 0; i < b.N; i++ { + decode(100, b) + } + }) + b.Run("10", func(b *testing.B) { + for i := 0; i < b.N; i++ { + decode(10, b) + } + }) + b.Run("1", func(b *testing.B) { + for i := 0; i < b.N; i++ { + decode(1, b) + } + }) +} + +func encode(x int, b *testing.B) { + now := time.Now() + b.ResetTimer() + for i := 0; i < x; i++ { + r := row{ + id: 1, + uuid: "uuid_here", + insertTS: now, + } + _, _ = r.Row().Encode() + } +} + +func decode(x int, b *testing.B) { + now := time.Now() + encodes := make([]cx.VectorDecoded, 0, x) + for i := 0; i < x; i++ { + r := row{ + id: 1, + uuid: "uuid_here", + insertTS: now, + } + enc, _ := r.Row().Encode() + encodes = append(encodes, cx.VectorDecoded(enc)) + } + b.ResetTimer() + for i := range encodes { + _, _ = encodes[i].Decode() + } +} diff --git a/bench/insert_simple_test.go b/bench/insert_simple_test.go index 990e68b..df571b8 100644 --- a/bench/insert_simple_test.go +++ b/bench/insert_simple_test.go @@ -46,11 +46,11 @@ func (c *clickhouseMock) Conn() driver.Conn { // goarch: amd64 // pkg: github.com/zikwall/clickhouse-buffer/v3/bench // cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz -// BenchmarkInsertRedisObjects/10000-12 10 2035777840 ns/op 9124870 B/op 223549 allocs/op -// BenchmarkInsertRedisObjects/1000-12 10 208882330 ns/op 926325 B/op 22709 allocs/op -// BenchmarkInsertRedisObjects/100-12 10 19944150 ns/op 92810 B/op 2273 allocs/op -// BenchmarkInsertRedisObjects/10-12 10 1891890 ns/op 1588 B/op 28 allocs/op -// BenchmarkInsertRedisObjects/1-12 10 182180 ns/op 160 B/op 2 allocs/op +// BenchmarkInsertRedisObjects/10000-12 10 2165062600 ns/op 8949147 B/op 215127 allocs/op +// BenchmarkInsertRedisObjects/1000-12 10 205537440 ns/op 960664 B/op 23209 allocs/op +// BenchmarkInsertRedisObjects/100-12 10 20371570 ns/op 96292 B/op 2323 allocs/op +// BenchmarkInsertRedisObjects/10-12 10 2216160 ns/op 1868 B/op 32 allocs/op +// BenchmarkInsertRedisObjects/1-12 10 180490 ns/op 188 B/op 3 allocs/op // PASS // ok // nolint:funlen,dupl // it's not important here @@ -68,6 +68,139 @@ func BenchmarkInsertRedisObjects(b *testing.B) { var writeAPI clickhousebuffer.Writer b.ResetTimer() + b.Run("10000", func(b *testing.B) { + client.Options().SetBatchSize(10000) + rxbuffer, err := cxredis.NewBuffer(ctx, redis.NewClient(&redis.Options{ + Addr: redisHost, + Password: redisPass, + DB: 11, + }), "bucket", client.Options().BatchSize()) + if err != nil { + log.Panicln(err) + } + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + rxbuffer, + ) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + insertObjects(writeAPI, 10000, b) + } + }) + + b.Run("1000", func(b *testing.B) { + client.Options().SetBatchSize(1000) + rxbuffer, err := cxredis.NewBuffer(ctx, redis.NewClient(&redis.Options{ + Addr: redisHost, + Password: redisPass, + }), "bucket", client.Options().BatchSize()) + if err != nil { + log.Panicln(err) + } + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + rxbuffer, + ) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + insertObjects(writeAPI, 1000, b) + } + }) + + b.Run("100", func(b *testing.B) { + client.Options().SetBatchSize(100) + rxbuffer, err := cxredis.NewBuffer(ctx, redis.NewClient(&redis.Options{ + Addr: redisHost, + Password: redisPass, + }), "bucket", client.Options().BatchSize()) + if err != nil { + log.Panicln(err) + } + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + rxbuffer, + ) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + insertObjects(writeAPI, 100, b) + } + }) + + b.Run("10", func(b *testing.B) { + client.Options().SetBatchSize(10) + rxbuffer, err := cxredis.NewBuffer(ctx, redis.NewClient(&redis.Options{ + Addr: redisHost, + Password: redisPass, + }), "bucket", client.Options().BatchSize()) + if err != nil { + log.Panicln(err) + } + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + rxbuffer, + ) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + insertObjects(writeAPI, 10, b) + } + }) + + b.Run("1", func(b *testing.B) { + client.Options().SetBatchSize(1) + rxbuffer, err := cxredis.NewBuffer(ctx, redis.NewClient(&redis.Options{ + Addr: redisHost, + Password: redisPass, + }), "bucket", client.Options().BatchSize()) + if err != nil { + log.Panicln(err) + } + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + rxbuffer, + ) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + insertObjects(writeAPI, 1, b) + } + }) + + b.StopTimer() + writeAPI.Close() + client.Close() +} + +// x10 +// goos: linux +// goarch: amd64 +// pkg: github.com/zikwall/clickhouse-buffer/v3/bench +// cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz +// BenchmarkInsertRedisVectors/10000-12 10 2035777840 ns/op 9124870 B/op 223549 allocs/op +// BenchmarkInsertRedisVectors/1000-12 10 208882330 ns/op 926325 B/op 22709 allocs/op +// BenchmarkInsertRedisVectors/100-12 10 19944150 ns/op 92810 B/op 2273 allocs/op +// BenchmarkInsertRedisVectors/10-12 10 1891890 ns/op 1588 B/op 28 allocs/op +// BenchmarkInsertRedisVectors/1-12 10 182180 ns/op 160 B/op 2 allocs/op +// PASS +// ok +// nolint:funlen,dupl // it's not important here +func BenchmarkInsertRedisVectors(b *testing.B) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + client := clickhousebuffer.NewClientWithOptions(ctx, &clickhouseMock{}, + clickhousebuffer.DefaultOptions(). + SetDebugMode(false). + SetFlushInterval(10000). + SetBatchSize(1000), + ) + redisHost := os.Getenv("REDIS_HOST") + redisPass := os.Getenv("REDIS_PASS") + var writeAPI clickhousebuffer.Writer + b.ResetTimer() + b.Run("10000", func(b *testing.B) { client.Options().SetBatchSize(10000) rxbuffer, err := cxredis.NewBuffer(ctx, redis.NewClient(&redis.Options{ @@ -595,6 +728,110 @@ func BenchmarkInsertSimplestVectors(b *testing.B) { client.Close() } +// goos: linux +// goarch: amd64 +// pkg: github.com/zikwall/clickhouse-buffer/v3/bench +// cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz +// BenchmarkInsertSimplestEmptyVectors/10000000-12 100 22317607 ns/op 0 B/op 0 allocs/op +// BenchmarkInsertSimplestEmptyVectors/1000000-12 100 1246957 ns/op 240026 B/op 0 allocs/op +// BenchmarkInsertSimplestEmptyVectors/100000-12 100 125928 ns/op 24002 B/op 0 allocs/op +// BenchmarkInsertSimplestEmptyVectors/10000-12 100 13788 ns/op 2457 B/op 0 allocs/op +// BenchmarkInsertSimplestEmptyVectors/1000-12 100 1475 ns/op 246 B/op 0 allocs/op +// BenchmarkInsertSimplestEmptyVectors/100-12 100 282.0 ns/op 54 B/op 0 allocs/op +// PASS +// ok +// nolint:lll,dupl // it's OK +func BenchmarkInsertSimplestEmptyVectors(b *testing.B) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + client := clickhousebuffer.NewClientWithOptions(ctx, &clickhouseMock{}, + clickhousebuffer.DefaultOptions(). + SetDebugMode(false). + SetFlushInterval(10000000). + SetBatchSize(100), + ) + + var writeAPI clickhousebuffer.Writer + b.ResetTimer() + + b.Run("10000000", func(b *testing.B) { + client.Options().SetBatchSize(10000000) + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + cxmem.NewBuffer(client.Options().BatchSize()), + ) + b.ResetTimer() + for i := 0; i < b.N; i++ { + insertEmptyVectors(writeAPI, 10000000, b) + } + }) + + b.Run("1000000", func(b *testing.B) { + client.Options().SetBatchSize(1000000) + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + cxmem.NewBuffer(client.Options().BatchSize()), + ) + b.ResetTimer() + for i := 0; i < b.N; i++ { + insertEmptyVectors(writeAPI, 1000000, b) + } + }) + + b.Run("100000", func(b *testing.B) { + client.Options().SetBatchSize(100000) + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + cxmem.NewBuffer(client.Options().BatchSize()), + ) + b.ResetTimer() + for i := 0; i < b.N; i++ { + insertEmptyVectors(writeAPI, 100000, b) + } + }) + + b.Run("10000", func(b *testing.B) { + client.Options().SetBatchSize(10000) + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + cxmem.NewBuffer(client.Options().BatchSize()), + ) + b.ResetTimer() + for i := 0; i < b.N; i++ { + insertEmptyVectors(writeAPI, 10000, b) + } + }) + + b.Run("1000", func(b *testing.B) { + client.Options().SetBatchSize(1000) + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + cxmem.NewBuffer(client.Options().BatchSize()), + ) + b.ResetTimer() + for i := 0; i < b.N; i++ { + insertEmptyVectors(writeAPI, 1000, b) + } + }) + + b.Run("100", func(b *testing.B) { + client.Options().SetBatchSize(100) + writeAPI = client.Writer( + cx.NewView(tables.ExampleTableName(), tables.ExampleTableColumns()), + cxmem.NewBuffer(client.Options().BatchSize()), + ) + b.ResetTimer() + for i := 0; i < b.N; i++ { + insertEmptyVectors(writeAPI, 100, b) + } + }) + + b.StopTimer() + writeAPI.Close() + client.Close() +} + func insertObjects(writeAPI clickhousebuffer.Writer, x int, b *testing.B) { b.ResetTimer() var object *BenchTable @@ -613,6 +850,13 @@ func insertVectors(writeAPI clickhousebuffer.Writer, x int, b *testing.B) { } } +func insertEmptyVectors(writeAPI clickhousebuffer.Writer, x int, b *testing.B) { + b.ResetTimer() + for i := 0; i < x; i++ { + writeAPI.WriteVector(cx.Vector{}) + } +} + func insertPreAllocatedObjects(writeAPI clickhousebuffer.Writer, x int, b *testing.B) { objects := make([]cx.Vectorable, 0, x+1) for i := 0; i < x; i++ {