1. Install the upload CLI
Install perfall-cli once from PyPI on the machine that will publish benchmark results.
pip install perfall-cli
Documentation
Perfall accepts benchmark artifacts from seven supported adapters. Install
perfall-cli from PyPI once, generate the artifact for your stack,
and upload it with your project API key.
Install perfall-cli once from PyPI on the machine that will publish benchmark results.
pip install perfall-cli
Open the Projects page, create a project, and reveal the API key when you are ready to wire your benchmark job.
Pick the framework below that matches your stack and run its export command to create a JSON or JSONL artifact.
Run perfall ingest <adapter> with the artifact path and your project API key, then return after the next run to compare trends.
Want to confirm the CLI, API key, and dashboard path before wiring a real benchmark suite? Download the sample pytest-benchmark artifact and upload it with your project API key.
perfall ingest pytest-benchmark \
--file pytest-benchmark-sample.json \
--api-key "$PERFALL_API_KEY"
Python
Use pytest-benchmark's JSON export when your benchmark suite already lives in pytest.
def test_sort(benchmark):
values = [3, 1, 2]
benchmark(sorted, values)
pytest --benchmark-only --benchmark-json benchmark.json
perfall ingest pytest-benchmark --file benchmark.json --api-key "$PERFALL_API_KEY"
Go
Use Go's built-in benchmark support and upload the JSON event stream from `go test -bench`.
func BenchmarkSort(b *testing.B) {
for i := 0; i < b.N; i++ {
values := []int{3, 1, 2}
sort.Ints(values)
}
}
go test -bench . -benchmem -json ./... > go-benchmark.jsonl
perfall ingest go-test --file go-benchmark.jsonl --api-key "$PERFALL_API_KEY"
Java
Use JMH when you need stable JVM benchmark output and export the run as JSON.
@State(Scope.Thread)
public class SortBenchmark {
@Benchmark
public int[] sort() {
int[] values = {3, 1, 2};
Arrays.sort(values);
return values;
}
}
java -jar benchmarks.jar -rf json -rff jmh-result.json
perfall ingest jmh --file jmh-result.json --api-key "$PERFALL_API_KEY"
Rust
Use Criterion.rs with cargo-criterion when you want a machine-readable JSONL stream.
fn sort_benchmark(c: &mut Criterion) {
c.bench_function("sort_u64", |b| {
b.iter(|| {
let mut values = vec![3_u64, 1, 2];
values.sort();
})
});
}
cargo criterion --message-format=json > cargo-criterion.jsonl
perfall ingest criterion --file cargo-criterion.jsonl --api-key "$PERFALL_API_KEY"
JavaScript / TypeScript
Use Vitest benchmark mode when you want benchmark cases alongside your existing JS or TS tests.
import { bench, describe } from 'vitest';
describe('sort', () => {
bench('sort numbers', () => {
[3, 1, 2].sort();
});
});
npx vitest bench --outputJson vitest-benchmark.json
perfall ingest vitest --file vitest-benchmark.json --api-key "$PERFALL_API_KEY"
C++
Use Google Benchmark JSON output when your native benchmark suite already builds a benchmark binary.
static void BM_Sort(benchmark::State& state) {
for (auto _ : state) {
std::array<int, 3> values{3, 1, 2};
std::sort(values.begin(), values.end());
}
}
BENCHMARK(BM_Sort);
BENCHMARK_MAIN();
./benchmarks --benchmark_out=google-benchmark.json --benchmark_out_format=json
perfall ingest google-benchmark --file google-benchmark.json --api-key "$PERFALL_API_KEY"
.NET
Use BenchmarkDotNet with a JSON exporter when you want structured benchmark output from a .NET project.
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Exporters.Json;
[JsonExporterAttribute.Brief]
public class MyBenchmarks
{
[Benchmark]
public void Sort()
{
var values = new[] { 3, 1, 2 };
Array.Sort(values);
}
}
dotnet run -c Release --project benchmarks.csproj
perfall ingest benchmarkdotnet --file BenchmarkDotNet.Artifacts/results/MyBenchmarks-report-brief.json --api-key "$PERFALL_API_KEY"
CI regression gate
Perfall can upload the current run, compare it with the latest baseline-branch sample for each smaller-is-better metric, print a concise summary, and exit non-zero when a regression exceeds your configured percentage.
perfall ingest pytest-benchmark \
--file benchmark.json \
--api-key "$PERFALL_API_KEY" \
--baseline-branch main \
--fail-on-regression-percent 5
name: Perfall benchmark gate
on:
push:
branches: [main]
pull_request:
jobs:
benchmarks:
runs-on: ubuntu-latest
env:
PERFALL_API_KEY: ${{ secrets.PERFALL_API_KEY }}
PERFALL_URL: ${{ vars.PERFALL_URL }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: |
python -m pip install --upgrade pip
python -m pip install perfall-cli pytest pytest-benchmark
pytest --benchmark-only --benchmark-json benchmark.json
- run: |
command=(
perfall ingest pytest-benchmark
--file benchmark.json
--api-key "$PERFALL_API_KEY"
)
if [ -n "${PERFALL_URL:-}" ]; then
command+=(--perfall-url "$PERFALL_URL")
fi
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
command+=(
--baseline-branch "${{ github.event.pull_request.base.ref }}"
--fail-on-regression-percent 5
)
fi
"${command[@]}"
PERFALL_API_KEY. Optional repository variable: PERFALL_URL when you need to target a non-default Perfall deployment.perfall-cli from PyPI directly and does not depend on any repo-local GitHub Action files.baseline-branch to the PR base branch, such as GitHub Actions github.event.pull_request.base.ref.ops/s are skipped by this MVP gate.The CLI is the recommended path, but direct integrations can POST normalized JSON to the ingest API when they need more control.
POST https://perfall.it/ingest/v1/samples
{
"api_key": "project-api-key",
"run": {
"tool": "pytest-benchmark",
"branch": "main"
},
"samples": [
{
"identifier": "bench.sort.mean",
"value": 10.4,
"timestamp": "2026-03-19T05:30:00+00:00"
}
]
}
api_key and at least one samples[] entry.identifier and a numeric value.status, project_id, accepted_samples, and identifiers.account_daily_quota_exceeded.POST https://perfall.it/ingest/submit.Create an account, create a project, and copy its API key from the Projects page before running the upload command for your framework.