Skip to content

feat: create codspeed go repository with the compat layer #2

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: pre-commit/[email protected]
with:
extra_args: --all-files
16 changes: 16 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-merge-conflict
- id: check-added-large-files

- repo: https://github.com/tekwizely/pre-commit-golang
rev: v1.0.0-rc.2
hooks:
- id: go-mod-tidy
- id: go-fmt
51 changes: 50 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,50 @@
# codspeed-go
<div align="center">
<h1>codspeed-go</h1>

[![CI](https://github.com/CodSpeedHQ/codspeed-go/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/CodSpeedHQ/codspeed-go/actions/workflows/ci.yml)
[![Discord](https://img.shields.io/badge/chat%20on-discord-7289da.svg)](https://discord.com/invite/MxpaCfKSqF)
[![CodSpeed Badge](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/CodSpeedHQ/codspeed-go)

</div>

This repo contains the integration libraries for using CodSpeed in Go:

- [`go-runner`](./go-runner/): Golang benchmark builder and runner
- [`compat/testing`](./compat/testing/): Compatibility layer for the `testing` package.

## Usage

Integrating CodSpeed into your Go codebase requires **no modification**. You can continue using `go test` and the `testing` package as you normally would. When running your benchmarks in CI with CodSpeed, we will manually build and run the benchmarks and report the results to CodSpeed.

For information on how to integrate it, see the [CodSpeed documentation](https://codspeed.io/docs/benchmarks/golang). If you need further information to integrate CodSpeed to your project, please feel free to open an issue or ask for help on our discord server.


## Manual Usage

To run the benchmarks with CodSpeed locally, you need to install the `go-runner` crate which is used to build and execute the benchmarks with instrumentation:
```bash
$ cd go-runner
$ cargo install --path .
```

Then you can run the benchmarks with (the syntax is equivalent to `go test` but supports fewer flags). This will print all the benchmarks that can be run with CodSpeed and warnings if some benchmarks are not supported.
```bash
$ cd example
$ export CODSPEED_PROFILE_FOLDER=/tmp/codspeed
$ go-runner test -bench=.
[INFO go_runner] Discovered 1 package
[INFO go_runner] Total benchmarks discovered: 2
[INFO go_runner] Found BenchmarkFibonacci10 in "fib_test.go"
[INFO go_runner] Found BenchmarkFibonacci20_Loop in "fib_test.go"
[INFO go_runner] Generating custom runner for package: example
[INFO go_runner] Running benchmarks for package: example
Running with CodSpeed instrumentation
goos: linux
goarch: amd64
cpu: 12th Gen Intel(R) Core(TM) i7-1260P @ 1672.130MHz
BenchmarkFibonacci10/fibonacci(10)/fibonacci(10)-16 1 1523 ns/op
BenchmarkFibonacci20_Loop-16 1 31373 ns/op
PASS
[INFO go_runner] Parsed 2 raw results
[INFO go_runner] Results written to "/tmp/codspeed/results/177951.json"
```
70 changes: 70 additions & 0 deletions compat/testing/testing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//go:build codspeed
// +build codspeed

package codspeed

import (
codspeed_testing "github.com/CodSpeedHQ/codspeed-go/testing/testing"
)

type B = codspeed_testing.B
type BenchmarkResult = codspeed_testing.BenchmarkResult
type Cover = codspeed_testing.Cover
type CoverBlock = codspeed_testing.CoverBlock
type F = codspeed_testing.F
type InternalBenchmark = codspeed_testing.InternalBenchmark
type InternalExample = codspeed_testing.InternalExample
type InternalFuzzTarget = codspeed_testing.InternalFuzzTarget
type InternalTest = codspeed_testing.InternalTest
type M = codspeed_testing.M
type PB = codspeed_testing.PB
type T = codspeed_testing.T
type TB = codspeed_testing.TB

func AllocsPerRun(runs int, f func()) (avg float64) {
return codspeed_testing.AllocsPerRun(runs, f)
}

func CoverMode() string {
return codspeed_testing.CoverMode()
}

func Coverage() float64 {
return codspeed_testing.Coverage()
}

func Init() {
codspeed_testing.Init()
}

func Main(matchString func(pat, str string) (bool, error), tests []codspeed_testing.InternalTest, benchmarks []codspeed_testing.InternalBenchmark, examples []codspeed_testing.InternalExample) {
codspeed_testing.Main(matchString, tests, benchmarks, examples)
}

func RegisterCover(c codspeed_testing.Cover) {
codspeed_testing.RegisterCover(c)
}

func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []codspeed_testing.InternalBenchmark) {
codspeed_testing.RunBenchmarks(matchString, benchmarks)
}

func RunExamples(matchString func(pat, str string) (bool, error), examples []codspeed_testing.InternalExample) (ok bool) {
return codspeed_testing.RunExamples(matchString, examples)
}

func RunTests(matchString func(pat, str string) (bool, error), tests []codspeed_testing.InternalTest) (ok bool) {
return codspeed_testing.RunTests(matchString, tests)
}

func Short() bool {
return codspeed_testing.Short()
}

func Testing() bool {
return codspeed_testing.Testing()
}

func Verbose() bool {
return codspeed_testing.Verbose()
}
70 changes: 70 additions & 0 deletions compat/testing/testing_compat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//go:build !codspeed
// +build !codspeed

package codspeed

import (
stdtesting "testing"
)

type B = stdtesting.B
type BenchmarkResult = stdtesting.BenchmarkResult
type Cover = stdtesting.Cover
type CoverBlock = stdtesting.CoverBlock
type F = stdtesting.F
type InternalBenchmark = stdtesting.InternalBenchmark
type InternalExample = stdtesting.InternalExample
type InternalFuzzTarget = stdtesting.InternalFuzzTarget
type InternalTest = stdtesting.InternalTest
type M = stdtesting.M
type PB = stdtesting.PB
type T = stdtesting.T
type TB = stdtesting.TB

func AllocsPerRun(runs int, f func()) (avg float64) {
return stdtesting.AllocsPerRun(runs, f)
}

func CoverMode() string {
return stdtesting.CoverMode()
}

func Coverage() float64 {
return stdtesting.Coverage()
}

func Init() {
stdtesting.Init()
}

func Main(matchString func(pat, str string) (bool, error), tests []stdtesting.InternalTest, benchmarks []stdtesting.InternalBenchmark, examples []stdtesting.InternalExample) {
stdtesting.Main(matchString, tests, benchmarks, examples)
}

func RegisterCover(c stdtesting.Cover) {
stdtesting.RegisterCover(c)
}

func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []stdtesting.InternalBenchmark) {
stdtesting.RunBenchmarks(matchString, benchmarks)
}

func RunExamples(matchString func(pat, str string) (bool, error), examples []stdtesting.InternalExample) (ok bool) {
return stdtesting.RunExamples(matchString, examples)
}

func RunTests(matchString func(pat, str string) (bool, error), tests []stdtesting.InternalTest) (ok bool) {
return stdtesting.RunTests(matchString, tests)
}

func Short() bool {
return stdtesting.Short()
}

func Testing() bool {
return stdtesting.Testing()
}

func Verbose() bool {
return stdtesting.Verbose()
}
86 changes: 86 additions & 0 deletions example-codspeed/cli/runner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//go:build codspeed
// +build codspeed

package main

import (
"fmt"
"io"
"reflect"
"time"

example "example"

codspeed_testing "github.com/CodSpeedHQ/codspeed-go/testing/testing"
)

type corpusEntry = struct {
Parent string
Path string
Data []byte
Values []any
Generation int
IsSeed bool
}

type simpleDeps struct{}

func (d simpleDeps) ImportPath() string { return "" }
func (d simpleDeps) MatchString(pat, str string) (bool, error) { return true, nil }
func (d simpleDeps) SetPanicOnExit0(bool) {}
func (d simpleDeps) StartCPUProfile(io.Writer) error { return nil }
func (d simpleDeps) StopCPUProfile() {}
func (d simpleDeps) StartTestLog(io.Writer) {}
func (d simpleDeps) StopTestLog() error { return nil }
func (d simpleDeps) WriteProfileTo(string, io.Writer, int) error { return nil }

func (d simpleDeps) CoordinateFuzzing(
fuzzTime time.Duration,
fuzzN int64,
minimizeTime time.Duration,
minimizeN int64,
parallel int,
corpus []corpusEntry,
types []reflect.Type,
corpusDir,
cacheDir string,
) error {
return nil
}
func (d simpleDeps) RunFuzzWorker(fn func(corpusEntry) error) error {
return nil
}
func (d simpleDeps) ReadCorpus(dir string, types []reflect.Type) ([]corpusEntry, error) {
return nil, nil
}
func (d simpleDeps) CheckCorpus(vals []any, types []reflect.Type) error {
return nil
}
func (d simpleDeps) ResetCoverage() {}
func (d simpleDeps) SnapshotCoverage() {}
func (d simpleDeps) InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) {
return "", nil, nil
}

func main() {
var tests = []codspeed_testing.InternalTest{}
var fuzzTargets = []codspeed_testing.InternalFuzzTarget{}
var examples = []codspeed_testing.InternalExample{}
var benchmarks = []codspeed_testing.InternalBenchmark{
{
Name: "BenchmarkFibonacci10",
F: example.BenchmarkFibonacci10,
},
{
Name: "BenchmarkFibonacci20",
F: example.BenchmarkFibonacci20,
},
}

for i := 0; i < len(benchmarks); i++ {
fmt.Printf("Benchmark %d: %s\n", i, benchmarks[i].Name)
}

m := codspeed_testing.MainStart(simpleDeps{}, tests, benchmarks, fuzzTargets, examples)
m.Run()
}
8 changes: 8 additions & 0 deletions example-codspeed/fib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package example

func fibonacci(n int) int {
if n <= 1 {
return n
}
return fibonacci(n-1) + fibonacci(n-2)
}
35 changes: 35 additions & 0 deletions example-codspeed/fib_codspeed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package example

import (
testing "github.com/CodSpeedHQ/codspeed-go/compat/testing"
)

func BenchmarkFibonacci10(b *testing.B) {
// b.Run("fibonacci(40)", func(b *testing.B) {
// for i := 0; i < b.N; i++ {
// fibonacci(10)
// }
// })
// b.Run("fibonacci(20)", func(b *testing.B) {
// for i := 0; i < b.N; i++ {
// fibonacci(20)
// }
// })
b.RunParallel(func(b *testing.PB) {
for b.Next() {
fibonacci(30)
}
})
}

func BenchmarkFibonacci20(b *testing.B) {
for b.Loop() {
fibonacci(30)
}
}

// func BenchmarkFibonacci30(b *testing.B) {
// for i := 0; i < b.N; i++ {
// fibonacci(30)
// }
// }
7 changes: 7 additions & 0 deletions example-codspeed/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module example

go 1.24.3

require github.com/CodSpeedHQ/codspeed-go v0.0.0

replace github.com/CodSpeedHQ/codspeed-go => ..
8 changes: 8 additions & 0 deletions example/fib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package example

func fibonacci(n int) int {
if n <= 1 {
return n
}
return fibonacci(n-1) + fibonacci(n-2)
}
Loading
Loading