github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/benchmarks/fs/fio_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 fio_test 15 16 import ( 17 "context" 18 "fmt" 19 "os" 20 "path/filepath" 21 "strings" 22 "testing" 23 24 "github.com/SagerNet/gvisor/pkg/cleanup" 25 "github.com/SagerNet/gvisor/pkg/test/dockerutil" 26 "github.com/SagerNet/gvisor/test/benchmarks/harness" 27 "github.com/SagerNet/gvisor/test/benchmarks/tools" 28 ) 29 30 // BenchmarkFio runs fio on the runtime under test. There are 4 basic test 31 // cases each run on a tmpfs mount and a bind mount. Fio requires root so that 32 // caches can be dropped. 33 func BenchmarkFio(b *testing.B) { 34 testCases := []tools.Fio{ 35 { 36 Test: "write", 37 BlockSize: 4, 38 IODepth: 4, 39 }, 40 { 41 Test: "write", 42 BlockSize: 1024, 43 IODepth: 4, 44 }, 45 { 46 Test: "read", 47 BlockSize: 4, 48 IODepth: 4, 49 }, 50 { 51 Test: "read", 52 BlockSize: 1024, 53 IODepth: 4, 54 }, 55 { 56 Test: "randwrite", 57 BlockSize: 4, 58 IODepth: 4, 59 }, 60 { 61 Test: "randread", 62 BlockSize: 4, 63 IODepth: 4, 64 }, 65 } 66 67 machine, err := harness.GetMachine() 68 if err != nil { 69 b.Fatalf("failed to get machine with: %v", err) 70 } 71 defer machine.CleanUp() 72 73 for _, fsType := range []harness.FileSystemType{harness.BindFS, harness.TmpFS, harness.RootFS} { 74 for _, tc := range testCases { 75 operation := tools.Parameter{ 76 Name: "operation", 77 Value: tc.Test, 78 } 79 blockSize := tools.Parameter{ 80 Name: "blockSize", 81 Value: fmt.Sprintf("%dK", tc.BlockSize), 82 } 83 filesystem := tools.Parameter{ 84 Name: "filesystem", 85 Value: string(fsType), 86 } 87 name, err := tools.ParametersToName(operation, blockSize, filesystem) 88 if err != nil { 89 b.Fatalf("Failed to parser paramters: %v", err) 90 } 91 b.Run(name, func(b *testing.B) { 92 b.StopTimer() 93 tc.Size = b.N 94 95 ctx := context.Background() 96 container := machine.GetContainer(ctx, b) 97 cu := cleanup.Make(func() { 98 container.CleanUp(ctx) 99 }) 100 defer cu.Clean() 101 102 mnts, outdir, err := harness.MakeMount(machine, fsType, &cu) 103 if err != nil { 104 b.Fatalf("failed to make mount: %v", err) 105 } 106 107 // Start the container with the mount. 108 if err := container.Spawn( 109 ctx, dockerutil.RunOpts{ 110 Image: "benchmarks/fio", 111 Mounts: mnts, 112 }, 113 // Sleep on the order of b.N. 114 "sleep", fmt.Sprintf("%d", 1000*b.N), 115 ); err != nil { 116 b.Fatalf("failed to start fio container with: %v", err) 117 } 118 119 if out, err := container.Exec(ctx, dockerutil.ExecOpts{}, 120 "mkdir", "-p", outdir); err != nil { 121 b.Fatalf("failed to copy directory: %v (%s)", err, out) 122 } 123 124 // Directory and filename inside container where fio will read/write. 125 outfile := filepath.Join(outdir, "test.txt") 126 127 // For reads, we need a file to read so make one inside the container. 128 if strings.Contains(tc.Test, "read") { 129 fallocateCmd := fmt.Sprintf("fallocate -l %dK %s", tc.Size, outfile) 130 if out, err := container.Exec(ctx, dockerutil.ExecOpts{}, 131 strings.Split(fallocateCmd, " ")...); err != nil { 132 b.Fatalf("failed to create readable file on mount: %v, %s", err, out) 133 } 134 } 135 136 // Drop caches just before running. 137 if err := harness.DropCaches(machine); err != nil { 138 b.Skipf("failed to drop caches with %v. You probably need root.", err) 139 } 140 141 cmd := tc.MakeCmd(outfile) 142 if err := harness.DropCaches(machine); err != nil { 143 b.Fatalf("failed to drop caches: %v", err) 144 } 145 146 // Run fio. 147 b.StartTimer() 148 data, err := container.Exec(ctx, dockerutil.ExecOpts{}, cmd...) 149 if err != nil { 150 b.Fatalf("failed to run cmd %v: %v", cmd, err) 151 } 152 b.StopTimer() 153 tc.Report(b, data) 154 }) 155 } 156 } 157 } 158 159 // TestMain is the main method for package fs. 160 func TestMain(m *testing.M) { 161 harness.Init() 162 os.Exit(m.Run()) 163 }