blob: 28fdaffe4c7ffbd44de91d70b615294c35d8524e [file] [log] [blame]
package cli
import (
"context"
"fmt"
"time"
"github.com/urfave/cli/v2"
"google.golang.org/protobuf/encoding/prototext"
"go.chromium.org/luci/common/api/swarming/swarming/v1"
"go.skia.org/infra/cabe/go/analyzer"
"go.skia.org/infra/cabe/go/backends"
"go.skia.org/infra/cabe/go/perfresults"
"go.skia.org/infra/cabe/go/replaybackends"
"go.skia.org/infra/go/sklog"
)
// checkCmd holds the flag values and any internal state necessary for
// executing the `check` subcommand.
type checkCmd struct {
commonCmd
}
// CheckCommand returns a [*cli.Command] for running cabe's analysis precondition checker.
func CheckCommand() *cli.Command {
cmd := &checkCmd{}
return &cli.Command{
Name: "check",
Description: "check runs some diagnostic checks on perf experiment jobs.",
Usage: "cabe check --pinpoint-job <pinpoint-job>",
Flags: cmd.flags(),
Action: cmd.action,
}
}
// action runs diagnostic checks on an experiment.
func (cmd *checkCmd) action(cliCtx *cli.Context) error {
ctx := cliCtx.Context
rbeClients, err := backends.DialRBECAS(ctx)
if err != nil {
sklog.Fatalf("dialing RBE-CAS backends: %v", err)
return err
}
swarmingClient, err := backends.DialSwarming(ctx)
if err != nil {
sklog.Fatalf("dialing swarming: %v", err)
return err
}
var casResultReader = func(c context.Context, casInstance, digest string) (map[string]perfresults.PerfResults, error) {
rbeClient := rbeClients[casInstance]
return backends.FetchBenchmarkJSON(ctx, rbeClient, digest)
}
var swarmingTaskReader = func(ctx context.Context, pinpointJobID string) ([]*swarming.SwarmingRpcsTaskRequestMetadata, error) {
tasksResp, err := swarmingClient.ListTasks(ctx, time.Now().AddDate(0, 0, -56), time.Now(), []string{pinpointSwarmingTagName + ":" + pinpointJobID}, "")
if err != nil {
sklog.Fatalf("list task results: %v", err)
return nil, err
}
return tasksResp, nil
}
if cmd.replayFromZip != "" {
replayBackends := replaybackends.FromZipFile(cmd.replayFromZip, "blank")
casResultReader = replayBackends.CASResultReader
swarmingTaskReader = replayBackends.SwarmingTaskReader
} else if cmd.recordToZip != "" {
replayBackends := replaybackends.ToZipFile(cmd.recordToZip, rbeClients, swarmingClient)
defer func() {
if err := replayBackends.Close(); err != nil {
sklog.Fatalf("closing replay backends: %v", err)
}
}()
casResultReader = replayBackends.CASResultReader
swarmingTaskReader = replayBackends.SwarmingTaskReader
}
var analyzerOpts = []analyzer.Options{
analyzer.WithCASResultReader(casResultReader),
analyzer.WithSwarmingTaskReader(swarmingTaskReader),
}
a := analyzer.New(cmd.pinpointJobID, analyzerOpts...)
c := analyzer.NewChecker(analyzer.DefaultCheckerOpts...)
if err := a.RunChecker(ctx, c); err != nil {
sklog.Fatalf("run checker error: %v", err)
return err
}
exSpec := a.ExperimentSpec()
if exSpec != nil {
txt := prototext.MarshalOptions{
Multiline: true,
Indent: " ",
}.Format(exSpec)
fmt.Printf("ExperimentSpec:\n%s\n", txt)
}
findings := c.Findings()
if len(findings) == 0 {
fmt.Printf("Checker returned no findings.\n")
return nil
}
fmt.Printf("Checker returned %d findings\n", len(findings))
for i, finding := range c.Findings() {
fmt.Println(i, finding)
}
return nil
}