Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
817285f
Set up for perfcomp build from DET
zhouselena Aug 7, 2025
826490d
Ignore bin and temp files created by perfcomp
zhouselena Aug 7, 2025
508e17b
Perf analysis compare logic
zhouselena Aug 7, 2025
33e3c7f
Parse perf txt to md report
zhouselena Aug 7, 2025
8805889
Project-generalized perf comp CLI ported over from Go Driver
zhouselena Aug 7, 2025
26597c1
Add README for usage and instructions
zhouselena Aug 7, 2025
4c02876
Rename functions and add comments for clarity
zhouselena Aug 8, 2025
0338c9e
Add testing for compare.go
zhouselena Aug 8, 2025
e8e535f
Error messages should be lowercase
zhouselena Aug 9, 2025
a4e766d
Define context in caller runCompare
zhouselena Aug 9, 2025
1330563
Rename connection string
zhouselena Aug 9, 2025
abaa20c
Fix create comment for no stat sig benchmarks
zhouselena Aug 11, 2025
b6bff32
Update README to remind rerun build.sh
zhouselena Aug 12, 2025
0569078
Shell script builds and runs perfcomp
zhouselena Aug 12, 2025
4f0d903
Project flag must be mandatory
zhouselena Aug 12, 2025
82f1dc9
Propogate errors and other fixes
zhouselena Aug 12, 2025
141a568
Cleanup go version
zhouselena Aug 12, 2025
73ca146
Cleanup
zhouselena Aug 12, 2025
876925c
Update triage context instructions
zhouselena Aug 14, 2025
837ef5e
Add compare options for context,project,task,variant,version
zhouselena Aug 15, 2025
bea9582
Update shell script with required flags
zhouselena Aug 15, 2025
1dac817
Update README with flag behaviour
zhouselena Aug 15, 2025
48ed412
Update flags
zhouselena Aug 16, 2025
463eb92
Fix validation
zhouselena Aug 18, 2025
862a167
Update go.mod
zhouselena Aug 18, 2025
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
87 changes: 87 additions & 0 deletions .evergreen/perfcomp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# perfcomp

**perfcomp** is a performance analyzer on a PR commit basis.

## 📦 Installation

To install the latest version:

```bash
go install github.com/mongodb-labs/drivers-evergreen-tools/perfcomp/cmd/perfcomp@latest
```

Or build it locally in `bin/perfcomp`:

```bash
bash build.sh
```

## 🔧 Usage

### Parameters

To use `perfcomp`, you should have an analytics node URI env variable called `PERF_URI_PRIVATE_ENDPOINT`. You can request for it from the devprod performance team.

To run in your project repository, you need to create a [performance context](https://performance-monitoring-and-analysis.server-tig.prod.corp.mongodb.com/contexts) that captures all benchmarks in your project. This needs to be a triage context. Feel free to refer to the [Go Driver context](https://performance-monitoring-and-analysis.server-tig.prod.corp.mongodb.com/context/name/GoDriver%20perf%20task) as a template.

> _If you are creating a triage context for the first time, it may take a few hours for your project's data to be tagged._

You also need the name of the performance task and variant specific to your project. You can do a query in the analytics node `raw_results` collection:

```
db.raw_results.find({
“info.project”: “<project>”,
“info.version”: “<random_evergreen_version>"
})
```

and look for the `variant` and `task_name` properties.

### perfcomp CLI

```bash
perfcomp is a cli that reports stat-sig results between evergreen patches with the mainline commit

Usage:
perfcomp [command]

Available Commands:
compare compare evergreen patch to mainline commit
mdreport generates markdown output after run
```

### Commands

#### compare

```bash
compare evergreen patch to mainline commit

Usage:
perfcomp compare [version_id] [flags]

Flags:
--context string specify the performance triage context, ex. "GoDriver perf task" (required)
--project string specify the name of an existing Evergreen project, ex. "mongo-go-driver" (required)
--task string specify the evergreen perf task name, ex. "perf" (required)
--variant string specify the perf task variant, ex. "perf" (required)
```

#### mdreport

```bash
generates markdown output after compare run (must be run after `compare`)

Usage:
perfcomp mdreport
```

### Run via shell script

Alternatively, you can run the perfcomp shell script. This script will run build and then run `compare`. From the root directory,

```bash
PERF_URI_PRIVATE_ENDPOINT="<perf_uri>" VERSION_ID="<version>" PROJECT="<project>" CONTEXT="<context>" TASK="<task>" VARIANT="<variant>" .evergreen/run-perf-comp.sh
```

If you would like to see a markdown preview of the report, you can also pass in `HEAD_SHA=""`. This will generate `.evergreen/perfcomp/perf-report.md`.
6 changes: 6 additions & 0 deletions .evergreen/perfcomp/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail

BIN_DIR="bin"
mkdir -p $BIN_DIR
go build -o $BIN_DIR/perfcomp ./cmd/perfcomp/
150 changes: 150 additions & 0 deletions .evergreen/perfcomp/cmd/perfcomp/compare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package main

import (
"context"
"fmt"
"log"
"math"
"os"
"sort"
"strings"
"text/tabwriter"
"time"

"github.com/mongodb-labs/drivers-evergreen-tools/perfcomp"
"github.com/spf13/cobra"
)

func newCompareCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "compare",
Short: "compare evergreen patch to mainline commit",
// Version id is a required argument
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("this command requires an evergreen patch version ID")
}
return nil
},
}

cmd.Flags().String("project", "", "specify the name of an existing Evergreen project, ex. \"mongo-go-driver\"")
cmd.Flags().String("task", "", "specify the evergreen perf task name, ex. \"perf\"")
cmd.Flags().String("variant", "", "specify the perf task variant, ex. \"perf\"")
cmd.Flags().String("context", "", "specify the performance triage context, ex. \"GoDriver perf task\"")

for _, flag := range []string{"project", "task", "variant", "context"} {
cmd.MarkFlagRequired(flag)
}

cmd.Run = func(cmd *cobra.Command, args []string) {
// Check for variables
uri := os.Getenv("PERF_URI_PRIVATE_ENDPOINT")
if uri == "" {
log.Fatal("PERF_URI_PRIVATE_ENDPOINT env variable is not set")
}

// Retrieve and validate flag values
project, err := cmd.Flags().GetString("project")
if err != nil {
log.Fatalf("failed to get project flag: %v", err)
}
task, err := cmd.Flags().GetString("task")
if err != nil {
log.Fatalf("failed to get task flag: %v", err)
}
variant, err := cmd.Flags().GetString("variant")
if err != nil {
log.Fatalf("failed to get variant flag: %v", err)
}
context, err := cmd.Flags().GetString("context")
if err != nil {
log.Fatalf("failed to get context flag: %v", err)
}

// Validate all flags
for _, flag := range []string{project, task, variant, context} {
if flag == "" {
log.Fatalf("must provide %s", flag)
}
}

// Run compare function
if err := runCompare(cmd, args, project, task, variant, context); err != nil {
log.Fatalf("failed to compare: %v", err)
}
}

return cmd
}

func createComment(result perfcomp.CompareResult) string {
var comment strings.Builder

if len(result.SigEnergyStats) == 0 {
comment.Reset()
fmt.Fprintf(&comment, "There were no significant changes to the performance to report for version %s.\n", result.Version)
} else {
fmt.Fprintf(&comment, "The following benchmark tests for version %s had statistically significant changes (i.e., |z-score| > 1.96):\n\n", result.Version)

w := tabwriter.NewWriter(&comment, 0, 0, 1, ' ', 0)

fmt.Fprintln(w, "| Benchmark\t| Measurement\t| % Change\t| Patch Value\t| Stable Region\t| H-Score\t| Z-Score\t| ")
fmt.Fprintln(w, "| ---------\t| -----------\t| --------\t| -----------\t| -------------\t| -------\t| -------\t|")

sort.Slice(result.SigEnergyStats, func(i, j int) bool {
return math.Abs(result.SigEnergyStats[i].PercentChange) > math.Abs(result.SigEnergyStats[j].PercentChange)
})
for _, es := range result.SigEnergyStats {
fmt.Fprintf(w, "| %s\t| %s\t| %.4f\t| %.4f\t| Avg: %.4f, Med: %.4f, Stdev: %.4f\t| %.4f\t| %.4f\t|\n", es.Benchmark, es.Measurement, es.PercentChange, es.MeasurementVal, es.StableRegion.Mean, es.StableRegion.Median, es.StableRegion.Std, es.HScore, es.ZScore)
}

w.Flush()
}

comment.WriteString("\n*For a comprehensive view of all microbenchmark results for this PR's commit, please check out the Evergreen perf task for this patch.*")
return comment.String()

}

func runCompare(cmd *cobra.Command, args []string, project string, taskName string, variant string, perfContext string) error {
perfAnalyticsConnString := os.Getenv("PERF_URI_PRIVATE_ENDPOINT")
version := args[len(args)-1]

ctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second)
defer cancel()

res, err := perfcomp.Compare(ctx, perfAnalyticsConnString,
perfcomp.WithVersion(version),
perfcomp.WithProject(project),
perfcomp.WithTask(taskName),
perfcomp.WithVariant(variant),
perfcomp.WithContext(perfContext),
)
if err != nil {
log.Fatalf("failed to compare: %v", err)
}

res.CommitSHA = os.Getenv("HEAD_SHA")
res.MainlineCommit = os.Getenv("BASE_SHA")

prComment := createComment(*res)
log.Println("🧪 Performance Results")
log.Println(prComment)

if res.CommitSHA != "" {
// Write results to .txt file to parse into markdown comment
fWrite, err := os.Create(perfReportFileTxt)
if err != nil {
log.Fatalf("Could not create %s: %v", perfReportFileTxt, err)
}
defer fWrite.Close()

fmt.Fprintf(fWrite, "Version ID: %s\n", version)
fmt.Fprintf(fWrite, "Commit SHA: %s\n", res.CommitSHA)
fmt.Fprintln(fWrite, prComment)
log.Printf("PR commit %s: saved to %s for markdown comment.\n", res.CommitSHA, perfReportFileTxt)
}

return nil
}
22 changes: 22 additions & 0 deletions .evergreen/perfcomp/cmd/perfcomp/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

import (
"log"

"github.com/spf13/cobra"
)

func main() {
cmd := &cobra.Command{
Use: "perfcomp",
Short: "perfcomp is a cli that reports stat-sig results between evergreen patches with the mainline commit",
Version: "0.0.0-alpha",
}

cmd.AddCommand(newCompareCommand())
cmd.AddCommand(newMdCommand())

if err := cmd.Execute(); err != nil {
log.Fatalf("error: %v", err)
}
}
Loading
Loading