diff options
-rw-r--r-- | BUILD | 7 | ||||
-rw-r--r-- | test/benchmarks/base/BUILD | 40 | ||||
-rw-r--r-- | test/benchmarks/base/base.go | 81 | ||||
-rw-r--r-- | test/benchmarks/base/size_test.go | 92 | ||||
-rw-r--r-- | test/benchmarks/base/startup_test.go | 68 | ||||
-rw-r--r-- | test/benchmarks/base/sysbench_test.go | 5 | ||||
-rw-r--r-- | test/benchmarks/fs/BUILD | 32 | ||||
-rw-r--r-- | test/benchmarks/fs/bazel_test.go | 11 | ||||
-rw-r--r-- | test/benchmarks/fs/fio_test.go | 11 | ||||
-rw-r--r-- | test/benchmarks/fs/fs.go | 31 | ||||
-rw-r--r-- | test/benchmarks/harness/harness.go | 14 |
11 files changed, 213 insertions, 179 deletions
@@ -64,9 +64,12 @@ build_test( "//test/e2e:integration_test", "//test/image:image_test", "//test/root:root_test", - "//test/benchmarks/base:base_test", + "//test/benchmarks/base:startup_test", + "//test/benchmarks/base:size_test", + "//test/benchmarks/base:sysbench_test", "//test/benchmarks/database:database_test", - "//test/benchmarks/fs:fs_test", + "//test/benchmarks/fs:bazel_test", + "//test/benchmarks/fs:fio_test", "//test/benchmarks/media:media_test", "//test/benchmarks/ml:ml_test", "//test/benchmarks/network:network_test", diff --git a/test/benchmarks/base/BUILD b/test/benchmarks/base/BUILD index 7dfd4b693..b4b55317b 100644 --- a/test/benchmarks/base/BUILD +++ b/test/benchmarks/base/BUILD @@ -8,23 +8,41 @@ go_library( srcs = [ "base.go", ], - deps = ["//test/benchmarks/harness"], + deps = [ + "//pkg/test/dockerutil", + "//test/benchmarks/harness", + ], ) go_test( - name = "base_test", + name = "startup_test", size = "enormous", - srcs = [ - "size_test.go", - "startup_test.go", - "sysbench_test.go", + srcs = ["startup_test.go"], + visibility = ["//:sandbox"], + deps = [ + "//pkg/test/dockerutil", + "//test/benchmarks/base", + "//test/benchmarks/harness", ], - library = ":base", - tags = [ - # Requires docker and runsc to be configured before test runs. - "manual", - "local", +) + +go_test( + name = "size_test", + size = "enormous", + srcs = ["size_test.go"], + visibility = ["//:sandbox"], + deps = [ + "//pkg/test/dockerutil", + "//test/benchmarks/base", + "//test/benchmarks/harness", + "//test/benchmarks/tools", ], +) + +go_test( + name = "sysbench_test", + size = "enormous", + srcs = ["sysbench_test.go"], visibility = ["//:sandbox"], deps = [ "//pkg/test/dockerutil", diff --git a/test/benchmarks/base/base.go b/test/benchmarks/base/base.go index 7bac52ff1..979564af9 100644 --- a/test/benchmarks/base/base.go +++ b/test/benchmarks/base/base.go @@ -12,20 +12,87 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package base holds base performance benchmarks. +// Package base holds utility methods common to the base tests. package base import ( - "os" + "context" + "net" "testing" + "time" + "gvisor.dev/gvisor/pkg/test/dockerutil" "gvisor.dev/gvisor/test/benchmarks/harness" ) -var testHarness harness.Harness +// ServerArgs wraps args for startServers and runServerWorkload. +type ServerArgs struct { + Machine harness.Machine + Port int + RunOpts dockerutil.RunOpts + Cmd []string +} + +// StartServers starts b.N containers defined by 'runOpts' and 'cmd' and uses +// 'machine' to check that each is up. +func StartServers(ctx context.Context, b *testing.B, args ServerArgs) []*dockerutil.Container { + b.Helper() + servers := make([]*dockerutil.Container, 0, b.N) + + // Create N servers and wait until each of them is serving. + for i := 0; i < b.N; i++ { + server := args.Machine.GetContainer(ctx, b) + servers = append(servers, server) + if err := server.Spawn(ctx, args.RunOpts, args.Cmd...); err != nil { + CleanUpContainers(ctx, servers) + b.Fatalf("failed to spawn node instance: %v", err) + } + + // Get the container IP. + servingIP, err := server.FindIP(ctx, false) + if err != nil { + CleanUpContainers(ctx, servers) + b.Fatalf("failed to get ip from server: %v", err) + } + + // Wait until the server is up. + if err := harness.WaitUntilServing(ctx, args.Machine, servingIP, args.Port); err != nil { + CleanUpContainers(ctx, servers) + b.Fatalf("failed to wait for serving") + } + } + return servers +} + +// CleanUpContainers cleans up a slice of containers. +func CleanUpContainers(ctx context.Context, containers []*dockerutil.Container) { + for _, c := range containers { + if c != nil { + c.CleanUp(ctx) + } + } +} + +// RedisInstance returns a Redis container and its reachable IP. +func RedisInstance(ctx context.Context, b *testing.B, machine harness.Machine) (*dockerutil.Container, net.IP) { + b.Helper() + // Spawn a redis instance for the app to use. + redis := machine.GetNativeContainer(ctx, b) + if err := redis.Spawn(ctx, dockerutil.RunOpts{ + Image: "benchmarks/redis", + }); err != nil { + redis.CleanUp(ctx) + b.Fatalf("failed to spwan redis instance: %v", err) + } -// TestMain is the main method for package network. -func TestMain(m *testing.M) { - testHarness.Init() - os.Exit(m.Run()) + if out, err := redis.WaitForOutput(ctx, "Ready to accept connections", 3*time.Second); err != nil { + redis.CleanUp(ctx) + b.Fatalf("failed to start redis server: %v %s", err, out) + } + redisIP, err := redis.FindIP(ctx, false) + if err != nil { + redis.CleanUp(ctx) + b.Fatalf("failed to get IP from redis instance: %v", err) + } + return redis, redisIP } diff --git a/test/benchmarks/base/size_test.go b/test/benchmarks/base/size_test.go index 7d3877459..acc49cc7c 100644 --- a/test/benchmarks/base/size_test.go +++ b/test/benchmarks/base/size_test.go @@ -12,18 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -package base +package size_test import ( "context" + "os" "testing" "time" "gvisor.dev/gvisor/pkg/test/dockerutil" + "gvisor.dev/gvisor/test/benchmarks/base" "gvisor.dev/gvisor/test/benchmarks/harness" "gvisor.dev/gvisor/test/benchmarks/tools" ) +var testHarness harness.Harness + // BenchmarkSizeEmpty creates N empty containers and reads memory usage from // /proc/meminfo. func BenchmarkSizeEmpty(b *testing.B) { @@ -53,11 +57,11 @@ func BenchmarkSizeEmpty(b *testing.B) { if err := container.Spawn(ctx, dockerutil.RunOpts{ Image: "benchmarks/alpine", }, "sh", "-c", "echo Hello && sleep 1000"); err != nil { - cleanUpContainers(ctx, containers) + base.CleanUpContainers(ctx, containers) b.Fatalf("failed to run container: %v", err) } if _, err := container.WaitForOutputSubmatch(ctx, "Hello", 5*time.Second); err != nil { - cleanUpContainers(ctx, containers) + base.CleanUpContainers(ctx, containers) b.Fatalf("failed to read container output: %v", err) } } @@ -67,7 +71,7 @@ func BenchmarkSizeEmpty(b *testing.B) { // Check available memory after containers are up. after, err := machine.RunCommand(cmd, args...) - cleanUpContainers(ctx, containers) + base.CleanUpContainers(ctx, containers) if err != nil { b.Fatalf("failed to get meminfo: %v", err) } @@ -100,14 +104,14 @@ func BenchmarkSizeNginx(b *testing.B) { Image: "benchmarks/nginx", } const port = 80 - servers := startServers(ctx, b, - serverArgs{ - machine: machine, - port: port, - runOpts: runOpts, - cmd: []string{"nginx", "-c", "/etc/nginx/nginx_gofer.conf"}, + servers := base.StartServers(ctx, b, + base.ServerArgs{ + Machine: machine, + Port: port, + RunOpts: runOpts, + Cmd: []string{"nginx", "-c", "/etc/nginx/nginx_gofer.conf"}, }) - defer cleanUpContainers(ctx, servers) + defer base.CleanUpContainers(ctx, servers) // DropCaches after servers are created. harness.DropCaches(machine) @@ -130,7 +134,7 @@ func BenchmarkSizeNode(b *testing.B) { // Make a redis instance for Node to connect. ctx := context.Background() - redis, redisIP := redisInstance(ctx, b, machine) + redis, redisIP := base.RedisInstance(ctx, b, machine) defer redis.CleanUp(ctx) // DropCaches after redis is created. @@ -152,14 +156,14 @@ func BenchmarkSizeNode(b *testing.B) { } nodeCmd := []string{"node", "index.js", redisIP.String()} const port = 8080 - servers := startServers(ctx, b, - serverArgs{ - machine: machine, - port: port, - runOpts: runOpts, - cmd: nodeCmd, + servers := base.StartServers(ctx, b, + base.ServerArgs{ + Machine: machine, + Port: port, + RunOpts: runOpts, + Cmd: nodeCmd, }) - defer cleanUpContainers(ctx, servers) + defer base.CleanUpContainers(ctx, servers) // DropCaches after servers are created. harness.DropCaches(machine) @@ -172,50 +176,8 @@ func BenchmarkSizeNode(b *testing.B) { meminfo.Report(b, before, after) } -// serverArgs wraps args for startServers and runServerWorkload. -type serverArgs struct { - machine harness.Machine - port int - runOpts dockerutil.RunOpts - cmd []string -} - -// startServers starts b.N containers defined by 'runOpts' and 'cmd' and uses -// 'machine' to check that each is up. -func startServers(ctx context.Context, b *testing.B, args serverArgs) []*dockerutil.Container { - b.Helper() - servers := make([]*dockerutil.Container, 0, b.N) - - // Create N servers and wait until each of them is serving. - for i := 0; i < b.N; i++ { - server := args.machine.GetContainer(ctx, b) - servers = append(servers, server) - if err := server.Spawn(ctx, args.runOpts, args.cmd...); err != nil { - cleanUpContainers(ctx, servers) - b.Fatalf("failed to spawn node instance: %v", err) - } - - // Get the container IP. - servingIP, err := server.FindIP(ctx, false) - if err != nil { - cleanUpContainers(ctx, servers) - b.Fatalf("failed to get ip from server: %v", err) - } - - // Wait until the server is up. - if err := harness.WaitUntilServing(ctx, args.machine, servingIP, args.port); err != nil { - cleanUpContainers(ctx, servers) - b.Fatalf("failed to wait for serving") - } - } - return servers -} - -// cleanUpContainers cleans up a slice of containers. -func cleanUpContainers(ctx context.Context, containers []*dockerutil.Container) { - for _, c := range containers { - if c != nil { - c.CleanUp(ctx) - } - } +// TestMain is the main method for package network. +func TestMain(m *testing.M) { + testHarness.Init() + os.Exit(m.Run()) } diff --git a/test/benchmarks/base/startup_test.go b/test/benchmarks/base/startup_test.go index c36a544db..28731f97a 100644 --- a/test/benchmarks/base/startup_test.go +++ b/test/benchmarks/base/startup_test.go @@ -12,19 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -package base +package startup_test import ( "context" "fmt" - "net" + "os" "testing" - "time" "gvisor.dev/gvisor/pkg/test/dockerutil" + "gvisor.dev/gvisor/test/benchmarks/base" "gvisor.dev/gvisor/test/benchmarks/harness" ) +var testHarness harness.Harness + // BenchmarkStartEmpty times startup time for an empty container. func BenchmarkStartupEmpty(b *testing.B) { machine, err := testHarness.GetMachine() @@ -60,11 +62,11 @@ func BenchmarkStartupNginx(b *testing.B) { Image: "benchmarks/nginx", } runServerWorkload(ctx, b, - serverArgs{ - machine: machine, - runOpts: runOpts, - port: 80, - cmd: []string{"nginx", "-c", "/etc/nginx/nginx_gofer.conf"}, + base.ServerArgs{ + Machine: machine, + RunOpts: runOpts, + Port: 80, + Cmd: []string{"nginx", "-c", "/etc/nginx/nginx_gofer.conf"}, }) } @@ -79,7 +81,7 @@ func BenchmarkStartupNode(b *testing.B) { defer machine.CleanUp() ctx := context.Background() - redis, redisIP := redisInstance(ctx, b, machine) + redis, redisIP := base.RedisInstance(ctx, b, machine) defer redis.CleanUp(ctx) runOpts := dockerutil.RunOpts{ Image: "benchmarks/node", @@ -89,52 +91,28 @@ func BenchmarkStartupNode(b *testing.B) { cmd := []string{"node", "index.js", redisIP.String()} runServerWorkload(ctx, b, - serverArgs{ - machine: machine, - port: 8080, - runOpts: runOpts, - cmd: cmd, + base.ServerArgs{ + Machine: machine, + Port: 8080, + RunOpts: runOpts, + Cmd: cmd, }) } -// redisInstance returns a Redis container and its reachable IP. -func redisInstance(ctx context.Context, b *testing.B, machine harness.Machine) (*dockerutil.Container, net.IP) { - b.Helper() - // Spawn a redis instance for the app to use. - redis := machine.GetNativeContainer(ctx, b) - if err := redis.Spawn(ctx, dockerutil.RunOpts{ - Image: "benchmarks/redis", - }); err != nil { - redis.CleanUp(ctx) - b.Fatalf("failed to spwan redis instance: %v", err) - } - - if out, err := redis.WaitForOutput(ctx, "Ready to accept connections", 3*time.Second); err != nil { - redis.CleanUp(ctx) - b.Fatalf("failed to start redis server: %v %s", err, out) - } - redisIP, err := redis.FindIP(ctx, false) - if err != nil { - redis.CleanUp(ctx) - b.Fatalf("failed to get IP from redis instance: %v", err) - } - return redis, redisIP -} - // runServerWorkload runs a server workload defined by 'runOpts' and 'cmd'. // 'clientMachine' is used to connect to the server on 'serverMachine'. -func runServerWorkload(ctx context.Context, b *testing.B, args serverArgs) { +func runServerWorkload(ctx context.Context, b *testing.B, args base.ServerArgs) { b.ResetTimer() for i := 0; i < b.N; i++ { if err := func() error { - server := args.machine.GetContainer(ctx, b) + server := args.Machine.GetContainer(ctx, b) defer func() { b.StopTimer() // Cleanup servers as we run so that we can go indefinitely. server.CleanUp(ctx) b.StartTimer() }() - if err := server.Spawn(ctx, args.runOpts, args.cmd...); err != nil { + if err := server.Spawn(ctx, args.RunOpts, args.Cmd...); err != nil { return fmt.Errorf("failed to spawn node instance: %v", err) } @@ -144,7 +122,7 @@ func runServerWorkload(ctx context.Context, b *testing.B, args serverArgs) { } // Wait until the Client sees the server as up. - if err := harness.WaitUntilServing(ctx, args.machine, servingIP, args.port); err != nil { + if err := harness.WaitUntilServing(ctx, args.Machine, servingIP, args.Port); err != nil { return fmt.Errorf("failed to wait for serving: %v", err) } return nil @@ -153,3 +131,9 @@ func runServerWorkload(ctx context.Context, b *testing.B, args serverArgs) { } } } + +// TestMain is the main method for package network. +func TestMain(m *testing.M) { + testHarness.Init() + os.Exit(m.Run()) +} diff --git a/test/benchmarks/base/sysbench_test.go b/test/benchmarks/base/sysbench_test.go index 39ced3dab..bbb797e14 100644 --- a/test/benchmarks/base/sysbench_test.go +++ b/test/benchmarks/base/sysbench_test.go @@ -12,16 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -package base +package sysbench_test import ( "context" "testing" "gvisor.dev/gvisor/pkg/test/dockerutil" + "gvisor.dev/gvisor/test/benchmarks/harness" "gvisor.dev/gvisor/test/benchmarks/tools" ) +var testHarness harness.Harness + type testCase struct { name string test tools.Sysbench diff --git a/test/benchmarks/fs/BUILD b/test/benchmarks/fs/BUILD index 45f11372b..021fae38d 100644 --- a/test/benchmarks/fs/BUILD +++ b/test/benchmarks/fs/BUILD @@ -1,27 +1,23 @@ -load("//tools:defs.bzl", "go_library", "go_test") +load("//tools:defs.bzl", "go_test") package(licenses = ["notice"]) -go_library( - name = "fs", - testonly = 1, - srcs = ["fs.go"], - deps = ["//test/benchmarks/harness"], +go_test( + name = "bazel_test", + size = "enormous", + srcs = ["bazel_test.go"], + visibility = ["//:sandbox"], + deps = [ + "//pkg/test/dockerutil", + "//test/benchmarks/harness", + "//test/benchmarks/tools", + ], ) go_test( - name = "fs_test", - size = "large", - srcs = [ - "bazel_test.go", - "fio_test.go", - ], - library = ":fs", - tags = [ - # Requires docker and runsc to be configured before test runs. - "local", - "manual", - ], + name = "fio_test", + size = "enormous", + srcs = ["fio_test.go"], visibility = ["//:sandbox"], deps = [ "//pkg/test/dockerutil", diff --git a/test/benchmarks/fs/bazel_test.go b/test/benchmarks/fs/bazel_test.go index 56103639d..53ed3f9f2 100644 --- a/test/benchmarks/fs/bazel_test.go +++ b/test/benchmarks/fs/bazel_test.go @@ -11,11 +11,12 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package fs +package bazel_test import ( "context" "fmt" + "os" "strings" "testing" @@ -24,6 +25,8 @@ import ( "gvisor.dev/gvisor/test/benchmarks/tools" ) +var h harness.Harness + // Note: CleanCache versions of this test require running with root permissions. func BenchmarkBuildABSL(b *testing.B) { runBuildBenchmark(b, "benchmarks/absl", "/abseil-cpp", "absl/base/...") @@ -138,3 +141,9 @@ func runBuildBenchmark(b *testing.B, image, workdir, target string) { }) } } + +// TestMain is the main method for package fs. +func TestMain(m *testing.M) { + h.Init() + os.Exit(m.Run()) +} diff --git a/test/benchmarks/fs/fio_test.go b/test/benchmarks/fs/fio_test.go index 5ca191404..96340373c 100644 --- a/test/benchmarks/fs/fio_test.go +++ b/test/benchmarks/fs/fio_test.go @@ -11,11 +11,12 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package fs +package fio_test import ( "context" "fmt" + "os" "path/filepath" "strings" "testing" @@ -26,6 +27,8 @@ import ( "gvisor.dev/gvisor/test/benchmarks/tools" ) +var h harness.Harness + // BenchmarkFio runs fio on the runtime under test. There are 4 basic test // cases each run on a tmpfs mount and a bind mount. Fio requires root so that // caches can be dropped. @@ -179,3 +182,9 @@ func makeMount(machine harness.Machine, mountType mount.Type, target string) (mo return mount.Mount{}, func() {}, fmt.Errorf("illegal mount time not supported: %v", mountType) } } + +// TestMain is the main method for package fs. +func TestMain(m *testing.M) { + h.Init() + os.Exit(m.Run()) +} diff --git a/test/benchmarks/fs/fs.go b/test/benchmarks/fs/fs.go deleted file mode 100644 index e5ca28c3b..000000000 --- a/test/benchmarks/fs/fs.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2020 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package fs holds benchmarks around filesystem performance. -package fs - -import ( - "os" - "testing" - - "gvisor.dev/gvisor/test/benchmarks/harness" -) - -var h harness.Harness - -// TestMain is the main method for package fs. -func TestMain(m *testing.M) { - h.Init() - os.Exit(m.Run()) -} diff --git a/test/benchmarks/harness/harness.go b/test/benchmarks/harness/harness.go index 68bd7b4cf..e14cce987 100644 --- a/test/benchmarks/harness/harness.go +++ b/test/benchmarks/harness/harness.go @@ -17,17 +17,31 @@ package harness import ( "flag" + "fmt" + "os" "gvisor.dev/gvisor/pkg/test/dockerutil" ) +var ( + help = flag.Bool("help", false, "print this usage message") +) + // Harness is a handle for managing state in benchmark runs. type Harness struct { } // Init performs any harness initilialization before runs. func (h *Harness) Init() error { + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "Usage: %s -- --test.bench=<regex>\n", os.Args[0]) + flag.PrintDefaults() + } flag.Parse() + if flag.NFlag() == 0 || *help { + flag.Usage() + os.Exit(0) + } dockerutil.EnsureSupportedDockerVersion() return nil } |