Vizb
A CLI tool that transforms Go benchmark raw output into interactive 4D visualizations. It allows you to merge multiple benchmark data, apply advanced grouping logic, and explore performance across four dimensions: Source, Group, and two customizable axes (X and Y). Available GitHub Action for seamless CI pipeline integration — all within a single deployable HTML file.
Features
- Modern Interactive UI: Robust Vue.js application with a smooth and responsive experience.
- Multi-Chart: Supports multiple charts (
bar,lineandpie) in a single place. - Sorting: Sort data (
asc/desc) for comparison through UI settings or CLI flags. - Swap Axis: Swap the
n,xandyaxes for diverse comparison through UI settings. - Logarithmic Scale: Use
--scale logfor bar and line charts to better visualize benchmarks with high variance in values. - Multi-Dimensional Grouping: Merge multiple benchmark data for deep comparative analysis.
- Tag-Based Merging: Tag benchmarks with commit hashes or version labels to compare performance across releases with automatic data merging.
- Flexible Input: Automatically processes raw
go test -benchoutput and the standard JSON output ofgo test -bench -json. - Comprehensive Metrics: Compare time, memory, and numbers with customizable units.
- Smart Grouping: Extract grouping logic from benchmark names using regex and group patterns.
- Filtering: Filter benchmarks to include only those matching a regex pattern.
- Export Options: Generate
single-fileHTML/JSON and options to save charts asJPEG. - GitHub Action: First-class CI support — run benchmarks, tag releases, merge history, and deploy visualizations directly from your workflows with a single composite action.
Installation
Go Toolchain
go install github.com/goptics/vizb@latest
Download Binary
Pre-built binaries for Linux, macOS, and Windows are available on the releases page.
Basic Usage
Using raw benchmark output
Run your Go benchmarks and save the output:
go test -bench . > bench.txt
Generate charts from the benchmark:
vizb bench.txt -o output.html
Direct piping
Pipe benchmark results directly to vizb:
# Raw output
go test -bench . | vizb -o output.html
# JSON output (automatically detected and converted)
go test -bench . -json | vizb -o output.html
Using vizb standard JSON benchmark output
vizb bench.txt -o output.json
Generate charts from the standard JSON benchmark data:
vizb output.json -o output.html
Using logarithmic scale
For benchmarks with high variance in values (e.g., 1 to 1,000,000), use the logarithmic Y-axis scale:
vizb bench.txt -o output.html --scale log
The --scale flag accepts linear (default) or log. It works with bar and line charts; pie charts and 1D data automatically use linear scale.
Merging multiple benchmarks
You can combine multiple benchmark JSON files using the merge command. This is useful for aggregating benchmark data from different runs, machines, or environments. The merge command always outputs JSON — use vizb html to render the result as an interactive HTML chart.
# Merge specific files into JSON
vizb merge output.json output2.json -o merged.json
# Generate HTML from merged JSON
vizb html merged.json -o merged_report.html
# Merge all JSON files in a directory
vizb merge ./results/ -o all.json
# Mix and match files and directories
vizb merge ./old_results/ output.json -o comparison.json
Open the generated HTML file in your browser to view the interactive charts.
[!Note] The
mergecommand requires JSON files as input, which must be generated usingvizb bench.txt -o output.json.
Tag-Based Merging
Vizb supports tagging benchmarks to compare performance across multiple commits, releases, or environment variants. The --tag flag on the main command assigns a label (e.g., commit hash, version number) to a benchmark run. When merging, vizb groups benchmarks by name and deep-merges those sharing the same name but different tags into a single object, preserving all timestamps, history, and data.
Tagging a benchmark run
vizb bench-v1.txt -o v1.json --tag v1 -n "Foo"
vizb bench-v2.txt -o v2.json --tag v2 -n "Foo"
How tag-based merging works
When you merge benchmarks sharing the same name with different tags:
vizb merge v1.json v2.json -o comparison.json
vizb html comparison.json -o comparison.html
Vizb groups benchmarks by name and processes each group as follows:
- Deduplication: If two entries share the same name and tag, only the one with the latest timestamp is kept. Older entries are discarded.
- Inner merge: Entries with different tags are deep-merged into a single benchmark. Data points are sorted in chronological tag order and each is annotated with its originating tag.
- Legacy entries: Untagged benchmarks (no
--tag) with the same name are deduplicated (first-seen wins) and their data is prepended before tagged entries. - Output: The merged benchmark retains the latest tag (by timestamp), carries a history of older tags, and includes data from all runs.
Controlling where the tag is injected
By default, the tag is injected into the name dimension of each inner data object. Use --tag-axis (shorthand -A) to target xAxis or yAxis instead:
# Inject tag into xAxis so the X-axis labels show version differences
vizb merge v1.json v2.json -A x -o comparison.json
vizb html comparison.json -o comparison.html
Accepted values: n (name), x (xAxis), y (yAxis). Default is n.
Advance Usage
How vizb groups your benchmark data
Vizb creates charts that make sense by putting your benchmark data into logical groupings and axes. It sees the data as 1D (xAxis) by default, but if you have to deal with 2D or 3D data, you can use the --group-pattern and --group-regex flags to group your data.
Understanding Group Patterns
A group pattern tells vizb how to dissect your benchmark names into three key components:
- Name (n): The family or group the benchmark belongs to. Benchmarks with the same
Namewill be grouped together in the same chart. (optional) - XAxis (x): The category that goes on the X-axis (e.g., input size, concurrency level).
- YAxis (y): The specific test case or variation (e.g., algorithm name, sub-test).
Visualizing the Extraction
Imagine you have a benchmark named BenchmarkSort/100/Ints, which has 3D data.
If you use the pattern name/xAxis/yAxis (or n/x/y), vizb splits the name wherever it finds a /:
Benchmark Name: BenchmarkSort / 100 / Ints
│ │ │
Pattern: [Name] [XAxis] [YAxis]
│ │ │
Result: "Sort" "100" "Ints"
Group Pattern Syntax (--group-pattern)
- Components: Use
name,xAxis,yAxis(or shorthandsn,x,y). - Separators: Use
/(slash) or_(underscore) to match the separators in your benchmark names. - Skipping parts: You can leave parts empty in the pattern to ignore sections of the benchmark name.
Standard Go Benchmarks (Slash Separated)
Format: Benchmark<Group>/<InputSize>/<Variant>
Pattern: n/x/y
| Benchmark Name | Extracted Data |
|---|---|
BenchmarkSort/1024/QuickSort |
Name: Sort XAxis: 1024 YAxis: QuickSort |
BenchmarkSort/1024/MergeSort |
Name: Sort XAxis: 1024 YAxis: MergeSort |
Underscore Separated
Format: Benchmark<Group>_<Variant>_<InputSize>
Pattern: n_y_x
| Benchmark Name | Extracted Data |
|---|---|
BenchmarkHash_SHA256_1KB |
Name: Hash YAxis: SHA256 XAxis: 1KB |
BenchmarkHash_MD5_1KB |
Name: Hash YAxis: MD5 XAxis: 1KB |
Simple Grouping (No X-Axis)
Format: Benchmark<Group>/<Variant>
Pattern: n/y
| Benchmark Name | Extracted Data |
|---|---|
BenchmarkJSON/Marshal |
Name: JSON XAxis: (empty) YAxis: Marshal |
BenchmarkJSON/Unmarshal |
Name: JSON XAxis: (empty) YAxis: Unmarshal |
Ignoring Prefixes
Sometimes you might want to ignore a common prefix or a specific part of the name.
Pattern: /n/y (Starts with a separator to skip the first part)
| Benchmark Name | Extracted Data |
|---|---|
BenchmarkTest/JSON/Marshal |
Name: JSON YAxis: Marshal (First part "Test" is ignored) |
Group Regex Syntax (--group-regex)
For more complex benchmark names where simple patterns aren't enough, you can use Regular Expressions with named groups.
- Named Groups: Use
(?<name>...),(?<xAxis>...),(?<yAxis>...)(or shorthands(?<n>...),(?<x>...),(?<y>...)) to capture parts of the benchmark name. - Flexibility: Regex allows you to match specific characters, ignore parts, and handle irregular formats.
Examples
| Benchmark Name | Regex | Extracted Data | Dimensions |
|---|---|---|---|
BenchmarkHashing64MD5 |
Hashing64(?<x>.*) |
XAxis: MD5 |
1D |
BenchmarkJSONByMarshal |
(?<x>.*)By(?<y>.*) |
XAxis: JSON YAxis: Marshal |
2D |
BenchmarkDecode/text=digits/level=speed |
(?<n>.*)/text=(?<x>.*)/level=(?<y>.*) |
Name: Decode XAxis: digits YAxis: speed |
3D |
[!Note] You must specify at least one of the
xandyaxes when you use the--group-[pattern|regex]command. thenis optional.
GitHub Action
Vizb provides a composite GitHub Action to run benchmarks and generate visualizations in CI.
Run bench and generate HTML
# Need go since the composite uses the raw binary
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
- uses: goptics/vizb@v0
with:
bench-cmd: "go test -bench=."
output-html: pages/index.html
Tracking Performance Across Releases
Tag benchmarks with release versions, merge historical data, and deploy charts:
on:
push:
tags: ['v*']
jobs:
bench:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: Download previous benchmark data
uses: dawidd6/action-download-artifact@v21
continue-on-error: true
with:
workflow: bench.yml
name: merged.json
path: prev
- uses: goptics/vizb@v0
with:
bench-cmd: "go test -bench=."
tag: ${{ github.ref_name }}
merge-dir: prev
tag-axis: x
output-json: merged.json # passing previous json file if exist
output-html: pages/index.html
- uses: actions/upload-artifact@v4
with:
name: merged.json
path: merged.json
- uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: pages
[!Note] The
tag-axisinput controls which data dimension receives the tag annotation. Usexto show versions on the X-axis for clean progressive comparison.
Development
This project uses Task for managing development workflows.
Setup Development Environment
# Install Task runner
go install github.com/go-task/task/v3/cmd/task@latest
Available Tasks
# install dependencies
task init
# Run the UI in development mode
task dev:ui
# Build The UI
task build:ui
# Build the binary (run from ./bin/vizb)
task build:cli
# Build everything
task build
# Run tests
task test
Contributing
Contributions are welcome! Feel free to open issues or submit pull requests.
License
This project is licensed under the MIT License - see the LICENSE file for details.