github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/benchmarks/database/redis_test.go (about) 1 // Copyright 2021 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 3.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package database 16 17 import ( 18 "context" 19 "os" 20 "strings" 21 "testing" 22 "time" 23 24 "github.com/SagerNet/gvisor/pkg/test/dockerutil" 25 "github.com/SagerNet/gvisor/test/benchmarks/harness" 26 "github.com/SagerNet/gvisor/test/benchmarks/tools" 27 ) 28 29 // All possible operations from redis. Note: "ping" will 30 // run both PING_INLINE and PING_BUILD. 31 var operations []string = []string{ 32 "PING_INLINE", 33 "PING_BULK", 34 "SET", 35 "GET", 36 "INCR", 37 "LPUSH", 38 "RPUSH", 39 "LPOP", 40 "RPOP", 41 "SADD", 42 "HSET", 43 "SPOP", 44 "LRANGE_100", 45 "LRANGE_300", 46 "LRANGE_500", 47 "LRANGE_600", 48 "MSET", 49 } 50 51 // BenchmarkRedis runs redis-benchmark against a redis instance and reports 52 // data in queries per second. Each is reported by named operation (e.g. LPUSH). 53 func BenchmarkRedis(b *testing.B) { 54 clientMachine, err := harness.GetMachine() 55 if err != nil { 56 b.Fatalf("failed to get machine: %v", err) 57 } 58 defer clientMachine.CleanUp() 59 60 serverMachine, err := harness.GetMachine() 61 if err != nil { 62 b.Fatalf("failed to get machine: %v", err) 63 } 64 defer serverMachine.CleanUp() 65 66 // Redis runs on port 6379 by default. 67 port := 6379 68 ctx := context.Background() 69 server := serverMachine.GetContainer(ctx, b) 70 defer server.CleanUp(ctx) 71 72 // The redis docker container takes no arguments to run a redis server. 73 if err := server.Spawn(ctx, dockerutil.RunOpts{ 74 Image: "benchmarks/redis", 75 Ports: []int{port}, 76 }); err != nil { 77 b.Fatalf("failed to start redis server with: %v", err) 78 } 79 80 if out, err := server.WaitForOutput(ctx, "Ready to accept connections", 3*time.Second); err != nil { 81 b.Fatalf("failed to start redis server: %v %s", err, out) 82 } 83 84 ip, err := serverMachine.IPAddress() 85 if err != nil { 86 b.Fatalf("failed to get IP from server: %v", err) 87 } 88 89 serverPort, err := server.FindPort(ctx, port) 90 if err != nil { 91 b.Fatalf("failed to get IP from server: %v", err) 92 } 93 94 if err = harness.WaitUntilServing(ctx, clientMachine, ip, serverPort); err != nil { 95 b.Fatalf("failed to start redis with: %v", err) 96 } 97 for _, operation := range operations { 98 param := tools.Parameter{ 99 Name: "operation", 100 Value: operation, 101 } 102 name, err := tools.ParametersToName(param) 103 if err != nil { 104 b.Fatalf("Failed to parse paramaters: %v", err) 105 } 106 107 b.Run(name, func(b *testing.B) { 108 redis := tools.Redis{ 109 Operation: operation, 110 } 111 112 // Sometimes, the connection between the redis client and server can be 113 // flaky such that the client returns infinity as the QPS measurement for 114 // a give operation. If this happens, retry the client up to 3 times. 115 out := "inf" 116 for retries := 0; strings.Contains(out, "inf") && retries < 3; retries++ { 117 b.ResetTimer() 118 client := clientMachine.GetNativeContainer(ctx, b) 119 defer client.CleanUp(ctx) 120 121 out, err = client.Run(ctx, dockerutil.RunOpts{ 122 Image: "benchmarks/redis", 123 }, redis.MakeCmd(ip, serverPort, b.N /*requests*/)...) 124 } 125 126 if err != nil { 127 b.Fatalf("redis-benchmark failed with: %v", err) 128 } 129 130 b.StopTimer() 131 redis.Report(b, out) 132 }) 133 } 134 } 135 136 func TestMain(m *testing.M) { 137 harness.Init() 138 os.Exit(m.Run()) 139 }