8000 Persist benchmark results in CI by ryanslade · Pull Request #461 · xataio/pgroll · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Persist benchmark results in CI #461

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9795241
Start saving benchmark results to a file
ryanslade Nov 12, 2024
9ee34b4
Temporarily enable benchmarks on PR
ryanslade Nov 12, 2024
36920b9
Upload benchmark results
ryanslade Nov 12, 2024
27a1b3a
Fix file name
ryanslade Nov 12, 2024
c5b3f75
Uniuqe file name per run
ryanslade Nov 12, 2024
1ef2a70
Use correct filename
ryanslade Nov 12, 2024
71d75e8
Output name also needs to be unique across jobs
ryanslade Nov 12, 2024
784161f
Gather all benchmark results
ryanslade Nov 12, 2024
4330148
Trigger CI
ryanslade Nov 12, 2024
f5acc35
Clean up exit code handling
ryanslade Nov 12, 2024
6ad60eb
Try and enable benchmarks again
ryanslade Nov 12, 2024
736dc14
Download and list results
ryanslade Nov 12, 2024
77d2a24
Forgot runs-on
ryanslade Nov 12, 2024
24cd5c4
Gather should run after all benchmarks
ryanslade Nov 12, 2024
dc9bf1f
Download all artifacts to the same directory
ryanslade Nov 12, 2024
6e3fdef
Combing all results and upload artifact
ryanslade Nov 12, 2024
f8a7e81
Include SHA in filename
ryanslade Nov 12, 2024
684f969
Remove trailing "
ryanslade Nov 12, 2024
6846665
No JSON indenting, actually makes it harder to consume
ryanslade Nov 12, 2024
d6d134c
Grab SHA from context
ryanslade Nov 12, 2024
ba25bde
Merge branch 'main' into rs/save-benchmark-report
ryanslade Nov 12, 2024
6107a37
Include timestamp
ryanslade Nov 13, 2024
fa0ecfd
Move some types so they are available outside the package
ryanslade Nov 13, 2024
f86d454
Rename recorder
8000 ryanslade Nov 13, 2024
ad20eab
No need for mutex
ryanslade Nov 13, 2024
561b948
Add license
ryanslade Nov 13, 2024
12faf6e
Merge branch 'main' into rs/save-benchmark-report
ryanslade Nov 13, 2024
66604da
Merge branch 'main' into rs/save-benchmark-report
ryanslade Nov 14, 2024
b8612dd
Upload results to S3
ryanslade Nov 15, 2024
a404a18
Update step name
ryanslade Nov 15, 2024
087aa23
Don't run benchmarks on PR
ryanslade Nov 15, 2024
12e442f
Add helper and make results more flexible
ryanslade Nov 15, 2024
756c181
Comment typo
ryanslade Nov 15, 2024
d1b142f
Update role-to-assume
ryanslade Nov 15, 2024
189353c
Enable on PR to test
ryanslade Nov 15, 2024
c41eb59
Don't run on PR
ryanslade Nov 15, 2024
26b1c88
Run temporarily
ryanslade Nov 18, 2024
f3696ea
Disable again
ryanslade Nov 18, 2024
87678db
Enable manual trigger
ryanslade Nov 18, 2024
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
37 changes: 36 additions & 1 deletion .github/workflows/benchmark.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
name: Benchmark
on:
workflow_dispatch:
push:
branches:
- main
permissions:
id-token: write # For getting AWS permissions
contents: read
packages: read
jobs:
Expand All @@ -25,4 +27,37 @@ jobs:
- name: Run benchmarks
run: make bench
env:
POSTGRES_VERSION: ${{ matrix.pgVersion }}
POSTGRES_VERSION: ${{ matrix.pgVersion }}

- name: Upload results
uses: actions/upload-artifact@v4
with:
name: benchmark_result_${{ matrix.pgVersion }}.json
path: internal/benchmarks/benchmark_result_${{ matrix.pgVersion }}.json

gather:
name: 'Gather results'
runs-on: ubuntu-latest
needs: [benchmark]

steps:
- uses: actions/download-artifact@v4
with:
path: ./results/
merge-multiple: true

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::493985724844:role/pgroll-benchmark-results-access
aws-region: us-east-1
mask-aws-account-id: 'no'

- name: Download current results from S3
run: aws s3 cp s3://pgroll-benchmark-results/benchmark-results.json ./benchmark-results.json

- name: Append new results
run: cat results/*.json >> benchmark-results.json

- name: Upload combined results
run: aws s3 cp ./benchmark-results.json s3://pgroll-benchmark-results/benchmark-results.json
39 changes: 39 additions & 0 deletions internal/benchmarks/benchmarks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: Apache-2.0

package benchmarks

import (
"os"
"time"
)

type Reports struct {
GitSHA string
PostgresVersion string
Timestamp int64
Reports []Report
}

func (r *Reports) AddReport(report Report) {
r.Reports = append(r.Reports, report)
}

func getPostgresVersion() string {
return os.Getenv("POSTGRES_VERSION")
}

func newReports() *Reports {
return &Reports{
GitSHA: os.Getenv("GITHUB_SHA"),
PostgresVersion: getPostgresVersion(),
Timestamp: time.Now().Unix(),
Reports: []Report{},
}
}

type Report struct {
Name string
RowCount int
Unit string
Result float64
}
44 changes: 42 additions & 2 deletions internal/benchmarks/benchmarks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ package benchmarks
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"os"
"strconv"
"testing"

Expand All @@ -19,10 +22,32 @@ import (

const unitRowsPerSecond = "rows/s"

var rowCounts = []int{10_000, 100_000, 300_000}
var (
rowCounts = []int{10_000, 100_000, 300_000}
reports = newReports()
)

func TestMain(m *testing.M) {
testutils.SharedTestMain(m)
testutils.SharedTestMain(m, func() (err error) {
// Only run in GitHub actions
if os.Getenv("GITHUB_ACTIONS") != "true" {
return nil
}

w, err := os.Create(fmt.Sprintf("benchmark_result_%s.json", getPostgresVersion()))
if err != nil {
return fmt.Errorf("creating report file: %w", err)
}
defer func() {
err = w.Close()
}()

encoder := json.NewEncoder(w)
if err := encoder.Encode(reports); err != nil {
return fmt.Errorf("encoding report file: %w", err)
}
return nil
})
}

func BenchmarkBackfill(b *testing.B) {
Expand All @@ -48,6 +73,8 @@ func BenchmarkBackfill(b *testing.B) {
b.Logf("Backfilled %d rows in %s", rowCount, b.Elapsed())
rowsPerSecond := float64(rowCount) / b.Elapsed().Seconds()
b.ReportMetric(rowsPerSecond, unitRowsPerSecond)

addRowsPerSecond(b, rowCount, rowsPerSecond)
})
})
}
Expand Down Expand Up @@ -87,6 +114,8 @@ func BenchmarkWriteAmplification(b *testing.B) {
b.StopTimer()
rowsPerSecond := float64(rowCount) / b.Elapsed().Seconds()
b.ReportMetric(rowsPerSecond, unitRowsPerSecond)

addRowsPerSecond(b, rowCount, rowsPerSecond)
})
})
}
Expand Down Expand Up @@ -116,6 +145,8 @@ func BenchmarkWriteAmplification(b *testing.B) {
b.StopTimer()
rowsPerSecond := float64(rowCount) / b.Elapsed().Seconds()
b.ReportMetric(rowsPerSecond, unitRowsPerSecond)

addRowsPerSecond(b, rowCount, rowsPerSecond)
})
})
}
Expand Down Expand Up @@ -149,6 +180,15 @@ func setupInitialTable(tb testing.TB, ctx context.Context, testSchema string, mi
seed(tb, rowCount, db)
}

func addRowsPerSecond(b *testing.B, rowCount int, perSecond float64) {
reports.AddReport(Report{
Name: b.Name(),
Unit: unitRowsPerSecond,
RowCount: rowCount,
Result: perSecond,
})
}

// Simple table with a nullable `name` field.
var migCreateTable = migrations.Migration{
Name: "01_create_table",
Expand Down
23 changes: 19 additions & 4 deletions internal/testutils/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ const defaultPostgresVersion = "15.3"
// tConnStr holds the connection string to the test container created in TestMain.
var tConnStr string

// SharedTestMain starts a postgres container to be used by all tests in a package.
// Each test then connects to the container and creates a new database.
func SharedTestMain(m *testing.M) {
// SharedTestMain starts a postgres container to be used by all tests in a package. Each test then
// connects to the container and creates a new database. Optional functions that will run after all
// tests can be added and should return a nil error to indicate they ran successfully. If they return
// an error all subsequent functions will be skipped.
func SharedTestMain(m *testing.M, postRunHooks ...func() error) {
ctx := context.Background()

waitForLogs := wait.
Expand Down Expand Up @@ -73,7 +75,20 @@ func SharedTestMain(m *testing.M) {
log.Printf("Failed to terminate container: %v", err)
}

os.Exit(exitCode)
if exitCode != 0 {
log.Printf("Non zero exit code (%d), skipping post run hooks", exitCode)
os.Exit(exitCode)
}

for _, hook := range postRunHooks {
err := hook()
if err != nil {
log.Printf("Post-run hook failed: %v", err)
os.Exit(1)
}
}

os.Exit(0)
}

// TestSchema returns the schema in which migration tests apply migrations. By
Expand Down
0