Generated banner for Golang Benchmark
Generated logo for Golang Benchmark

Golang Benchmark

Samuel BertheCommunityCreated by samberDistributed by Samuel Berthe

  • Skill
  • Tool integration
  • Software development
  • MIT
  • Low risk

From the author

Golang benchmarking, profiling, and performance measurement. Use when writing, running, or comparing Go benchmarks, profiling hot paths with pprof, interpreting CPU/memory/trace profiles, analyzing results with benchstat, setting up CI benchmark regression detection, or investigating production performance with Prometheus runtime metrics. Also use when the developer needs deep analysis on a specific performance indicator - this skill provides the measurement methodology, while `samber/cc-skills-golang@golang-performance` provides the optimization patterns.
— the description by samber

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a rigorous methodology for measuring Go performance. It covers the entire lifecycle: writing benchmarks with proper conventions, executing them under controlled conditions, generating profiles (CPU, memory, trace), and performing statistical comparisons using benchstat to distinguish real performance gains from noise. It emphasizes statistical significance and reproducible measurement over anecdotal testing.

What it does

  • Guides the creation of Go benchmarks using standard naming and file conventions.
  • Provides commands for running benchmarks with memory reporting and statistical iteration counts.
  • Facilitates the generation of CPU, memory, and execution trace profiles for deep analysis.
  • Uses benchstat to perform A/B comparisons with statistical confidence intervals.
  • Offers strategies for integrating performance regression detection into CI pipelines.
  • Explains how to document performance improvements in commit messages using benchmark data.

When to use it

  • When you need to measure the performance impact of a code change with statistical rigor.
  • When investigating performance bottlenecks using CPU or memory profiling.
  • When setting up automated performance regression gating in CI.
  • When comparing multiple optimization variants to identify the most effective approach.
  • When you need to verify that a code change has a measurable impact before committing.

Advantages

  • Promotes statistical rigor, preventing misleading conclusions from single benchmark runs.
  • Standardizes benchmark file naming and function ordering for better maintainability.
  • Integrates seamlessly with standard Go tooling and performance analysis utilities.
  • Provides clear guidance on avoiding common pitfalls like noisy neighbors and dead-code elimination.
  • Enables data-driven performance documentation in git history.

Usage examples

“How do I run my benchmarks 10 times to ensure statistical significance?”
The agent will provide the command: go test -run='^$' -bench=. -benchmem -count=10 ./pkg/...
“Compare my current changes against the main branch for performance regressions.”
The agent will guide you to use benchdiff to compare git refs, ensuring results are cached and statistically compared.
“How do I generate and analyze a CPU profile for my benchmark?”
The agent will show how to run go test with -cpuprofile, followed by using go tool pprof to interactively analyze the resulting file.
“How should I format my commit message when I optimize a function?”
The agent will provide a template including the hardware context and the benchstat output table to prove the performance gain.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/samber/golang-benchmark/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip golang-benchmark.zip -d .agents/skills

Documentation by samber

Persona: You are a Go performance measurement engineer. You never draw conclusions from a single benchmark run — statistical rigor and controlled conditions are prerequisites before any optimization decision.

Thinking mode: Reason as thoroughly as possible for benchmark analysis, profile interpretation, and performance comparison tasks — deep reasoning prevents misinterpreting profiling data and ensures statistically sound conclusions. On Claude Code, use ultrathink to trigger extended thinking explicitly.

Dependencies:

  • benchstat: go install golang.org/x/perf/cmd/benchstat@latest

Go Benchmarking & Performance Measurement

Performance improvement does not exist without measures — if you can measure it, you can improve it.

This skill covers the full measurement workflow: write a benchmark, run it, profile the result, compare before/after with statistical rigor, and track regressions in CI. For optimization patterns to apply after measurement, → See samber/cc-skills-golang@golang-performance skill. For pprof setup on running services, → See samber/cc-skills-golang@golang-troubleshooting skill.

Writing Benchmarks

File and Ordering Conventions

Benchmark functions live in a _bench_test.go file named after the source file under benchmark, not after the individual function — parser.go -> parser_bench_test.go, containing BenchmarkParse, BenchmarkEncode, etc., not a separate benchmarkparse_test.go per function.

  • Keeping benchmarks in their own file (instead of mixed into parser_test.go) keeps go test -bench=. ./pkg/parser output free of unrelated Test* noise.

  • It separates fixtures sized for measurement (large inputs, long-lived setup) from those sized for correctness — the two rarely share the same shape.

  • The file still follows Go's one-test-file-per-source-file convention (→ See samber/cc-skills-golang@golang-testing skill), just with the _bench suffix marking its narrower purpose.

Order Benchmark* functions inside parser_bench_test.go to mirror the order of the functions/methods they measure in parser.go — a reader comparing the two files top to bottom should find BenchmarkParse at the same relative position as Parse.

b.Loop() (Go 1.24+) — preferred

For Go 1.24+, prefer b.Loop() for new benchmarks. It times only the loop body and keeps function arguments/results alive, which reduces dead-code-elimination mistakes.

func BenchmarkParse(b *testing.B) {
    data := loadFixture("large.json") // setup — excluded from timing
    for b.Loop() {
        Parse(data)  // compiler cannot eliminate this call
    }
}

Legacy b.N loops still compile and are fine to keep when preserving existing benchmarks or supporting Go <1.24. They are easier to get wrong: setup may need b.ResetTimer(), and results may need a sink if the compiler can eliminate the work. Go 1.26 fixed an earlier b.Loop() inlining limitation — benchmarks on 1.24–1.25 already benefit from b.Loop() but may miss inlining optimizations that 1.26 delivers.

Go 1.27's size-specialized allocator changes allocation-heavy benchmark baselines (faster sub-80-byte allocations, larger binaries) independent of any code change. Treat a benchstat comparison that straddles the Go 1.26→1.27 toolchain boundary as measuring the toolchain, not the code — rerun the "before" benchmark on the same toolchain as "after" before trusting the delta.

Memory tracking
func BenchmarkAlloc(b *testing.B) {
    b.ReportAllocs() // or run with -benchmem flag
    var sink []byte
    for b.Loop() {
        sink = make([]byte, 1024)
    }
    _ = sink
}

b.ReportMetric() adds custom metrics (e.g., throughput):

b.ReportMetric(float64(totalBytes)/b.Elapsed().Seconds(), "bytes/s") // b.Elapsed() is only valid inside b.Loop()
Sub-benchmarks and table-driven
func BenchmarkEncode(b *testing.B) {
    for _, size := range []int{64, 256, 4096} {
        b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) {
            data := make([]byte, size)
            for b.Loop() {
                Encode(data)
            }
        })
    }
}

Running Benchmarks

go test -bench=BenchmarkEncode -benchmem -count=10 ./pkg/... | tee bench.txt
FlagPurpose
-bench=.Run all benchmarks (regexp filter)
-benchmemReport allocations (B/op, allocs/op)
-count=10Run 10 times for statistical significance
-benchtime=3sMinimum time per benchmark (default 1s)
-cpu=1,2,4Run with different GOMAXPROCS values
-cpuprofile=cpu.profWrite CPU profile
-memprofile=mem.profWrite memory profile
-trace=trace.outWrite execution trace

Output format: BenchmarkEncode/size=64-8 5000000 230.5 ns/op 128 B/op 2 allocs/op — the -8 suffix is GOMAXPROCS, ns/op is time per operation, B/op is bytes allocated per op, allocs/op is heap allocation count per op.

Comparing Optimization Variants in Parallel

When several competing optimization hypotheses exist for the same bottleneck, implement each variant in its own isolated worktree via a separate sub-agent, so their code changes never collide in the shared working tree.

Run the benchmarks serially, not concurrently. Concurrent benchmark runs share the same CPU — the noisy-neighbor effect contaminates ns/op and reintroduces the exact statistical noise -count and benchstat exist to eliminate. Implementing in parallel is safe (isolated worktrees, no file contention); measuring in parallel is not (shared hardware, real contention). Run each variant's benchmark one at a time, back in the main tree or sequentially per worktree.

Compare every variant's benchstat output against the same baseline report, keep the winner, and remove the worktrees for the rest.

Documenting Results in Commits

Paste benchstat output in the commit body when the change has a measurable performance impact. This documents why an optimization was made, prevents future readers from reverting it, and lets reviewers verify the claim without re-running benchmarks.

Commit format:

perf(parser): reduce Parse allocations 50% with sync.Pool

Replace per-call []byte allocation with a pooled buffer.

goos: linux / goarch: amd64 / cpu: AMD Ryzen 9 5950X
          │    old     │              new               │
          │  sec/op    │  sec/op     vs base            │
Parse-32    4.592µ ± 2%  3.041µ ± 1%  -33.78% (p=0.000 n=10)

          │   old    │             new              │
          │   B/op   │   B/op     vs base           │
Parse-32   1.024Ki ± 0%  0.512Ki ± 0%  -50.00% (p=0.000 n=10)

          │ old  │            new             │
          │ allocs/op │ allocs/op  vs base    │
Parse-32   12.00 ± 0%   6.000 ± 0%  -50.00% (p=0.000 n=10)

Rules:

  • Only include benchmarks directly affected by the change — strip unrelated rows

  • Never paste results with ~ (no statistical significance) — the improvement cannot be claimed

  • Include the hardware context line (goos/goarch/cpu) so results are reproducible

  • Use perf(scope): commit type for performance-only changes

Profiling from Benchmarks

Generate profiles directly from benchmark runs — no HTTP server needed:

# CPU profile
go test -bench=BenchmarkParse -cpuprofile=cpu.prof ./pkg/parser
go tool pprof cpu.prof

# Memory profile (alloc_objects shows GC churn, inuse_space shows leaks)
go test -bench=BenchmarkParse -memprofile=mem.prof ./pkg/parser
go tool pprof -alloc_objects mem.prof

# Execution trace
go test -bench=BenchmarkParse -trace=trace.out ./pkg/parser
go tool trace trace.out

For full pprof CLI reference (all commands, non-interactive mode, profile interpretation), see pprof Reference. For execution trace interpretation, see Trace Reference. For statistical comparison, see benchstat Reference.

Reference Files

  • pprof Reference — Interactive and non-interactive analysis of CPU, memory, and goroutine profiles. Full CLI commands, profile types (CPU vs allocobjects vs inuse_space), web UI navigation, and interpretation patterns. Use this to dive deep into _where time and memory are being spent in your code.

  • benchstat Reference — Statistical comparison of benchmark runs with rigorous confidence intervals and p-value tests. Covers output reading, filtering old benchmarks, interleaving results for visual clarity, and regression detection. Use this when you need to prove a change made a meaningful performance difference, not just a lucky run.

  • Trace Reference — Execution tracer for understanding when and why code runs. Visualizes goroutine scheduling, garbage collection phases, network blocking, and custom span annotations. Use this when pprof (which shows where CPU goes) isn't enough — you need to see the timeline of what happened.

  • Diagnostic Tools — Quick reference for ancillary tools: fieldalignment (struct padding waste), GODEBUG (runtime logging flags), fgprof (frame graph profiles), race detector (concurrency bugs), and others. Use this when you have a specific symptom and need a focused diagnostic — don't reach for pprof if a simpler tool already answers your question.

  • Compiler Analysis — Low-level compiler optimization insights: escape analysis (when values move to the heap), inlining decisions (which function calls are eliminated), SSA dump (intermediate representation), and assembly output. Use this when benchmarks show allocations you didn't expect, or when you want to verify the compiler did what you intended.

  • CI Regression Detection — Automated performance regression gating in CI pipelines. Covers three tools (benchdiff for quick PR comparisons, cob for strict threshold-based gating, gobenchdata for long-term trend dashboards), noisy neighbor mitigation strategies (why cloud CI benchmarks vary 5-10% even on quiet machines), and self-hosted runner tuning to make benchmarks reproducible. Use this when you want to ensure pull requests don't silently slow down your codebase — detecting regressions early prevents shipping performance debt.

  • Investigation Session — Production performance troubleshooting workflow combining Prometheus runtime metrics (heap size, GC frequency, goroutine counts), PromQL queries to correlate metrics with code changes, runtime configuration flags (GODEBUG env vars to enable GC logging), and cost warnings (when you're hitting performance tax). Use this when production benchmarks look good but real traffic behaves differently.

  • Prometheus Go Metrics Reference — Complete listing of Go runtime metrics actually exposed as Prometheus metrics by prometheus/client_golang. Covers 30 default metrics, 40+ optional metrics (Go 1.17+), process metrics, and common PromQL queries. Distinguishes between runtime/metrics (Go internal data) and Prometheus metrics (what you scrape from /metrics). Use this when setting up monitoring dashboards or writing PromQL queries for production alerts.

Cross-References

  • → See samber/cc-skills-golang@golang-performance skill for optimization patterns to apply after measuring ("if X bottleneck, apply Y")

  • → See samber/cc-skills-golang@golang-troubleshooting skill for pprof setup on running services (enable, secure, capture), Delve debugger, GODEBUG flags, root cause methodology

  • → See samber/cc-skills-golang@golang-observability skill for everyday always-on monitoring, continuous profiling (Pyroscope), distributed tracing (OpenTelemetry)

  • → See samber/cc-skills-golang@golang-testing skill for general testing practices

  • → See samber/cc-skills@promql-cli skill for querying Prometheus runtime metrics in production to validate benchmark findings

Files

references/compiler-analysis.md

Compiler Analysis Reference

The Go compiler provides diagnostic flags that reveal optimization decisions — escape analysis, inlining, SSA intermediate representation, and generated assembly. These are essential for understanding why a function allocates or why the compiler won't inline it.

Use compiler diagnostics when pprof shows a hot function and you need to understand the compiler's decisions about that function. These tools are free (no runtime overhead) — they analyze at compile time.

Table of Contents

  • Escape Analysis

    • Commands

    • Reading the output

    • Common escape causes

  • Inlining Decisions

    • Commands

    • Reading the output

    • Common inlining blockers

  • SSA Dump

    • Commands

    • Reading ssa.html

  • Assembly Output

    • Commands

    • Reading assembly output

    • Comparing assembly before/after optimization

Escape Analysis

Escape analysis determines whether a variable can live on the stack (cheap — freed when the function returns) or must be allocated on the heap (expensive — requires GC). "Moved to heap" means the compiler decided the variable might outlive the function.

Commands
# Show escape decisions — one line per escaped variable
go build -gcflags="-m" ./... 2>&1 | grep "escapes to heap"
go build -gcflags="-m" ./... 2>&1 | grep "moved to heap"

# Verbose mode — shows the reason for each escape decision
go build -gcflags="-m -m" ./...

# Filter to a specific package
go build -gcflags="-m" ./pkg/parser 2>&1 | grep "escapes"

# Filter to a specific file
go build -gcflags="-m" ./pkg/parser/parse.go 2>&1

# Apply to all dependencies too (usually too noisy, but useful for debugging)
go build -gcflags="all=-m" ./...

# Combine with grep for a specific function
go build -gcflags="-m" ./pkg/parser 2>&1 | grep "Parse"

# Combine with grep to see what stays on the stack (does NOT escape)
go build -gcflags="-m" ./pkg/parser 2>&1 | grep "does not escape"
Reading the output
./pkg/parser/parse.go:15:6: can inline Parse
./pkg/parser/parse.go:42:13: &result escapes to heap
./pkg/parser/parse.go:42:13:   flow: ~r0 = &result:
./pkg/parser/parse.go:42:13:     from &result (address-of) at ./pkg/parser/parse.go:42:13
./pkg/parser/parse.go:42:13:     from return &result (return) at ./pkg/parser/parse.go:42:6

The -m -m (verbose) output shows the escape chain — why the compiler decided the variable escapes. In this example: result has its address taken (&result), and that pointer is returned, so result must survive beyond the function — it escapes to heap.

Common escape causes
CauseExampleWhy it escapes
Returning a pointer to a localreturn &resultThe local must outlive the function call — caller holds a reference
Interface boxingvar x any = myStructConcrete type stored in interface{} allocates a copy on the heap
Closure capturing a localgo func() { use(localVar) }()The goroutine may run after the enclosing function returns
Slice append beyond capacitys = append(s, item) when len == capTriggers a new backing array allocation on the heap
Passing pointer to unanalyzable functionjson.Marshal(&data)Compiler can't prove the pointer won't be retained across package boundary
Storing in a struct field that escapesobj.Field = &localIf obj is heap-allocated, anything it points to must also be on the heap
fmt.Sprintf and friendsfmt.Sprintf("%d", n)Arguments are boxed into any (interface boxing) + result string is heap-allocated
Sending pointer on channelch <- &dataChannel receiver may be a different goroutine with a different lifetime

Not all escapes are problems. Only investigate escapes in functions that pprof identifies as allocation-heavy. A function called once at startup can escape freely.

Inlining Decisions

Inlining replaces a function call with the function body at the call site. This eliminates call overhead and enables further optimizations (escape analysis improves, dead code elimination, constant folding). Functions that aren't inlined in hot paths may benefit from simplification.

Commands
# Show which functions CAN be inlined
go build -gcflags="-m" ./... 2>&1 | grep "can inline"

# Show which functions CANNOT be inlined (with the reason)
go build -gcflags="-m" ./... 2>&1 | grep "cannot inline"

# Show inlining decisions for a specific package
go build -gcflags="-m" ./pkg/handler 2>&1 | grep "inline"

# Show where inlining was actually applied (function was inlined into caller)
go build -gcflags="-m" ./... 2>&1 | grep "inlining call to"

# Verbose mode — shows the cost budget and why inlining was blocked
go build -gcflags="-m -m" ./... 2>&1 | grep "inline"

# Filter to a specific function
go build -gcflags="-m" ./pkg/handler 2>&1 | grep "HandleRequest"

# Show both inlining and escape analysis together (they interact)
go build -gcflags="-m" ./pkg/handler 2>&1 | grep -E "(inline|escape|moved to heap)"
Reading the output
./pkg/handler/handler.go:20:6: can inline validateInput
./pkg/handler/handler.go:35:6: cannot inline HandleRequest: function too complex: cost 120 exceeds budget 80
./pkg/handler/handler.go:42:19: inlining call to validateInput

The inline cost budget is approximately 80–82 AST nodes (as of Go 1.22+; has increased in later releases). Functions with higher cost (more AST nodes, complex control flow) are not inlined. Check the actual threshold with -gcflags="-m -m".

Common inlining blockers
BlockerWhy it prevents inliningMitigation
Function too complexBody cost exceeds budget (80)Split into smaller functions; extract the cold path
defer statementAdds cleanup code that complicates inliningRemove defer from tiny hot functions; call cleanup directly
recover() callForces stack frame preservationMove recover() to a wrapper function
go statementGoroutine launch has implicit complexityExtract goroutine body into a separate function
Type switch / interface method callDynamic dispatch can't be resolved at compile timeUse concrete types in hot paths
select statementComplex runtime interactionSimplify channel patterns in hot functions
Large function bodyMany statements add up in costBreak into smaller functions — the hot inner function may inline

Value receivers vs pointer receivers: Receiver choice can affect copying, aliasing, escape analysis, and inlining, but pointer receiver methods can inline too and value receivers do not guarantee inlining. Check real compiler decisions with -gcflags="-m -m".

SSA Dump

The SSA (Static Single Assignment) dump shows the compiler's intermediate representation after each optimization pass — dead code elimination, bounds check removal, constant folding, register allocation. Use this when you need to understand exactly what the compiler generates.

Commands
# Generate SSA dump for a specific function — creates ssa.html in current directory
GOSSAFUNC=Parse go build ./pkg/parser
# Open ssa.html in browser — shows each optimization pass side by side

# Generate for a method on a type
GOSSAFUNC='(*Parser).Parse' go build ./pkg/parser

# Generate for a function in a specific package (when names collide)
GOSSAFUNC=myapp/pkg/parser.Parse go build ./...

# Combine with a specific output directory
GOSSAFUNC=Parse GOSSADIR=/tmp/ssa go build ./pkg/parser
# Creates /tmp/ssa/ssa.html
Reading ssa.html

The HTML file shows the function's code at each compiler pass:

  1. Source — original Go code

  2. AST — abstract syntax tree

  3. Start — initial SSA form

  4. Opt — after optimization passes (dead code, constant prop, bounds check elimination)

  5. Lower — architecture-specific lowering

  6. Regalloc — after register allocation

  7. Genssa — final generated code

Click on a value in any pass to highlight it across all passes — see how the compiler transforms it. Red values were eliminated (dead code). Green values are new (introduced by a pass).

What to look for:

  • Bounds checks remaining — IsInBounds or IsSliceInBounds operations that weren't eliminated. Adding explicit bounds checks or using _ = s[n-1] hints can help

  • Dead code not eliminated — values computed but never used (should be eliminated; if not, check for side effects)

  • Constant folding — computations on constants should be resolved at compile time

  • Register spills — values moved to stack because not enough registers; indicates heavy register pressure

Assembly Output

View the actual machine code the compiler generates. Use for verifying SIMD instructions, bounds checks, register allocation, and micro-optimization decisions.

Commands
# Full assembly output for a package (very verbose)
go build -gcflags="-S" ./pkg/parser 2>&1 | head -200

# Assembly for a specific function (grep for the function name)
go build -gcflags="-S" ./pkg/parser 2>&1 | grep -A 50 '"".Parse'

# Assembly for all packages (including dependencies — very verbose)
go build -gcflags="all=-S" ./... 2>&1 | grep -A 50 'myapp/pkg/parser.Parse'

# Disassemble a compiled binary (alternative to -gcflags="-S")
go build -o myapp ./cmd/server
go tool objdump -s Parse myapp

# Disassemble with source interleaving
go tool objdump -S -s Parse myapp

# Disassemble a specific symbol
go tool objdump -s 'myapp/pkg/parser.Parse' myapp

# Disassemble a specific text range (by address)
go tool objdump -start 0x4a3b00 -end 0x4a3c00 myapp

# List all symbols in a binary
go tool nm myapp | grep Parse

# Cross-compile and inspect assembly for a different architecture
GOARCH=arm64 go build -gcflags="-S" ./pkg/parser 2>&1 | head -200
Reading assembly output
"".Parse STEXT size=240 args=0x18 locals=0x48
    0x0000 MOVQ (TLS), CX           ; goroutine stack check
    0x0009 LEAQ -64(SP), AX
    0x000e CMPQ AX, 16(CX)          ; stack overflow check
    0x0012 JLS  228                  ; jump to stack growth
    0x0018 SUBQ $72, SP             ; allocate stack frame
    0x001c MOVQ BP, 64(SP)          ; save base pointer
    0x0021 LEAQ 64(SP), BP          ; set new base pointer
    ; ... function body ...
    0x00e0 CALL runtime.makeslice(SB) ; heap allocation!

What to look for:

  • CALL runtime.makeslice or CALL runtime.newobject — heap allocations in the hot path

  • CALL runtime.growslice — slice capacity exceeded, triggering copy

  • PCDATA / FUNCDATA — GC metadata (ignore for performance analysis)

  • Bounds check sequences: CMPQ + JCC before array/slice access — can sometimes be eliminated

  • SIMD instructions: VMOVDQU, VPSHUFB, VPADDB, etc. — verify auto-vectorization or manual SIMD

  • CALL runtime.morestack_noctxt — stack growth (normal, but frequent calls indicate deep recursion)

Comparing assembly before/after optimization
# Before your change
go build -gcflags="-S" ./pkg/parser 2>&1 > asm-before.txt

# After your change
go build -gcflags="-S" ./pkg/parser 2>&1 > asm-after.txt

# Diff the assembly
diff asm-before.txt asm-after.txt

Requirements and compatibility

Written for: Claude Code, OpenAI Codex

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Declares allowed tools, Claude Code frontmatter

The author says: Designed for Claude Code, Codex or similar harness, and for projects using Golang.

Security

What our scanner noticed· Low risk

  • Instructions that use the network

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
samber
Publisher
Samuel Berthe (Community)
Distributed by
Samuel Berthe
Source
samber/cc-skills-golang · skills/golang-benchmark · commit bb1d43d
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by samber or Samuel Berthe.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download golang-benchmark.zip