github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/benchmarks/network/ruby_test.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.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 package network 15 16 import ( 17 "context" 18 "fmt" 19 "os" 20 "strconv" 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 // BenchmarkRuby runs requests using 'hey' against a ruby application server. 30 // On start, ruby app generates some random data and pushes it to a redis 31 // instance. On a request, the app grabs for random entries from the redis 32 // server, publishes it to a document, and returns the doc to the request. 33 func BenchmarkRuby(b *testing.B) { 34 concurrency := []int{1, 5, 10, 25} 35 for _, c := range concurrency { 36 param := tools.Parameter{ 37 Name: "concurrency", 38 Value: strconv.Itoa(c), 39 } 40 name, err := tools.ParametersToName(param) 41 if err != nil { 42 b.Fatalf("Failed to parse parameters: %v", err) 43 } 44 b.Run(name, func(b *testing.B) { 45 hey := &tools.Hey{ 46 Requests: b.N, 47 Concurrency: c, 48 } 49 runRuby(b, hey) 50 }) 51 } 52 } 53 54 // runRuby runs the test for a given # of requests and concurrency. 55 func runRuby(b *testing.B, hey *tools.Hey) { 56 // The machine to hold Redis and the Ruby Server. 57 serverMachine, err := harness.GetMachine() 58 if err != nil { 59 b.Fatalf("failed to get machine with: %v", err) 60 } 61 defer serverMachine.CleanUp() 62 63 // The machine to run 'hey'. 64 clientMachine, err := harness.GetMachine() 65 if err != nil { 66 b.Fatalf("failed to get machine with: %v", err) 67 } 68 defer clientMachine.CleanUp() 69 ctx := context.Background() 70 71 // Spawn a redis instance for the app to use. 72 redis := serverMachine.GetNativeContainer(ctx, b) 73 if err := redis.Spawn(ctx, dockerutil.RunOpts{ 74 Image: "benchmarks/redis", 75 }); err != nil { 76 b.Fatalf("failed to spwan redis instance: %v", err) 77 } 78 defer redis.CleanUp(ctx) 79 80 if out, err := redis.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 redisIP, err := redis.FindIP(ctx, false) 84 if err != nil { 85 b.Fatalf("failed to get IP from redis instance: %v", err) 86 } 87 88 // Ruby runs on port 9292. 89 const port = 9292 90 91 // Start-up the Ruby server. 92 rubyApp := serverMachine.GetContainer(ctx, b) 93 if err := rubyApp.Spawn(ctx, dockerutil.RunOpts{ 94 Image: "benchmarks/ruby", 95 WorkDir: "/app", 96 Links: []string{redis.MakeLink("redis")}, 97 Ports: []int{port}, 98 Env: []string{ 99 fmt.Sprintf("PORT=%d", port), 100 "WEB_CONCURRENCY=20", 101 "WEB_MAX_THREADS=20", 102 "RACK_ENV=production", 103 fmt.Sprintf("HOST=%s", redisIP), 104 }, 105 User: "nobody", 106 }, "sh", "-c", "/usr/bin/puma"); err != nil { 107 b.Fatalf("failed to spawn node instance: %v", err) 108 } 109 defer rubyApp.CleanUp(ctx) 110 111 servingIP, err := serverMachine.IPAddress() 112 if err != nil { 113 b.Fatalf("failed to get ip from server: %v", err) 114 } 115 116 servingPort, err := rubyApp.FindPort(ctx, port) 117 if err != nil { 118 b.Fatalf("failed to port from node instance: %v", err) 119 } 120 121 // Wait until the Client sees the server as up. 122 if err := harness.WaitUntilServing(ctx, clientMachine, servingIP, servingPort); err != nil { 123 b.Fatalf("failed to wait until serving: %v", err) 124 } 125 heyCmd := hey.MakeCmd(servingIP, servingPort) 126 127 // the client should run on Native. 128 b.ResetTimer() 129 client := clientMachine.GetNativeContainer(ctx, b) 130 defer client.CleanUp(ctx) 131 out, err := client.Run(ctx, dockerutil.RunOpts{ 132 Image: "benchmarks/hey", 133 }, heyCmd...) 134 if err != nil { 135 b.Fatalf("hey container failed: %v logs: %s", err, out) 136 } 137 b.StopTimer() 138 hey.Report(b, out) 139 } 140 141 func TestMain(m *testing.M) { 142 harness.Init() 143 os.Exit(m.Run()) 144 }