> ## Documentation Index
> Fetch the complete documentation index at: https://codspeed.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing Benchmarks in Go

> Create benchmarks for your Go codebase using the `testing` package

export const CIWorkflow = ({minimal = false, enableWorkflowDispatch = true, runsOn = "ubuntu-latest", highlight = [], mode, modes, submodules = false, preSteps = [], buildSteps = ["# ...", "# Setup your environment here:", "#  - Configure your Python/Rust/Node version", "#  - Install your dependencies", "#  - Build your benchmarks (if using a compiled language)", "# ..."], benchmarkCommand = ["<Insert your benchmark command here>"], jobName = "Run benchmarks", env = {}}) => {
  const modeList = modes || (mode ? [mode] : undefined);
  if (!modeList || modeList.length === 0) {
    throw new Error("mode or modes is required");
  }
  const indent = (lines, depth) => {
    const reindentedLines = lines.map(l => l.length === 0 ? l : (" ").repeat(depth) + l);
    return reindentedLines.join("\n");
  };
  const workflowDispatchSection = enableWorkflowDispatch ? "  # `workflow_dispatch` allows CodSpeed to trigger backtest\n" + "  # performance analysis in order to generate initial data.\n" + "  workflow_dispatch:\n" : "";
  let yaml = "";
  if (!minimal) {
    yaml += `
name: CodSpeed Benchmarks

on:
  push:
    branches:
      - "main" # or "master"
  pull_request:
`;
    yaml += workflowDispatchSection;
  }
  yaml += `
jobs:
  benchmarks:
    name: ${jobName}
    runs-on: ${runsOn}`;
  if (!minimal) {
    yaml += `
    permissions: # optional for public repositories
      contents: read # required for actions/checkout
      id-token: write # required for OIDC authentication with CodSpeed`;
  }
  if (preSteps.length > 0) yaml += "\n" + indent(preSteps, 4);
  yaml += `
    steps:
      - uses: actions/checkout@v5`;
  if (submodules) {
    const value = typeof submodules === "string" ? submodules : "true";
    yaml += `\n        with:\n          submodules: ${value}`;
  }
  yaml += "\n" + indent(buildSteps, 6);
  const modeValue = modeList.join(",");
  yaml += `
      - name: Run the benchmarks
        uses: CodSpeedHQ/action@v4
        with:
          mode: ${modeValue}`;
  if (benchmarkCommand.length > 0) {
    const indentedBenchCommand = benchmarkCommand.length > 1 ? benchmarkCommand[0] + "\n" + indent(benchmarkCommand.slice(1), 12) : benchmarkCommand;
    const runLine = indent(["run: "], 10) + indentedBenchCommand;
    yaml += `\n${runLine}`;
  }
  const envEntries = Object.entries(env);
  if (envEntries.length > 0) {
    const envLines = ["env:", ...envEntries.map(([k, v]) => `  ${k}: ${v}`)];
    yaml += "\n" + indent(envLines, 8);
  }
  return <CodeBlock language="yaml" highlight={JSON.stringify(highlight)} {...minimal || ({
    filename: ".github/workflows/codspeed.yml",
    icon: "github"
  })}>
      {yaml}
    </CodeBlock>;
};

<Note>
  The Go integration is still in early development, and only some `go test` CLI flags are supported.
  See the [compatibility section](#compatibility) for more information on how to ensure your benchmarks work with CodSpeed.

  Additionally, **only the [walltime instrument](/instruments/walltime) is
  currently supported**

  If you have any feedback, please reach out to us via
  [Discord](https://discord.gg/MxpaCfKSqF) or
  [email our support](mailto:contact@codspeed.io).
</Note>

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, your benchmarks will automatically
be built and the reports will be sent to CodSpeed.

## Creating benchmarks

You can just use the `testing` package to write benchmarks in Go. If the
benchmarks are working with `go test`, then they will also automatically be
detected by CodSpeed without any additional configuration.

Here's an example of a simple Fibonacci function benchmark:

```go fib_test.go theme={null}
package example

import "testing"

func BenchmarkFibonacci10(b *testing.B) {
  for b.Loop() {
    fib(10)
  }
}
```

<Info>
  **We recommend using [`b.Loop()`](https://pkg.go.dev/testing#B.Loop) as it's more precise and efficient**.

  Still, `for i := 0; i < b.N; i++` is also supported for backward compatibility
  (before Go 1.24):

  ```go theme={null}
  func BenchmarkFibonacci20(b *testing.B) {
    for i := 0; i < b.N; i++ {
      fib(20)
    }
  }
  ```
</Info>

For a deeper dive into Go benchmarking, see the dedicated guide:

<Card title="How to Benchmark Go with the testing Package" icon="golang" href="/guides/how-to-benchmark-go-with-testing" horizontal>
  An in-depth guide to writing Go benchmarks: sub-benchmarks, parallel
  benchmarks, benchstat, pprof, and CodSpeed CI integration.
</Card>

## Testing the benchmarks locally

To run the benchmarks with CodSpeed locally, you need to install the `codspeed`
runner:

```shellsession title=terminal icon="square-terminal" theme={null}
curl -fsSL https://codspeed.io/install.sh | sh
```

You can then run your `go test` command with CodSpeed:

```shellsession title=terminal icon="square-terminal" theme={null}
$ codspeed run --skip-upload -- go test -bench=.
►►► Running the benchmarks
[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           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 @ 1215.790MHz
BenchmarkFibonacci10-16         	 1348328	       361.9 ns/op
BenchmarkFibonacci20-16         	  106713	       47947 ns/op
PASS
[INFO  go_runner] Parsed 2 raw results
[INFO  go_runner] Results written to "/tmp/profile.qPQgi6h0iK.out/results/231603.json"
```

<Tip>
  This will print all the benchmarks that can be run with CodSpeed and warnings
  if some benchmarks are not supported.
</Tip>

## Running the benchmarks in your CI

To generate performance reports, you need to run the benchmarks in your CI. This
allows CodSpeed to automatically run benchmarks and warn you about regressions
during development.

<Tip>
  If you want more details on how to configure the CodSpeed action, you can check
  out the [Continuous Reporting section](/integrations/ci).
</Tip>

Here is an example of a GitHub Actions workflow that runs the benchmarks and
reports the results to CodSpeed on every push to the `main` branch and every
pull request:

<CIWorkflow mode="walltime" runsOn="codspeed-macro" buildSteps={["- uses: actions/setup-go@v6"]} benchmarkCommand={["go test -bench=."]} />

<Warning>
  **Incomplete flamegraphs on ARM64?**

  If your flamegraphs appear incomplete on ARM64 (e.g., on
  [CodSpeed Macro runners](/features/macro-runners)), try setting the
  `CODSPEED_PERF_UNWINDING_MODE` environment variable to `fp`:

  ```yaml {5-6} theme={null}
  - uses: CodSpeedHQ/action@v4
    with:
      run: go test -bench=.
      instruments: walltime
    env:
      CODSPEED_PERF_UNWINDING_MODE: fp
  ```

  This switches from DWARF-based unwinding to frame-pointer-based unwinding, which
  produces more reliable call stacks for Go on ARM64. CodSpeed tries to detect
  this automatically, but it cannot catch every case.
</Warning>

## Recipes

### Sharding benchmarks in parallel CI jobs

If your benchmarks are taking too much time to run under the CodSpeed action,
you can run them in parallel to speed up the execution.

To parallelize your benchmarks, simply add filters to the `go test` command to
only run a subset of benchmarks in each job.

<CIWorkflow minimal runsOn="codspeed-macro" mode="walltime" highlight={[5, 6, 7, 15]} preSteps={["strategy:", "  matrix:", "    target: [Fib10, Fib20]"]} buildSteps={["- uses: actions/setup-go@v6"]} benchmarkCommand={["go test -bench=${{ matrix.target }}"]} />

<Info>
  **Compatibility**

  We only support the following flags for `go test`:

  * `-bench` (required)

  If you run into issues or require certain features, please
  [open an issue](https://github.com/CodSpeedHQ/codspeed-go/issues) or
  [join our Discord](https://discord.com/invite/MxpaCfKSqF) to get help.
</Info>

## Next steps

<CardGroup>
  <Card title="Walltime instrument" icon="stopwatch" href="/instruments/walltime">
    Learn more about the Walltime instrument and how to use it.
  </Card>

  <Card title="How to Benchmark Go with the testing Package" icon="golang" href="/guides/how-to-benchmark-go-with-testing">
    An in-depth guide to writing Go benchmarks with CodSpeed.
  </Card>

  <Card title="Dive into performance changes" icon="bars-sort" href="/features/profiling">
    Learn more about profiling and how to read flamegraphs.
  </Card>

  <Card title="Example repository with benchmarks" icon="github" href="https://github.com/CodSpeedHQ/go-gin-benchmarks-example">
    The example GitHub repository for this Gin Gonic API with benchmarks.
  </Card>
</CardGroup>
