tart/benchmark/internal/command/xcode/xcode.go

109 lines
2.5 KiB
Go

package xcode
import (
"fmt"
executorpkg "github.com/cirruslabs/tart/benchmark/internal/executor"
"github.com/gosuri/uitable"
"github.com/spf13/cobra"
"go.uber.org/zap"
"go.uber.org/zap/zapio"
"os"
"os/exec"
)
var debug bool
var image string
var prepare string
func NewCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "xcode",
Short: "run XCode benchmarks",
RunE: run,
}
cmd.Flags().BoolVar(&debug, "debug", false, "enable debug logging")
cmd.Flags().StringVar(&image, "image", "ghcr.io/cirruslabs/macos-tahoe-xcode:latest", "image to use for testing")
cmd.Flags().StringVar(&prepare, "prepare", "", "command to run before running each benchmark")
return cmd
}
func run(cmd *cobra.Command, args []string) error {
config := zap.NewProductionConfig()
if debug {
config.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
}
logger, err := config.Build()
if err != nil {
return err
}
defer func() {
_ = logger.Sync()
}()
table := uitable.New()
table.AddRow("Name", "Executor", "Time")
for _, benchmark := range benchmarks {
for _, executorInitializer := range executorpkg.DefaultInitializers(cmd.Context(), image, logger) {
if prepare != "" {
shell := "/bin/sh"
if shellFromEnv, ok := os.LookupEnv("SHELL"); ok {
shell = shellFromEnv
}
logger.Sugar().Infof("running prepare command %q using shell %q",
prepare, shell)
cmd := exec.CommandContext(cmd.Context(), shell, "-c", prepare)
loggerWriter := &zapio.Writer{Log: logger, Level: zap.DebugLevel}
cmd.Stdout = loggerWriter
cmd.Stderr = loggerWriter
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to run prepare command %q: %v", prepare, err)
}
}
logger.Sugar().Infof("initializing executor %s", executorInitializer.Name)
executor, err := executorInitializer.Fn()
if err != nil {
return err
}
logger.Sugar().Infof("running benchmark %q on %s executor", benchmark.Name,
executorInitializer.Name)
stdout, err := executor.Run(cmd.Context(), benchmark.Command)
if err != nil {
return err
}
output, err := ParseOutput(string(stdout))
if err != nil {
return err
}
duration := output.Ended.Sub(output.Started)
logger.Sugar().Infof("Xcode benchmark duration: %s", duration)
table.AddRow(benchmark.Name, executorInitializer.Name, duration)
if err := executor.Close(); err != nil {
return fmt.Errorf("failed to close executor %s: %w",
executorInitializer.Name, err)
}
}
}
fmt.Println(table.String())
return nil
}