Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions internal/cli/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ type benchmarkBaseline struct {
GOOS string `json:"goos,omitempty"`
GOARCH string `json:"goarch,omitempty"`
GOMAXPROCS string `json:"gomaxprocs,omitempty"`
NumCPU int `json:"num_cpu"`
CWD string `json:"cwd"`
SQLite string `json:"sqlite_driver,omitempty"`
BenchCtx map[string]any `json:"bench_ctx,omitempty"`
Env map[string]string `json:"env,omitempty"`
Expand Down Expand Up @@ -332,6 +334,7 @@ func extractBenchmarkContext(output string) map[string]any {
keys := []string{
"fixture_files",
"sqlite_driver",
"sqlite_profile",
}
out := map[string]any{}
for line := range strings.SplitSeq(output, "\n") {
Expand Down Expand Up @@ -369,6 +372,7 @@ func runBenchmark(ctx context.Context, stdout io.Writer, args []string) error {
benchtime := fs.String("benchtime", "100ms", "benchmark time per test")
saveBaseline := fs.Bool("save-baseline", true, "save current benchmark result as baseline")
files := fs.Int("files", 0, "fixture file count (sets CODEGRAPH_BENCH_FILES)")
sqliteProfile := fs.String("sqlite-profile", "", "SQLite performance profile for benchmarks (sets CODEGRAPH_BENCH_SQLITE_PROFILE)")
gomaxprocs := fs.Int("gomaxprocs", 0, "GOMAXPROCS for benchmark subprocess (0 = default)")
if err := fs.Parse(args); err != nil {
return err
Expand Down Expand Up @@ -406,6 +410,12 @@ func runBenchmark(ctx context.Context, stdout io.Writer, args []string) error {
} else if v := strings.TrimSpace(os.Getenv("CODEGRAPH_BENCH_FILES")); v != "" {
benchEnv["CODEGRAPH_BENCH_FILES"] = v
}
if v := strings.TrimSpace(*sqliteProfile); v != "" {
env = append(env, "CODEGRAPH_BENCH_SQLITE_PROFILE="+v)
benchEnv["CODEGRAPH_BENCH_SQLITE_PROFILE"] = v
} else if v := strings.TrimSpace(os.Getenv("CODEGRAPH_BENCH_SQLITE_PROFILE")); v != "" {
benchEnv["CODEGRAPH_BENCH_SQLITE_PROFILE"] = v
}
if *gomaxprocs > 0 {
v := strconv.Itoa(*gomaxprocs)
env = append(env, "GOMAXPROCS="+v)
Expand All @@ -416,13 +426,16 @@ func runBenchmark(ctx context.Context, stdout io.Writer, args []string) error {
cmd.Env = env
out, err := cmd.CombinedOutput()
benchCtx := extractBenchmarkContext(string(out))
cwd, _ := os.Getwd()
result := map[string]any{
"command": append([]string{"go"}, cmdArgs...),
"count": *count,
"benchtime": *benchtime,
"go_version": runtime.Version(),
"goos": runtime.GOOS,
"goarch": runtime.GOARCH,
"num_cpu": runtime.NumCPU(),
"cwd": cwd,
Comment thread
isink17 marked this conversation as resolved.
"sqlite_driver": store.SQLiteDriverName(),
"env": benchEnv,
"bench_ctx": benchCtx,
Expand Down Expand Up @@ -471,6 +484,8 @@ func runBenchmark(ctx context.Context, stdout io.Writer, args []string) error {
GOOS: runtime.GOOS,
GOARCH: runtime.GOARCH,
GOMAXPROCS: gomaxLabel,
NumCPU: runtime.NumCPU(),
CWD: cwd,
SQLite: store.SQLiteDriverName(),
BenchCtx: benchCtx,
Env: benchEnv,
Expand Down
31 changes: 31 additions & 0 deletions internal/cli/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,37 @@ func main() {}
}
}

func TestBenchmarkBaselineIncludesContextFields(t *testing.T) {
payload := benchmarkBaseline{
CreatedAt: "2026-01-02T03:04:05Z",
Command: []string{"go", "test"},
Count: 1,
Benchtime: "10ms",
GoVersion: "go1.x",
GOOS: "windows",
GOARCH: "amd64",
GOMAXPROCS: "default",
NumCPU: 12,
CWD: "C:\\repo",
SQLite: "sqlite",
Benchmarks: map[string]benchmarkMetric{"BenchmarkX": {NsPerOp: 1}},
}
data, err := json.Marshal(payload)
if err != nil {
t.Fatalf("Marshal(payload) error = %v", err)
}
var decoded map[string]any
if err := json.Unmarshal(data, &decoded); err != nil {
t.Fatalf("Unmarshal(payload) error = %v", err)
}
if _, ok := decoded["num_cpu"]; !ok {
t.Fatalf("payload missing num_cpu: %s", string(data))
}
if _, ok := decoded["cwd"]; !ok {
t.Fatalf("payload missing cwd: %s", string(data))
}
}

func TestRunIndexWithRepoDBDirSkipsRepoDatabaseFiles(t *testing.T) {
home := filepath.Join(t.TempDir(), "codegraph-home")
t.Setenv("CODEGRAPH_HOME", home)
Expand Down
10 changes: 9 additions & 1 deletion internal/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,15 @@ func newCommandList() []*command {
{
name: "benchmark",
description: "benchmarks",
usageLines: []string{" benchmark [--count N] [--benchtime DURATION] [--save-baseline] [--files N] [--gomaxprocs N]"},
usageLines: []string{" benchmark [--count N] [--benchtime DURATION] [--save-baseline] [--files N] [--sqlite-profile NAME] [--gomaxprocs N]"},
Comment thread
isink17 marked this conversation as resolved.
flags: []commandFlag{
{name: "--count", description: "number of benchmark runs"},
{name: "--benchtime", description: "benchmark time per test"},
{name: "--save-baseline", description: "save current benchmark result as baseline"},
{name: "--files", description: "fixture file count (sets CODEGRAPH_BENCH_FILES)"},
{name: "--sqlite-profile", description: "SQLite performance profile (sets CODEGRAPH_BENCH_SQLITE_PROFILE)"},
{name: "--gomaxprocs", description: "GOMAXPROCS for benchmark subprocess (0 = default)"},
},
run: func(ctx context.Context, cfg config.Config, stdout, stderr io.Writer, invokedName string, args []string) error {
return runBenchmark(ctx, stdout, args)
},
Expand Down
Loading