github.com/firecracker-microvm/firecracker-go-sdk@v1.0.0/benchmark_test.go (about) 1 // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"). You may 4 // not use this file except in compliance with the License. A copy of the 5 // License is located at 6 // 7 // http://aws.amazon.com/apache2.0/ 8 // 9 // or in the "license" file accompanying this file. This file is distributed 10 // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 // express or implied. See the License for the specific language governing 12 // permissions and limitations under the License. 13 package firecracker 14 15 import ( 16 "bufio" 17 "context" 18 "fmt" 19 "io/ioutil" 20 "os" 21 "path/filepath" 22 "strings" 23 "testing" 24 25 "github.com/sirupsen/logrus" 26 27 models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" 28 ) 29 30 const numberOfVMs = 200 31 32 func createMachine(ctx context.Context, name string, forwardSignals []os.Signal) (*Machine, func(), error) { 33 dir, err := ioutil.TempDir("", name) 34 if err != nil { 35 return nil, nil, err 36 } 37 cleanup := func() { 38 os.RemoveAll(dir) 39 } 40 41 socketPath := filepath.Join(dir, "api.sock") 42 vmlinuxPath := filepath.Join(testDataPath, "./vmlinux") 43 logFifo := filepath.Join(dir, "log.fifo") 44 metrics := filepath.Join(dir, "metrics.fifo") 45 46 config := Config{ 47 SocketPath: socketPath, 48 KernelImagePath: vmlinuxPath, 49 LogFifo: logFifo, 50 MetricsFifo: metrics, 51 LogLevel: "Info", 52 MachineCfg: models.MachineConfiguration{ 53 VcpuCount: Int64(1), 54 CPUTemplate: models.CPUTemplate(models.CPUTemplateT2), 55 MemSizeMib: Int64(256), 56 Smt: Bool(false), 57 }, 58 Drives: []models.Drive{ 59 { 60 DriveID: String("root"), 61 IsRootDevice: Bool(true), 62 IsReadOnly: Bool(true), 63 PathOnHost: String(testRootfs), 64 }, 65 }, 66 ForwardSignals: forwardSignals, 67 } 68 69 cmd := VMCommandBuilder{}. 70 WithSocketPath(socketPath). 71 WithBin(getFirecrackerBinaryPath()). 72 Build(ctx) 73 74 log := logrus.New() 75 log.SetLevel(logrus.FatalLevel) 76 machine, err := NewMachine(ctx, config, WithProcessRunner(cmd), WithLogger(logrus.NewEntry(log))) 77 if err != nil { 78 return nil, cleanup, err 79 } 80 81 return machine, cleanup, nil 82 } 83 84 func startAndWaitVM(ctx context.Context, m *Machine) error { 85 err := m.Start(ctx) 86 if err != nil { 87 return err 88 } 89 90 file, err := os.Open(m.LogFile()) 91 if err != nil { 92 return err 93 } 94 95 scanner := bufio.NewScanner(file) 96 for scanner.Scan() { 97 line := scanner.Text() 98 if strings.Contains(line, "Guest-boot-time") { 99 break 100 } 101 } 102 err = m.StopVMM() 103 if err != nil { 104 return err 105 } 106 107 err = m.Wait(ctx) 108 if err != nil { 109 return err 110 } 111 112 return nil 113 } 114 115 func benchmarkForwardSignals(b *testing.B, forwardSignals []os.Signal) { 116 ctx := context.Background() 117 118 b.Logf("%s: %d", b.Name(), b.N) 119 120 for i := 0; i < b.N; i++ { 121 errCh := make(chan error, numberOfVMs) 122 for j := 0; j < numberOfVMs; j++ { 123 go func() { 124 var err error 125 defer func() { errCh <- err }() 126 127 machine, cleanup, err := createMachine(ctx, b.Name(), forwardSignals) 128 if err != nil { 129 err = fmt.Errorf("failed to create a VM: %v", err) 130 return // anonymous defer func() will deliver the error 131 } 132 defer cleanup() 133 134 err = startAndWaitVM(ctx, machine) 135 if err != nil && !strings.Contains(err.Error(), "signal: terminated") { 136 err = fmt.Errorf("failed to start the VM: %v", err) 137 return // anonymous defer func() will deliver the error 138 } 139 return // anonymous defer func() will deliver this nil error 140 }() 141 } 142 for k := 0; k < numberOfVMs; k++ { 143 err := <-errCh 144 if err != nil { 145 b.Fatal(err) 146 } 147 } 148 close(errCh) 149 } 150 } 151 func BenchmarkForwardSignalsDefault(t *testing.B) { 152 benchmarkForwardSignals(t, nil) 153 } 154 155 func BenchmarkForwardSignalsDisable(t *testing.B) { 156 benchmarkForwardSignals(t, []os.Signal{}) 157 }