From cb9a2a1ad4f568a21382e949a592b621c11b5a2c Mon Sep 17 00:00:00 2001 From: Boyuan He & Ridwan Sharif Date: Wed, 26 Aug 2020 15:26:46 -0400 Subject: fuse: add benchmarking support for FUSE This change adds the following: - Add support for containerizing syscall tests for FUSE - Mount tmpfs in the container so we can run benchmarks against it - Run the server in a background process - benchmarks for fuse syscall Co-authored-by: Ridwan Sharif --- test/runner/BUILD | 3 ++ test/runner/defs.bzl | 28 +++++++++++++ test/runner/runner.go | 112 +++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 132 insertions(+), 11 deletions(-) (limited to 'test/runner') diff --git a/test/runner/BUILD b/test/runner/BUILD index 582d2946d..049c26081 100644 --- a/test/runner/BUILD +++ b/test/runner/BUILD @@ -11,11 +11,14 @@ go_binary( ], visibility = ["//:sandbox"], deps = [ + "//pkg/context", "//pkg/log", + "//pkg/test/dockerutil", "//pkg/test/testutil", "//runsc/specutils", "//test/runner/gtest", "//test/uds", + "@com_github_docker_docker//api/types/mount:go_default_library", "@com_github_opencontainers_runtime_spec//specs-go:go_default_library", "@com_github_syndtr_gocapability//capability:go_default_library", "@org_golang_x_sys//unix:go_default_library", diff --git a/test/runner/defs.bzl b/test/runner/defs.bzl index 032ebd04e..9dc955c77 100644 --- a/test/runner/defs.bzl +++ b/test/runner/defs.bzl @@ -57,6 +57,8 @@ def _syscall_test( platform, use_tmpfs, tags, + use_image = "", + setup_command = "", network = "none", file_access = "exclusive", overlay = False, @@ -79,6 +81,8 @@ def _syscall_test( name += "_fuse" if network != "none": name += "_" + network + "net" + if use_image != "": + name += "_container" # Apply all tags. if tags == None: @@ -107,6 +111,8 @@ def _syscall_test( "--platform=" + platform, "--network=" + network, "--use-tmpfs=" + str(use_tmpfs), + "--use-image=" + use_image, + "--setup-command=" + setup_command, "--file-access=" + file_access, "--overlay=" + str(overlay), "--add-uds-tree=" + str(add_uds_tree), @@ -132,6 +138,8 @@ def syscall_test( shard_count = 5, size = "small", use_tmpfs = False, + use_image = "", + setup_command = "", add_overlay = False, add_uds_tree = False, add_hostinet = False, @@ -146,6 +154,8 @@ def syscall_test( shard_count: shards for defined tests. size: the defined test size. use_tmpfs: use tmpfs in the defined tests. + use_image: use specified docker image in the defined tests. + setup_command: command to set up the docker container. Should be used when ise_image is. add_overlay: add an overlay test. add_uds_tree: add a UDS test. add_hostinet: add a hostinet test. @@ -178,8 +188,26 @@ def syscall_test( vfs2 = True, fuse = fuse, ) + + if use_image != "": + # Run the test in the container specified. + _syscall_test( + test = test, + shard_count = shard_count, + size = size, + platform = default_platform, + use_tmpfs = use_tmpfs, + use_image = use_image, + setup_command = setup_command, + add_uds_tree = add_uds_tree, + tags = platforms[default_platform] + vfs2_tags, + vfs2 = True, + fuse = True, + ) + if fuse: # Only generate *_vfs2_fuse target if fuse parameter is enabled. + # The rest of the targets don't support FUSE as of yet. return _syscall_test( diff --git a/test/runner/runner.go b/test/runner/runner.go index 22d535f8d..fe501c4c7 100644 --- a/test/runner/runner.go +++ b/test/runner/runner.go @@ -23,16 +23,20 @@ import ( "os" "os/exec" "os/signal" + "path" "path/filepath" "strings" "syscall" "testing" "time" + "github.com/docker/docker/api/types/mount" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/syndtr/gocapability/capability" "golang.org/x/sys/unix" + "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/log" + "gvisor.dev/gvisor/pkg/test/dockerutil" "gvisor.dev/gvisor/pkg/test/testutil" "gvisor.dev/gvisor/runsc/specutils" "gvisor.dev/gvisor/test/runner/gtest" @@ -40,17 +44,19 @@ import ( ) var ( - debug = flag.Bool("debug", false, "enable debug logs") - strace = flag.Bool("strace", false, "enable strace logs") - platform = flag.String("platform", "ptrace", "platform to run on") - network = flag.String("network", "none", "network stack to run on (sandbox, host, none)") - useTmpfs = flag.Bool("use-tmpfs", false, "mounts tmpfs for /tmp") - fileAccess = flag.String("file-access", "exclusive", "mounts root in exclusive or shared mode") - overlay = flag.Bool("overlay", false, "wrap filesystem mounts with writable tmpfs overlay") - vfs2 = flag.Bool("vfs2", false, "enable VFS2") - fuse = flag.Bool("fuse", false, "enable FUSE") - parallel = flag.Bool("parallel", false, "run tests in parallel") - runscPath = flag.String("runsc", "", "path to runsc binary") + debug = flag.Bool("debug", false, "enable debug logs") + strace = flag.Bool("strace", false, "enable strace logs") + platform = flag.String("platform", "ptrace", "platform to run on") + network = flag.String("network", "none", "network stack to run on (sandbox, host, none)") + useTmpfs = flag.Bool("use-tmpfs", false, "mounts tmpfs for /tmp") + useImage = flag.String("use-image", "", "container image to use for test. Path relative to //images") + setupCommand = flag.String("setup-command", "", "command to run before running the test to set up container environment") + fileAccess = flag.String("file-access", "exclusive", "mounts root in exclusive or shared mode") + overlay = flag.Bool("overlay", false, "wrap filesystem mounts with writable tmpfs overlay") + vfs2 = flag.Bool("vfs2", false, "enable VFS2") + fuse = flag.Bool("fuse", false, "enable FUSE") + parallel = flag.Bool("parallel", false, "run tests in parallel") + runscPath = flag.String("runsc", "", "path to runsc binary") addUDSTree = flag.Bool("add-uds-tree", false, "expose a tree of UDS utilities for use in tests") ) @@ -313,8 +319,92 @@ func setupUDSTree(spec *specs.Spec) (cleanup func(), err error) { return cleanup, nil } +func runTestCaseInContainer(testBin string, tc gtest.TestCase, image string, t *testing.T) { + if usingFUSE, err := dockerutil.UsingFUSE(); err != nil { + t.Fatalf("failed to read config for runtime %s: %v", dockerutil.Runtime(), err) + } else if !usingFUSE { + t.Skip("FUSE not being used.") + } + + ctx := context.Background() + d := dockerutil.MakeContainer(ctx, t) + defer d.CleanUp(ctx) + + // Run the basic container. + tmpDir := "/tmpDir" + testBinDir := "/testDir" + opts := dockerutil.RunOpts{ + Image: image, + Privileged: true, + CapAdd: []string{"CAP_SYS_ADMIN"}, + + // Mount a tmpfs directory to use when benchmarking. + Mounts: []mount.Mount{ + { + Type: mount.TypeTmpfs, + Target: tmpDir, + ReadOnly: false, + }, + }, + Env: []string{ + fmt.Sprintf("TEST_TMPDIR=%s", tmpDir), + fmt.Sprintf("TEST_FUSEPRE=%s", "/fus/mountpoint"), + }, + } + wd, err := os.Getwd() + if err != nil { + t.Fatalf("Getwd run failed: %v", err) + } + + wdPathToTestBin := strings.TrimPrefix(testBin, wd) + containerTestBin := path.Join(testBinDir, path.Base(wdPathToTestBin)) + d.CopyFiles(&opts, testBinDir, wdPathToTestBin) + if err := d.CopyErr(); err != nil { + t.Fatalf("Copy failed %v", err) + } + + err = d.Spawn(ctx, opts, "sleep", "1000") + if err != nil { + t.Fatalf("docker run failed: %v", err) + } + + // Run the server setup command. + if *setupCommand != "" { + out, err := d.Exec(ctx, dockerutil.ExecOpts{ + Privileged: true, + }, "/bin/sh", "-c", *setupCommand) + if err != nil { + t.Fatalf("docker exec failed: %v with output %v", err, out) + } + } + + cmd := "chmod +x " + containerTestBin + out, err := d.Exec(ctx, dockerutil.ExecOpts{ + Privileged: true, + }, "/bin/sh", "-c", cmd) + if err != nil { + t.Fatalf("docker exec failed: %v with output %v", err, out) + } + + cmd = containerTestBin + " " + strings.Join(tc.Args(), " ") + out, err = d.Exec(ctx, dockerutil.ExecOpts{ + Privileged: true, + }, "/bin/sh", "-c", cmd) + if err != nil { + t.Fatalf("docker exec failed: %v with output %v", err, out) + } + + fmt.Print(out) + return +} + // runsTestCaseRunsc runs the test case in runsc. func runTestCaseRunsc(testBin string, tc gtest.TestCase, t *testing.T) { + if *useImage != "" { + runTestCaseInContainer(testBin, tc, *useImage, t) + return + } + // Run a new container with the test executable and filter for the // given test suite and name. spec := testutil.NewSpecWithArgs(append([]string{testBin}, tc.Args()...)...) -- cgit v1.2.3