https://github.com/goptics/vizb
A 4D visualizer for go benchmarks from your local to CI/CD pipeline
https://github.com/goptics/vizb
benchmark benchmarking chart ci-cd cli github-actions go golang golang-benchmark golang-tools visualizer
Last synced: 30 days ago
JSON representation
A 4D visualizer for go benchmarks from your local to CI/CD pipeline
- Host: GitHub
- URL: https://github.com/goptics/vizb
- Owner: goptics
- License: mit
- Created: 2025-06-17T12:53:37.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-05-21T14:09:47.000Z (about 1 month ago)
- Last Synced: 2026-05-21T14:32:18.031Z (about 1 month ago)
- Topics: benchmark, benchmarking, chart, ci-cd, cli, github-actions, go, golang, golang-benchmark, golang-tools, visualizer
- Language: Go
- Homepage: https://goptics.github.io/vizb
- Size: 4.22 MB
- Stars: 69
- Watchers: 1
- Forks: 6
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-go - vizb - A CLI tool to visualize Go benchmark data in 4D. (Benchmarks / Other Software)
- fucking-awesome-go - vizb - A CLI tool to visualize Go benchmark data in 4D. (Benchmarks / Other Software)
- awesome-go-with-stars - vizb - 03-09 | (Benchmarks / Other Software)
README
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`, `line` and `pie`) in a single place.
- **Sorting**: Sort data (`asc`/`desc`) for comparison through UI settings or CLI flags.
- **Swap Axis**: Swap the `n`, `x` and `y` axes for diverse comparison through UI settings.
- **Logarithmic Scale**: Use `--scale log` for 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 -bench` output and the standard JSON output of `go 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-file` HTML/JSON and options to save charts as `JPEG`.
- **GitHub Action**: First-class CI support — run benchmarks, tag releases, merge history, and deploy visualizations directly from your workflows with a single composite action.
- **Release Guard**: Manual approval gate — push a tag, review in the Actions UI, and approve before GoReleaser publishes.
## Installation
### Go Toolchain
```bash
go install github.com/goptics/vizb@latest
```
### Download Binary
Pre-built binaries for Linux, macOS, and Windows are available on the [releases page](https://github.com/goptics/vizb/releases).
## Basic Usage
### Using raw benchmark output
Run your Go benchmarks and save the output:
```bash
go test -bench . > bench.txt
```
Generate charts from the benchmark:
```bash
vizb bench.txt -o output.html
```
### Direct piping
Pipe benchmark results directly to vizb:
```bash
# 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
```bash
vizb bench.txt -o output.json
```
Generate charts from the standard JSON benchmark data:
```bash
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:
```bash
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.
```bash
# 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 `merge` command requires JSON files as input, which must be generated using `vizb 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
```bash
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:
```bash
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:
1. **Deduplication**: If two entries share the same name and tag, only the one with the latest timestamp is kept. Older entries are discarded.
2. **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.
3. **Legacy entries**: Untagged benchmarks (no `--tag`) with the same name are deduplicated (first-seen wins) and their data is prepended before tagged entries.
4. **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:
```bash
# 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:
1. **Name (n)**: The family or group the benchmark belongs to. Benchmarks with the same `Name` will be grouped together in the same chart. (optional)
2. **XAxis (x)**: The category that goes on the X-axis (e.g., input size, concurrency level).
3. **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 `/`:
```text
Benchmark Name: BenchmarkSort / 100 / Ints
│ │ │
Pattern: [Name] [XAxis] [YAxis]
│ │ │
Result: "Sort" "100" "Ints"
```
### Group Pattern Syntax (`--group-pattern`)
- **Components**: Use `name`, `xAxis`, `yAxis` (or shorthands `n`, `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//`
**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__`
**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/`
**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 `(?...)`, `(?...)`, `(?...)` (or shorthands `(?...)`, `(?...)`, `(?...)`) 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(?.*)` | **XAxis:** `MD5` | 1D |
| `BenchmarkJSONByMarshal` | `(?.*)By(?.*)` | **XAxis:** `JSON` **YAxis:** `Marshal` | 2D |
| `BenchmarkDecode/text=digits/level=speed` | `(?.*)/text=(?.*)/level=(?.*)` | **Name:** `Decode` **XAxis:** `digits` **YAxis:** `speed` | 3D |
> [!Note]
> You must specify at least one of the `x` and `y` axes when you use the `--group-[pattern|regex]` command. the `n` is optional.
## GitHub Action
Vizb provides a composite GitHub Action to run benchmarks and generate visualizations in CI.
### Basic Usage
```yaml
- 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:
```yaml
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
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-axis` input controls which data dimension receives the tag annotation. Use `x` to show versions on the X-axis for clean progressive comparison.
## Development
This project uses [Task](https://taskfile.dev/) for managing development workflows.
### Setup Development Environment
```bash
# Install Task runner
go install github.com/go-task/task/v3/cmd/task@latest
```
### Available Tasks
```bash
# 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.