From 93a5971eb77b743be3d99728b8349a833daa914f Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Tue, 1 Jul 2025 14:12:11 -0400 Subject: [PATCH 01/12] add send-perf-pr-comment and testing script --- .evergreen/config.yml | 8 ++++++++ etc/perf-pr-comment.sh | 6 ++++++ 2 files changed, 14 insertions(+) create mode 100755 etc/perf-pr-comment.sh diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 05832906d1..903acb5f90 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -285,6 +285,13 @@ functions: echo "Response Body: $response_body" echo "HTTP Status: $http_status" + send-perf-pr-comment: + - command: shell.exec + params: + working_dir: src/go.mongodb.org/mongo-driver + binary: bash + script: etc/perf-pr-comment.sh + run-enterprise-auth-tests: - command: ec2.assume_role params: @@ -676,6 +683,7 @@ tasks: binary: bash args: [*task-runner, driver-benchmark] - func: send-perf-data + - func: send-perf-pr-comment - name: test-standalone-noauth-nossl tags: ["test", "standalone"] diff --git a/etc/perf-pr-comment.sh b/etc/perf-pr-comment.sh new file mode 100755 index 0000000000..cf5d3bad4d --- /dev/null +++ b/etc/perf-pr-comment.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -e +set -x + +echo "hello world - perf comment" From 0103afdea67885a8bb925dad271fd441bb80f7e5 Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Tue, 1 Jul 2025 14:20:34 -0400 Subject: [PATCH 02/12] refactor to Taskfile --- .evergreen/config.yml | 6 +++--- Taskfile.yml | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 903acb5f90..420f5c996d 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -286,11 +286,11 @@ functions: echo "HTTP Status: $http_status" send-perf-pr-comment: - - command: shell.exec + - command: subprocess.exec + type: test params: - working_dir: src/go.mongodb.org/mongo-driver binary: bash - script: etc/perf-pr-comment.sh + args: [*task-runner, perf-pr-comment] run-enterprise-auth-tests: - command: ec2.assume_role diff --git a/Taskfile.yml b/Taskfile.yml index 3473cb4981..8b2c7df0e3 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -70,6 +70,8 @@ tasks: pr-task: bash etc/pr-task.sh + perf-pr-comment: bash etc/perf-pr-comment.sh + # Lint with various GOOS and GOARCH tasks to catch static analysis failures that may only affect # specific operating systems or architectures. For example, staticcheck will only check for 64-bit # alignment of atomically accessed variables on 32-bit architectures (see From 364f2796cf6b2ca3324652478b83f966f0213be7 Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Wed, 2 Jul 2025 11:02:04 -0400 Subject: [PATCH 03/12] added test ping, but might have network issues --- .evergreen/config.yml | 1 + Taskfile.yml | 2 +- internal/cmd/perfnotif/main.go | 45 ++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 internal/cmd/perfnotif/main.go diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 420f5c996d..94a2024093 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -290,6 +290,7 @@ functions: type: test params: binary: bash + include_expansions_in_env: [perf_uri] args: [*task-runner, perf-pr-comment] run-enterprise-auth-tests: diff --git a/Taskfile.yml b/Taskfile.yml index 8b2c7df0e3..617340ac2d 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -70,7 +70,7 @@ tasks: pr-task: bash etc/pr-task.sh - perf-pr-comment: bash etc/perf-pr-comment.sh + perf-pr-comment: go run internal/cmd/perfnotif/main.go # Lint with various GOOS and GOARCH tasks to catch static analysis failures that may only affect # specific operating systems or architectures. For example, staticcheck will only check for 64-bit diff --git a/internal/cmd/perfnotif/main.go b/internal/cmd/perfnotif/main.go new file mode 100644 index 0000000000..722acb110c --- /dev/null +++ b/internal/cmd/perfnotif/main.go @@ -0,0 +1,45 @@ +// Copyright (C) MongoDB, Inc. 2025-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +package main + +import ( + "context" + "fmt" + "log" + "os" + "time" + + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" +) + +func main() { + uri := os.Getenv("perf_uri") + if uri == "" { + log.Panic("perf_uri env variable is not set") + } + + client, err := mongo.Connect(options.Client().ApplyURI(uri)) + if err != nil { + log.Panicf("Error connecting client: %v", err) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + err = client.Ping(ctx, nil) + if err != nil { + log.Panicf("Error pinging MongoDB Analytics: %v", err) + } + + fmt.Println("Successfully connected to MongoDB Analytics node.") + + err = client.Disconnect(context.Background()) + if err != nil { + log.Panicf("Failed to disconnect client: %v", err) + } +} From 2db16858daeaaf240dbb0698192c57101ca03f0b Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Wed, 2 Jul 2025 15:13:29 -0400 Subject: [PATCH 04/12] try with private endpoint --- .evergreen/config.yml | 2 +- internal/cmd/perfnotif/main.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 94a2024093..51b34f0777 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -290,7 +290,7 @@ functions: type: test params: binary: bash - include_expansions_in_env: [perf_uri] + include_expansions_in_env: [perf_uri_private_endpoint] args: [*task-runner, perf-pr-comment] run-enterprise-auth-tests: diff --git a/internal/cmd/perfnotif/main.go b/internal/cmd/perfnotif/main.go index 722acb110c..22e7e15d5d 100644 --- a/internal/cmd/perfnotif/main.go +++ b/internal/cmd/perfnotif/main.go @@ -18,9 +18,9 @@ import ( ) func main() { - uri := os.Getenv("perf_uri") + uri := os.Getenv("perf_uri_private_endpoint") if uri == "" { - log.Panic("perf_uri env variable is not set") + log.Panic("perf_uri_private_endpoint env variable is not set") } client, err := mongo.Connect(options.Client().ApplyURI(uri)) From 24d243d303970c1d0ffae873560151ec59d11986 Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Thu, 3 Jul 2025 10:50:38 -0400 Subject: [PATCH 05/12] test filtering documents --- internal/cmd/perfnotif/main.go | 43 ++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/internal/cmd/perfnotif/main.go b/internal/cmd/perfnotif/main.go index 22e7e15d5d..9e8c1ac2af 100644 --- a/internal/cmd/perfnotif/main.go +++ b/internal/cmd/perfnotif/main.go @@ -13,6 +13,7 @@ import ( "os" "time" + "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" ) @@ -30,16 +31,54 @@ func main() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - err = client.Ping(ctx, nil) if err != nil { log.Panicf("Error pinging MongoDB Analytics: %v", err) } - fmt.Println("Successfully connected to MongoDB Analytics node.") + coll := client.Database("expanded_metrics").Collection("change_points") + var cursor *mongo.Cursor + cursor, err = getDocsWithContext(coll) + if err != nil { + log.Panicf("Error retrieving documents from collection.") + } + fmt.Printf("Successfully retrieved %d documents.", cursor.RemainingBatchLength()) + err = client.Disconnect(context.Background()) if err != nil { log.Panicf("Failed to disconnect client: %v", err) } + +} + +func getDocsWithContext(coll *mongo.Collection) (*mongo.Cursor, error) { + filter := bson.D{ + {"time_series_info.project", "mongo-go-driver"}, + {"time_series_info.variant", "perf"}, + {"time_series_info.task", "perf"}, + // {"commit", commitName}, + {"triage_contexts", bson.M{"$in": []string{"GoDriver perf (h-score)"}}}, + } + + projection := bson.D{ + {"time_series_info.project", 1}, + {"time_series_info.task", 1}, + {"time_series_info.test", 1}, + {"triage_contexts", 1}, + {"h_score", 1}, + } + + findOptions := options.Find().SetProjection(projection) + + findCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + cursor, err := coll.Find(findCtx, filter, findOptions) + if err != nil { + return nil, err + } + defer cursor.Close(findCtx) + + return cursor, err } From 4a9511e7b70848964072ca73a15e162c487c6432 Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Tue, 8 Jul 2025 09:48:29 -0400 Subject: [PATCH 06/12] decode docs and display in evg logs, dummy commit for now --- .evergreen/config.yml | 2 ++ internal/cmd/perfnotif/main.go | 61 ++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 51b34f0777..2855d4b2ad 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -290,6 +290,8 @@ functions: type: test params: binary: bash + env: + COMMIT: "${github_commit}" include_expansions_in_env: [perf_uri_private_endpoint] args: [*task-runner, perf-pr-comment] diff --git a/internal/cmd/perfnotif/main.go b/internal/cmd/perfnotif/main.go index 9e8c1ac2af..6516eeda0d 100644 --- a/internal/cmd/perfnotif/main.go +++ b/internal/cmd/perfnotif/main.go @@ -18,6 +18,17 @@ import ( "go.mongodb.org/mongo-driver/v2/mongo/options" ) +type ChangePoint struct { + TimeSeriesInfo struct { + Project string `bson:"project"` + Task string `bson:"task"` + Test string `bson:"test"` + Measurement string `bson:"measurement"` + } `bson:"time_series_info"` + TriageContexts []string `bson:"triage_contexts"` + HScore float64 `bson:"h_score"` +} + func main() { uri := os.Getenv("perf_uri_private_endpoint") if uri == "" { @@ -37,13 +48,33 @@ func main() { } fmt.Println("Successfully connected to MongoDB Analytics node.") + commit := os.Getenv("COMMIT") // TODO: get PR from evergreen instead of just the commit, and use PR to get latest commit + if commit == "" { + log.Panic("could not retrieve commit number") + } + coll := client.Database("expanded_metrics").Collection("change_points") - var cursor *mongo.Cursor - cursor, err = getDocsWithContext(coll) + var changePoints []ChangePoint + changePoints, err = getDocsWithContext(coll, "50cf0c20d228975074c0010bfb688917e25934a4") // TODO: restore test commit if err != nil { - log.Panicf("Error retrieving documents from collection.") + log.Panicf("Error retrieving and decoding documents from collection: %v.", err) + } + + if len(changePoints) == 0 { + log.Panicf("Nothing was decoded") + } + + fmt.Print("Documents:") + for _, cp := range changePoints { + fmt.Printf(" Project: %s, Task: %s, Test: %s, Measurement: %s, Triage Contexts: %v, H-Score: %f\n", + cp.TimeSeriesInfo.Project, + cp.TimeSeriesInfo.Task, + cp.TimeSeriesInfo.Test, + cp.TimeSeriesInfo.Measurement, + cp.TriageContexts, + cp.HScore, + ) } - fmt.Printf("Successfully retrieved %d documents.", cursor.RemainingBatchLength()) err = client.Disconnect(context.Background()) if err != nil { @@ -52,12 +83,12 @@ func main() { } -func getDocsWithContext(coll *mongo.Collection) (*mongo.Cursor, error) { +func getDocsWithContext(coll *mongo.Collection, commit string) ([]ChangePoint, error) { filter := bson.D{ {"time_series_info.project", "mongo-go-driver"}, {"time_series_info.variant", "perf"}, {"time_series_info.task", "perf"}, - // {"commit", commitName}, + {"commit", commit}, {"triage_contexts", bson.M{"$in": []string{"GoDriver perf (h-score)"}}}, } @@ -65,6 +96,7 @@ func getDocsWithContext(coll *mongo.Collection) (*mongo.Cursor, error) { {"time_series_info.project", 1}, {"time_series_info.task", 1}, {"time_series_info.test", 1}, + {"time_series_info.measurement", 1}, {"triage_contexts", 1}, {"h_score", 1}, } @@ -80,5 +112,20 @@ func getDocsWithContext(coll *mongo.Collection) (*mongo.Cursor, error) { } defer cursor.Close(findCtx) - return cursor, err + fmt.Printf("Successfully retrieved %d documents from commit %s.", cursor.RemainingBatchLength(), commit) + + var changePoints []ChangePoint + for cursor.Next(findCtx) { + var cp ChangePoint + if err := cursor.Decode(&cp); err != nil { + return nil, err + } + changePoints = append(changePoints, cp) + } + + if err := cursor.Err(); err != nil { + return nil, err + } + + return changePoints, nil } From 04b822bc0649c757f05c773c8165e02f9dece35c Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Tue, 8 Jul 2025 10:11:37 -0400 Subject: [PATCH 07/12] refactor to use shell script in taskfile --- Taskfile.yml | 2 +- etc/perf-pr-comment.sh | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index 617340ac2d..8b2c7df0e3 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -70,7 +70,7 @@ tasks: pr-task: bash etc/pr-task.sh - perf-pr-comment: go run internal/cmd/perfnotif/main.go + perf-pr-comment: bash etc/perf-pr-comment.sh # Lint with various GOOS and GOARCH tasks to catch static analysis failures that may only affect # specific operating systems or architectures. For example, staticcheck will only check for 64-bit diff --git a/etc/perf-pr-comment.sh b/etc/perf-pr-comment.sh index cf5d3bad4d..aba08743aa 100755 --- a/etc/perf-pr-comment.sh +++ b/etc/perf-pr-comment.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash +# perf-pr-comment +# Generates a report of Go Driver perf changes for the current branch. -set -e -set -x +set -eux -echo "hello world - perf comment" +go run ./internal/cmd/perfnotif/main.go From 769f15058b7a468bfabc9b7beea2810c4dd3c7b1 Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Tue, 8 Jul 2025 11:35:13 -0400 Subject: [PATCH 08/12] add md comment TODO perf baron link, remove hardcoded commit number --- internal/cmd/perfnotif/main.go | 46 +++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/internal/cmd/perfnotif/main.go b/internal/cmd/perfnotif/main.go index 6516eeda0d..53e53d054e 100644 --- a/internal/cmd/perfnotif/main.go +++ b/internal/cmd/perfnotif/main.go @@ -7,6 +7,7 @@ package main import ( + "bytes" "context" "fmt" "log" @@ -48,33 +49,20 @@ func main() { } fmt.Println("Successfully connected to MongoDB Analytics node.") - commit := os.Getenv("COMMIT") // TODO: get PR from evergreen instead of just the commit, and use PR to get latest commit + commit := os.Getenv("COMMIT") if commit == "" { log.Panic("could not retrieve commit number") } coll := client.Database("expanded_metrics").Collection("change_points") var changePoints []ChangePoint - changePoints, err = getDocsWithContext(coll, "50cf0c20d228975074c0010bfb688917e25934a4") // TODO: restore test commit + changePoints, err = getDocsWithContext(coll, commit) if err != nil { log.Panicf("Error retrieving and decoding documents from collection: %v.", err) } - if len(changePoints) == 0 { - log.Panicf("Nothing was decoded") - } - - fmt.Print("Documents:") - for _, cp := range changePoints { - fmt.Printf(" Project: %s, Task: %s, Test: %s, Measurement: %s, Triage Contexts: %v, H-Score: %f\n", - cp.TimeSeriesInfo.Project, - cp.TimeSeriesInfo.Task, - cp.TimeSeriesInfo.Test, - cp.TimeSeriesInfo.Measurement, - cp.TriageContexts, - cp.HScore, - ) - } + var markdownComment = getMarkdownComment(changePoints) + fmt.Print(markdownComment.String()) err = client.Disconnect(context.Background()) if err != nil { @@ -112,7 +100,7 @@ func getDocsWithContext(coll *mongo.Collection, commit string) ([]ChangePoint, e } defer cursor.Close(findCtx) - fmt.Printf("Successfully retrieved %d documents from commit %s.", cursor.RemainingBatchLength(), commit) + fmt.Printf("Successfully retrieved %d documents from commit %s.\n", cursor.RemainingBatchLength(), commit) var changePoints []ChangePoint for cursor.Next(findCtx) { @@ -129,3 +117,25 @@ func getDocsWithContext(coll *mongo.Collection, commit string) ([]ChangePoint, e return changePoints, nil } + +func getMarkdownComment(changePoints []ChangePoint) bytes.Buffer { + var buffer bytes.Buffer + + buffer.WriteString("# 👋 GoDriver Performance Notification\n") + + if len(changePoints) > 0 { + buffer.WriteString("The following benchmark tests had statistically significant changes (i.e., h-score > 0.6):\n") + buffer.WriteString("| Benchmark Test | Measurement | H-Score | Performance Baron |\n") + buffer.WriteString("|---|---|---|---|\n") + + for _, cp := range changePoints { + var perfBaronLink = "" + fmt.Fprintf(&buffer, "| %s | %s | %f | %s |\n", cp.TimeSeriesInfo.Test, cp.TimeSeriesInfo.Measurement, cp.HScore, perfBaronLink) + } + } else { + buffer.WriteString("There were no significant changes to the performance to report.\n") + } + buffer.WriteString("For a comprehensive view of all microbenchmark results for this PR's commit, please visit this link.") + + return buffer +} From fb6cac663129bc9eea06fd68fe2075b254e711c8 Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Tue, 8 Jul 2025 14:10:50 -0400 Subject: [PATCH 09/12] add todo for link generation --- internal/cmd/perfnotif/main.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/cmd/perfnotif/main.go b/internal/cmd/perfnotif/main.go index 53e53d054e..4d6606527f 100644 --- a/internal/cmd/perfnotif/main.go +++ b/internal/cmd/perfnotif/main.go @@ -129,13 +129,15 @@ func getMarkdownComment(changePoints []ChangePoint) bytes.Buffer { buffer.WriteString("|---|---|---|---|\n") for _, cp := range changePoints { - var perfBaronLink = "" - fmt.Fprintf(&buffer, "| %s | %s | %f | %s |\n", cp.TimeSeriesInfo.Test, cp.TimeSeriesInfo.Measurement, cp.HScore, perfBaronLink) + // TODO: update this to dynamically generate link + var perfBaronLink = "https://performance-monitoring-and-analysis.server-tig.prod.corp.mongodb.com/baron" + fmt.Fprintf(&buffer, "| %s | %s | %f | [linked here](%s) |\n", cp.TimeSeriesInfo.Test, cp.TimeSeriesInfo.Measurement, cp.HScore, perfBaronLink) } } else { buffer.WriteString("There were no significant changes to the performance to report.\n") } - buffer.WriteString("For a comprehensive view of all microbenchmark results for this PR's commit, please visit this link.") + // TODO: update this to dynamically generate link + buffer.WriteString("*For a comprehensive view of all microbenchmark results for this PR's commit, please visit [this link](https://performance-monitoring-and-analysis.server-tig.prod.corp.mongodb.com/baron?change_point_filters=%5B%7B%22active%22%3Atrue%2C%22name%22%3A%22commit%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22commit_date%22%2C%22operator%22%3A%22after%22%2C%22type%22%3A%22date%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22calculated_on%22%2C%22operator%22%3A%22after%22%2C%22type%22%3A%22date%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22project%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22mongo-go-driver%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22variant%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22perf%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22task%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22perf%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22test%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22measurement%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22args%22%2C%22operator%22%3A%22eq%22%2C%22type%22%3A%22json%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22percent_change%22%2C%22operator%22%3A%22gt%22%2C%22type%22%3A%22number%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22z_score_change%22%2C%22operator%22%3A%22gt%22%2C%22type%22%3A%22number%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22h_score%22%2C%22operator%22%3A%22gt%22%2C%22type%22%3A%22number%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22absolute_change%22%2C%22operator%22%3A%22gt%22%2C%22type%22%3A%22number%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22build_failures%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22bf_suggestions%22%2C%22operator%22%3A%22inlist%22%2C%22type%22%3A%22listSelect%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22triage_status%22%2C%22operator%22%3A%22inlist%22%2C%22type%22%3A%22listSelect%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22changeType%22%2C%22operator%22%3A%22inlist%22%2C%22type%22%3A%22listSelect%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22triage_contexts%22%2C%22operator%22%3A%22inlist%22%2C%22type%22%3A%22listSelect%22%2C%22value%22%3A%5B%22GoDriver+perf+%28h-score%29%22%5D%7D%5D).*") return buffer } From db0a567923c79e3d30664a7dc8328b5232b82f09 Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Wed, 9 Jul 2025 13:40:42 -0400 Subject: [PATCH 10/12] temporary --- .../cmd/perfnotif/generateperfbaronlink.go | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 internal/cmd/perfnotif/generateperfbaronlink.go diff --git a/internal/cmd/perfnotif/generateperfbaronlink.go b/internal/cmd/perfnotif/generateperfbaronlink.go new file mode 100644 index 0000000000..a333947e72 --- /dev/null +++ b/internal/cmd/perfnotif/generateperfbaronlink.go @@ -0,0 +1,38 @@ +// Copyright (C) MongoDB, Inc. 2025-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +package main + +// const baseURL = "https://performance-monitoring-and-analysis.server-tig.prod.corp.mongodb.com/baron" + +type CPFilter struct { + Active bool `bson:"active"` + Name string `bson:"name"` + Operator string `bson:"operator"` + Type string `bson:"type"` + Value interface{} `json:"value,omitempty"` +} + +/* +[{"active":true,"name":"commit","operator":"matches","type":"regex","value":""}, +{"active":true,"name":"commit_date","operator":"after","type":"date"}, +{"active":true,"name":"calculated_on","operator":"after","type":"date"}, +{"active":true,"name":"project","operator":"matches","type":"regex","value":""}, +{"active":true,"name":"variant","operator":"matches","type":"regex","value":""}, +{"active":true,"name":"task","operator":"matches","type":"regex","value":""}, +{"active":true,"name":"test","operator":"matches","type":"regex","value":""}, +{"active":true,"name":"measurement","operator":"matches","type":"regex","value":""}, +{"active":true,"name":"args","operator":"eq","type":"json"}, +{"active":true,"name":"percent_change","operator":"gt","type":"number"}, +{"active":true,"name":"z_score_change","operator":"gt","type":"number"}, +{"active":true,"name":"h_score","operator":"gt","type":"number"}, +{"active":true,"name":"absolute_change","operator":"gt","type":"number"}, +{"active":true,"name":"build_failures","operator":"matches","type":"regex","value":""}, +{"active":true,"name":"bf_suggestions","operator":"inlist","type":"listSelect"}, +{"active":true,"name":"triage_status","operator":"inlist","type":"listSelect"}, +{"active":true,"name":"changeType","operator":"inlist","type":"listSelect"}, +{"active":true,"name":"triage_contexts","operator":"inlist","type":"listSelect","value":["GoDriver perf (h-score)"]}] +*/ From fc766565d12d79845493aa76761e8253439962e9 Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Thu, 10 Jul 2025 10:49:59 -0400 Subject: [PATCH 11/12] dynamically generate perf baron link --- .../cmd/perfnotif/generateperfbaronlink.go | 133 ++++++++++++++---- internal/cmd/perfnotif/main.go | 19 ++- 2 files changed, 120 insertions(+), 32 deletions(-) diff --git a/internal/cmd/perfnotif/generateperfbaronlink.go b/internal/cmd/perfnotif/generateperfbaronlink.go index a333947e72..0caf44d3d3 100644 --- a/internal/cmd/perfnotif/generateperfbaronlink.go +++ b/internal/cmd/perfnotif/generateperfbaronlink.go @@ -6,33 +6,114 @@ package main -// const baseURL = "https://performance-monitoring-and-analysis.server-tig.prod.corp.mongodb.com/baron" +import ( + "encoding/json" + "fmt" + "net/url" +) + +const baseURL = "https://performance-monitoring-and-analysis.server-tig.prod.corp.mongodb.com/baron" type CPFilter struct { - Active bool `bson:"active"` - Name string `bson:"name"` - Operator string `bson:"operator"` - Type string `bson:"type"` - Value interface{} `json:"value,omitempty"` + Active bool `json:"active"` + Name string `json:"name"` + Operator string `json:"operator"` + Type string `json:"type"` + Value interface{} `json:"value,omitempty"` // Exclude if no value, following structure of change_point_filters +} + +func createBaseChangePointFilters() []CPFilter { + return []CPFilter{ + {Active: true, Name: "commit", Operator: "matches", Type: "regex"}, + {Active: true, Name: "commit_date", Operator: "after", Type: "date"}, + {Active: true, Name: "calculated_on", Operator: "after", Type: "date"}, + {Active: true, Name: "project", Operator: "matches", Type: "regex"}, + {Active: true, Name: "variant", Operator: "matches", Type: "regex"}, + {Active: true, Name: "task", Operator: "matches", Type: "regex"}, + {Active: true, Name: "test", Operator: "matches", Type: "regex"}, + {Active: true, Name: "measurement", Operator: "matches", Type: "regex"}, + {Active: true, Name: "args", Operator: "eq", Type: "json"}, + {Active: true, Name: "percent_change", Operator: "gt", Type: "number"}, + {Active: true, Name: "z_score_change", Operator: "gt", Type: "number"}, + {Active: true, Name: "h_score", Operator: "gt", Type: "number"}, + {Active: true, Name: "absolute_change", Operator: "gt", Type: "number"}, + {Active: true, Name: "build_failures", Operator: "matches", Type: "regex"}, + {Active: true, Name: "bf_suggestions", Operator: "inlist", Type: "listSelect"}, + {Active: true, Name: "triage_status", Operator: "inlist", Type: "listSelect"}, + {Active: true, Name: "changeType", Operator: "inlist", Type: "listSelect"}, + {Active: true, Name: "triage_contexts", Operator: "inlist", Type: "listSelect"}, + } +} + +func updateFilterString(filters []CPFilter, name string, val string) { + for i := range filters { + if filters[i].Name == name { + filters[i].Value = val + } + } +} + +func updateFilterList(filters []CPFilter, name string, val []string) { + for i := range filters { + if filters[i].Name == name { + filters[i].Value = val + } + } } -/* -[{"active":true,"name":"commit","operator":"matches","type":"regex","value":""}, -{"active":true,"name":"commit_date","operator":"after","type":"date"}, -{"active":true,"name":"calculated_on","operator":"after","type":"date"}, -{"active":true,"name":"project","operator":"matches","type":"regex","value":""}, -{"active":true,"name":"variant","operator":"matches","type":"regex","value":""}, -{"active":true,"name":"task","operator":"matches","type":"regex","value":""}, -{"active":true,"name":"test","operator":"matches","type":"regex","value":""}, -{"active":true,"name":"measurement","operator":"matches","type":"regex","value":""}, -{"active":true,"name":"args","operator":"eq","type":"json"}, -{"active":true,"name":"percent_change","operator":"gt","type":"number"}, -{"active":true,"name":"z_score_change","operator":"gt","type":"number"}, -{"active":true,"name":"h_score","operator":"gt","type":"number"}, -{"active":true,"name":"absolute_change","operator":"gt","type":"number"}, -{"active":true,"name":"build_failures","operator":"matches","type":"regex","value":""}, -{"active":true,"name":"bf_suggestions","operator":"inlist","type":"listSelect"}, -{"active":true,"name":"triage_status","operator":"inlist","type":"listSelect"}, -{"active":true,"name":"changeType","operator":"inlist","type":"listSelect"}, -{"active":true,"name":"triage_contexts","operator":"inlist","type":"listSelect","value":["GoDriver perf (h-score)"]}] -*/ +func createGoDriverContextFilters() []CPFilter { + baseFilters := createBaseChangePointFilters() + updateFilterString(baseFilters, "project", "mongo-go-driver") + updateFilterString(baseFilters, "variant", "perf") + updateFilterString(baseFilters, "task", "perf") + updateFilterList(baseFilters, "triage_contexts", []string{"GoDriver perf (h-score)"}) + return baseFilters +} + +func GeneratePerfBaronLink(commitName string, testName string) (string, error) { // If empty parameters, then doesn't filter for commit or test + cpFilters := createGoDriverContextFilters() + if commitName != "" { + updateFilterString(cpFilters, "commit", commitName) + } + if testName != "" { + updateFilterString(cpFilters, "test", testName) + } + + cpFiltersJSON, err := json.Marshal(cpFilters) + if err != nil { + return "", fmt.Errorf("failed to marshal change_point_filters to json: %v", err) + } + u, err := url.Parse(baseURL) + if err != nil { + return "", fmt.Errorf("failed to parse base URL: %v", err) + } + + q := u.Query() + q.Set("change_point_filters", string(cpFiltersJSON)) + u.RawQuery = q.Encode() + return u.String(), nil +} + +func TestGeneratePerfBaronLink() { + fmt.Println() + // just mongo-go-driver, perf, perf + link1, err1 := GeneratePerfBaronLink("", "") + if err1 == nil { + fmt.Println(link1) + } + // add commit + link2, err2 := GeneratePerfBaronLink("50cf0c20d228975074c0010bfb688917e25934a4", "") + if err2 == nil { + fmt.Println(link2) + } + // add test + link3, err3 := GeneratePerfBaronLink("", "BenchmarkMultiInsertLargeDocument") + if err3 == nil { + fmt.Println(link3) + } + // add both + link4, err4 := GeneratePerfBaronLink("50cf0c20d228975074c0010bfb688917e25934a4", "BenchmarkMultiInsertLargeDocument") + if err4 == nil { + fmt.Println(link4) + } +} diff --git a/internal/cmd/perfnotif/main.go b/internal/cmd/perfnotif/main.go index 4d6606527f..444d7d3b41 100644 --- a/internal/cmd/perfnotif/main.go +++ b/internal/cmd/perfnotif/main.go @@ -61,7 +61,7 @@ func main() { log.Panicf("Error retrieving and decoding documents from collection: %v.", err) } - var markdownComment = getMarkdownComment(changePoints) + var markdownComment = getMarkdownComment(changePoints, commit) fmt.Print(markdownComment.String()) err = client.Disconnect(context.Background()) @@ -118,7 +118,7 @@ func getDocsWithContext(coll *mongo.Collection, commit string) ([]ChangePoint, e return changePoints, nil } -func getMarkdownComment(changePoints []ChangePoint) bytes.Buffer { +func getMarkdownComment(changePoints []ChangePoint, commit string) bytes.Buffer { var buffer bytes.Buffer buffer.WriteString("# 👋 GoDriver Performance Notification\n") @@ -129,15 +129,22 @@ func getMarkdownComment(changePoints []ChangePoint) bytes.Buffer { buffer.WriteString("|---|---|---|---|\n") for _, cp := range changePoints { - // TODO: update this to dynamically generate link - var perfBaronLink = "https://performance-monitoring-and-analysis.server-tig.prod.corp.mongodb.com/baron" + perfBaronLink, err := GeneratePerfBaronLink(commit, cp.TimeSeriesInfo.Test) + if err != nil { + perfBaronLink = "" + } fmt.Fprintf(&buffer, "| %s | %s | %f | [linked here](%s) |\n", cp.TimeSeriesInfo.Test, cp.TimeSeriesInfo.Measurement, cp.HScore, perfBaronLink) } } else { buffer.WriteString("There were no significant changes to the performance to report.\n") } - // TODO: update this to dynamically generate link - buffer.WriteString("*For a comprehensive view of all microbenchmark results for this PR's commit, please visit [this link](https://performance-monitoring-and-analysis.server-tig.prod.corp.mongodb.com/baron?change_point_filters=%5B%7B%22active%22%3Atrue%2C%22name%22%3A%22commit%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22commit_date%22%2C%22operator%22%3A%22after%22%2C%22type%22%3A%22date%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22calculated_on%22%2C%22operator%22%3A%22after%22%2C%22type%22%3A%22date%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22project%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22mongo-go-driver%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22variant%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22perf%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22task%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22perf%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22test%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22measurement%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22args%22%2C%22operator%22%3A%22eq%22%2C%22type%22%3A%22json%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22percent_change%22%2C%22operator%22%3A%22gt%22%2C%22type%22%3A%22number%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22z_score_change%22%2C%22operator%22%3A%22gt%22%2C%22type%22%3A%22number%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22h_score%22%2C%22operator%22%3A%22gt%22%2C%22type%22%3A%22number%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22absolute_change%22%2C%22operator%22%3A%22gt%22%2C%22type%22%3A%22number%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22build_failures%22%2C%22operator%22%3A%22matches%22%2C%22type%22%3A%22regex%22%2C%22value%22%3A%22%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22bf_suggestions%22%2C%22operator%22%3A%22inlist%22%2C%22type%22%3A%22listSelect%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22triage_status%22%2C%22operator%22%3A%22inlist%22%2C%22type%22%3A%22listSelect%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22changeType%22%2C%22operator%22%3A%22inlist%22%2C%22type%22%3A%22listSelect%22%7D%2C%7B%22active%22%3Atrue%2C%22name%22%3A%22triage_contexts%22%2C%22operator%22%3A%22inlist%22%2C%22type%22%3A%22listSelect%22%2C%22value%22%3A%5B%22GoDriver+perf+%28h-score%29%22%5D%7D%5D).*") + + perfBaronLink, err := GeneratePerfBaronLink(commit, "") + if err != nil { + perfBaronLink = "" + } + fmt.Println(perfBaronLink) + buffer.WriteString("\n*For a comprehensive view of all microbenchmark results for this PR's commit, please visit [this link](" + perfBaronLink + ")*") return buffer } From 0e9b2ac6952ee464b2e781219fcbb8013ec48bec Mon Sep 17 00:00:00 2001 From: Selena Zhou Date: Thu, 10 Jul 2025 16:24:29 -0400 Subject: [PATCH 12/12] perf baron link works --- etc/perf-pr-comment.sh | 2 +- internal/cmd/perfnotif/main.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/etc/perf-pr-comment.sh b/etc/perf-pr-comment.sh index aba08743aa..1d2b3a1cfb 100755 --- a/etc/perf-pr-comment.sh +++ b/etc/perf-pr-comment.sh @@ -4,4 +4,4 @@ set -eux -go run ./internal/cmd/perfnotif/main.go +go run ./internal/cmd/perfnotif/main.go ./internal/cmd/perfnotif/generateperfbaronlink.go diff --git a/internal/cmd/perfnotif/main.go b/internal/cmd/perfnotif/main.go index 444d7d3b41..f3f1eab363 100644 --- a/internal/cmd/perfnotif/main.go +++ b/internal/cmd/perfnotif/main.go @@ -143,7 +143,6 @@ func getMarkdownComment(changePoints []ChangePoint, commit string) bytes.Buffer if err != nil { perfBaronLink = "" } - fmt.Println(perfBaronLink) buffer.WriteString("\n*For a comprehensive view of all microbenchmark results for this PR's commit, please visit [this link](" + perfBaronLink + ")*") return buffer