diff options
Diffstat (limited to '')
-rw-r--r-- | dependencies/pkg/mod/github.com/go-redis/redis/v8@v8.11.5/bench_decode_test.go | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/dependencies/pkg/mod/github.com/go-redis/redis/v8@v8.11.5/bench_decode_test.go b/dependencies/pkg/mod/github.com/go-redis/redis/v8@v8.11.5/bench_decode_test.go new file mode 100644 index 0000000..8382806 --- /dev/null +++ b/dependencies/pkg/mod/github.com/go-redis/redis/v8@v8.11.5/bench_decode_test.go @@ -0,0 +1,309 @@ +package redis + +import ( + "context" + "fmt" + "io" + "net" + "testing" + "time" + + "github.com/go-redis/redis/v8/internal/proto" +) + +var ctx = context.TODO() + +type ClientStub struct { + Cmdable + resp []byte +} + +func NewClientStub(resp []byte) *ClientStub { + stub := &ClientStub{ + resp: resp, + } + stub.Cmdable = NewClient(&Options{ + PoolSize: 128, + Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) { + return stub.stubConn(), nil + }, + }) + return stub +} + +func NewClusterClientStub(resp []byte) *ClientStub { + stub := &ClientStub{ + resp: resp, + } + + client := NewClusterClient(&ClusterOptions{ + PoolSize: 128, + Addrs: []string{"127.0.0.1:6379"}, + Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) { + return stub.stubConn(), nil + }, + ClusterSlots: func(_ context.Context) ([]ClusterSlot, error) { + return []ClusterSlot{ + { + Start: 0, + End: 16383, + Nodes: []ClusterNode{{Addr: "127.0.0.1:6379"}}, + }, + }, nil + }, + }) + + // init command. + tmpClient := NewClient(&Options{Addr: ":6379"}) + cmdsInfo, err := tmpClient.Command(ctx).Result() + _ = tmpClient.Close() + client.cmdsInfoCache = newCmdsInfoCache(func(_ context.Context) (map[string]*CommandInfo, error) { + return cmdsInfo, err + }) + + stub.Cmdable = client + return stub +} + +func (c *ClientStub) stubConn() *ConnStub { + return &ConnStub{ + resp: c.resp, + } +} + +type ConnStub struct { + resp []byte + pos int +} + +func (c *ConnStub) Read(b []byte) (n int, err error) { + if len(c.resp) == 0 { + return 0, io.EOF + } + + if c.pos >= len(c.resp) { + c.pos = 0 + } + n = copy(b, c.resp[c.pos:]) + c.pos += n + return n, nil +} + +func (c *ConnStub) Write(b []byte) (n int, err error) { return len(b), nil } +func (c *ConnStub) Close() error { return nil } +func (c *ConnStub) LocalAddr() net.Addr { return nil } +func (c *ConnStub) RemoteAddr() net.Addr { return nil } +func (c *ConnStub) SetDeadline(_ time.Time) error { return nil } +func (c *ConnStub) SetReadDeadline(_ time.Time) error { return nil } +func (c *ConnStub) SetWriteDeadline(_ time.Time) error { return nil } + +type ClientStubFunc func([]byte) *ClientStub + +func BenchmarkDecode(b *testing.B) { + type Benchmark struct { + name string + stub ClientStubFunc + } + + benchmarks := []Benchmark{ + {"single", NewClientStub}, + {"cluster", NewClusterClientStub}, + } + + for _, bench := range benchmarks { + b.Run(fmt.Sprintf("RespError-%s", bench.name), func(b *testing.B) { + respError(b, bench.stub) + }) + b.Run(fmt.Sprintf("RespStatus-%s", bench.name), func(b *testing.B) { + respStatus(b, bench.stub) + }) + b.Run(fmt.Sprintf("RespInt-%s", bench.name), func(b *testing.B) { + respInt(b, bench.stub) + }) + b.Run(fmt.Sprintf("RespString-%s", bench.name), func(b *testing.B) { + respString(b, bench.stub) + }) + b.Run(fmt.Sprintf("RespArray-%s", bench.name), func(b *testing.B) { + respArray(b, bench.stub) + }) + b.Run(fmt.Sprintf("RespPipeline-%s", bench.name), func(b *testing.B) { + respPipeline(b, bench.stub) + }) + b.Run(fmt.Sprintf("RespTxPipeline-%s", bench.name), func(b *testing.B) { + respTxPipeline(b, bench.stub) + }) + + // goroutine + b.Run(fmt.Sprintf("DynamicGoroutine-%s-pool=5", bench.name), func(b *testing.B) { + dynamicGoroutine(b, bench.stub, 5) + }) + b.Run(fmt.Sprintf("DynamicGoroutine-%s-pool=20", bench.name), func(b *testing.B) { + dynamicGoroutine(b, bench.stub, 20) + }) + b.Run(fmt.Sprintf("DynamicGoroutine-%s-pool=50", bench.name), func(b *testing.B) { + dynamicGoroutine(b, bench.stub, 50) + }) + b.Run(fmt.Sprintf("DynamicGoroutine-%s-pool=100", bench.name), func(b *testing.B) { + dynamicGoroutine(b, bench.stub, 100) + }) + + b.Run(fmt.Sprintf("StaticGoroutine-%s-pool=5", bench.name), func(b *testing.B) { + staticGoroutine(b, bench.stub, 5) + }) + b.Run(fmt.Sprintf("StaticGoroutine-%s-pool=20", bench.name), func(b *testing.B) { + staticGoroutine(b, bench.stub, 20) + }) + b.Run(fmt.Sprintf("StaticGoroutine-%s-pool=50", bench.name), func(b *testing.B) { + staticGoroutine(b, bench.stub, 50) + }) + b.Run(fmt.Sprintf("StaticGoroutine-%s-pool=100", bench.name), func(b *testing.B) { + staticGoroutine(b, bench.stub, 100) + }) + } +} + +func respError(b *testing.B, stub ClientStubFunc) { + rdb := stub([]byte("-ERR test error\r\n")) + respErr := proto.RedisError("ERR test error") + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if err := rdb.Get(ctx, "key").Err(); err != respErr { + b.Fatalf("response error, got %q, want %q", err, respErr) + } + } +} + +func respStatus(b *testing.B, stub ClientStubFunc) { + rdb := stub([]byte("+OK\r\n")) + var val string + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if val = rdb.Set(ctx, "key", "value", 0).Val(); val != "OK" { + b.Fatalf("response error, got %q, want OK", val) + } + } +} + +func respInt(b *testing.B, stub ClientStubFunc) { + rdb := stub([]byte(":10\r\n")) + var val int64 + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if val = rdb.Incr(ctx, "key").Val(); val != 10 { + b.Fatalf("response error, got %q, want 10", val) + } + } +} + +func respString(b *testing.B, stub ClientStubFunc) { + rdb := stub([]byte("$5\r\nhello\r\n")) + var val string + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if val = rdb.Get(ctx, "key").Val(); val != "hello" { + b.Fatalf("response error, got %q, want hello", val) + } + } +} + +func respArray(b *testing.B, stub ClientStubFunc) { + rdb := stub([]byte("*3\r\n$5\r\nhello\r\n:10\r\n+OK\r\n")) + var val []interface{} + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if val = rdb.MGet(ctx, "key").Val(); len(val) != 3 { + b.Fatalf("response error, got len(%d), want len(3)", len(val)) + } + } +} + +func respPipeline(b *testing.B, stub ClientStubFunc) { + rdb := stub([]byte("+OK\r\n$5\r\nhello\r\n:1\r\n")) + var pipe Pipeliner + + b.ResetTimer() + for i := 0; i < b.N; i++ { + pipe = rdb.Pipeline() + set := pipe.Set(ctx, "key", "value", 0) + get := pipe.Get(ctx, "key") + del := pipe.Del(ctx, "key") + _, err := pipe.Exec(ctx) + if err != nil { + b.Fatalf("response error, got %q, want nil", err) + } + if set.Val() != "OK" || get.Val() != "hello" || del.Val() != 1 { + b.Fatal("response error") + } + } +} + +func respTxPipeline(b *testing.B, stub ClientStubFunc) { + rdb := stub([]byte("+OK\r\n+QUEUED\r\n+QUEUED\r\n+QUEUED\r\n*3\r\n+OK\r\n$5\r\nhello\r\n:1\r\n")) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + var set *StatusCmd + var get *StringCmd + var del *IntCmd + _, err := rdb.TxPipelined(ctx, func(pipe Pipeliner) error { + set = pipe.Set(ctx, "key", "value", 0) + get = pipe.Get(ctx, "key") + del = pipe.Del(ctx, "key") + return nil + }) + if err != nil { + b.Fatalf("response error, got %q, want nil", err) + } + if set.Val() != "OK" || get.Val() != "hello" || del.Val() != 1 { + b.Fatal("response error") + } + } +} + +func dynamicGoroutine(b *testing.B, stub ClientStubFunc, concurrency int) { + rdb := stub([]byte("$5\r\nhello\r\n")) + c := make(chan struct{}, concurrency) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + c <- struct{}{} + go func() { + if val := rdb.Get(ctx, "key").Val(); val != "hello" { + panic(fmt.Sprintf("response error, got %q, want hello", val)) + } + <-c + }() + } + // Here no longer wait for all goroutines to complete, it will not affect the test results. + close(c) +} + +func staticGoroutine(b *testing.B, stub ClientStubFunc, concurrency int) { + rdb := stub([]byte("$5\r\nhello\r\n")) + c := make(chan struct{}, concurrency) + + b.ResetTimer() + + for i := 0; i < concurrency; i++ { + go func() { + for { + _, ok := <-c + if !ok { + return + } + if val := rdb.Get(ctx, "key").Val(); val != "hello" { + panic(fmt.Sprintf("response error, got %q, want hello", val)) + } + } + }() + } + for i := 0; i < b.N; i++ { + c <- struct{}{} + } + close(c) +} |