How fast is each BLAS routine on this machine, with this library?
One small benchmark per routine, every result checked before it is timed,
and the libraries compared on one page of charts.
- 32 benchmarks, one executable per BLAS routine (
bmb_dgemm,bmb_ddot, …), levels 1 to 3, in single, double and complex precision. Think osu-micro-benchmarks, for BLAS instead of MPI. - Numbers you can trust: every point is checked against a reference before it is timed, so a library that computes the wrong thing stops the run instead of looking fast. The CPU, its frequency, the library and its version are recorded with every result.
- Eight BLAS libraries: OpenBLAS, BLIS, AMD AOCL-BLAS, Intel MKL, NVPL, ArmPL, Netlib, or all those FlexiBLAS can load, from one build.
- One page of charts,
bmb_report: performance against size with the caches marked, libraries side by side, thread scaling, and how far repeated runs spread. A single HTML file, which opens offline. - Made for HPC sites: a Spack package, a Docker image (Apptainer too), and ReFrame tests.
With a C compiler and a BLAS library (libopenblas-dev on Debian and
Ubuntu), take blas-microbenchmark-<version>.tar.gz from the
latest release, then:
tar xf blas-microbenchmark-<version>.tar.gz && cd blas-microbenchmark-<version>
./configure && make && make check && sudo make install
export PATH="/usr/local/libexec/blas-microbenchmark/level3:$PATH"
bmb_dgemm -m 512:2048$ bmb_dgemm -m 512:2048
# blas-microbenchmark 1.6.0
# backend: openblas (OpenBLAS 0.3.26 NO_LAPACKE DYNAMIC_ARCH NO_AFFINITY Haswell MAX_THREADS=64)
# verified: every point, against a reference, before it was timed
# layout: row-major
# cpu: Intel(R) Core(TM) Ultra 7 155U (14 logical CPUs, 1 NUMA node)
# caches: L1d 48K, L1i 64K, L2 2M, L3 12M
# os: Linux 6.6.87.1-microsoft-standard-WSL2 x86_64
# date: 2026-10-16T08:50:23Z
# routine: dgemm
Thread count Matrix dim1 (M=K) Matrix dim2 (N) time [s] GFLOP/s
1 512 512 0.005647207 47.534
1 1024 1024 0.035299474 60.836
1 2048 2048 0.286089708 60.051
Every benchmark takes the same options: the sizes to sweep (-v for
vectors, -m and -M for matrices), thread counts (-t 1:8), a file to
save to (-o results.json, or .csv). bmb_dgemm --help lists them;
man blas-microbenchmark explains everything else.
Run the same commands against each library, then make one page of them:
bmb_ddot -v 1024:16777216 -o results/ddot-openblas.json
bmb_dgemm -m 128:2048 -t 1:8 -o results/dgemm-openblas.json
bmb_dgemv -m 256:4096 -M 256:4096 -o results/dgemv-openblas.json
# ... the same three from a build against BLIS, as *-blis.json
bmb_report results/*.json > report.html
firefox report.html
The commands above, run on a laptop (Intel Core Ultra 7 155U, WSL2) against OpenBLAS 0.3.26 and BLIS 0.9.0: what the page draws, not a verdict on either library.
Run each command several times, into separate files, and the page also
shows how far the runs spread, and which differences are beyond that
noise. man bmb_report has the details.
| Level | Double | Single | Complex |
|---|---|---|---|
| 1 — vectors | dasum daxpy dcopy ddot dnrm2 dscal dswap |
saxpy sdot |
zdotc |
| 2 — matrix × vector | dgemv dger dsymv dsyr dsyr2 dtrmv dtrsv |
sgemv |
|
| 3 — matrix × matrix | dgemm dsymm dsyrk dsyr2k dtrmm dtrsm |
sgemm ssyrk strsm |
cgemm zgemm ztrsm zherk zhemm |
Each is bmb_<routine>. Level 1 and 2 report GFLOP/s and GB/s, level 3
GFLOP/s.
The Quick start above. make install puts bmb_report in
/usr/local/bin, the manual pages in /usr/local/share/man, and the
benchmarks by BLAS level under /usr/local/libexec/blas-microbenchmark,
not on the PATH; to run them all by name:
BMB=/usr/local/libexec/blas-microbenchmark
export PATH="$BMB/level1:$BMB/level2:$BMB/level3:$PATH"./configure --with-blas-backend=… picks the library (Backends).
On a cluster, it finds one loaded with module load (OPENBLAS_ROOT,
BLIS_INCDIR, …), or point at it with --with-blas-incpath=DIR and
--with-blas-libpath=DIR.
Check that the download is untouched
Each release tarball is attested by the workflow that built it. With the GitHub CLI:
gh attestation verify blas-microbenchmark-<version>.tar.gz --repo MathieuCAISSA/blas-microbenchmarkOr, from 1.3.0, with cosign and the
bundle attached to the release (signed by the release workflow, run for
the version's tag, or from main when a release's upload is run again):
cosign verify-blob-attestation --type slsaprovenance1 \
--bundle blas-microbenchmark-<version>.tar.gz.sigstore.json \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github\.com/MathieuCAISSA/blas-microbenchmark/\.github/workflows/release\.yml@refs/(tags/v|heads/main$)' \
blas-microbenchmark-<version>.tar.gzspack repo add https://github.com/MathieuCAISSA/blas-microbenchmark.git
spack install blas-microbenchmark ^openblas
spack load blas-microbenchmarkThe BLAS can be ^openblas, ^blis, ^amdblis, ^intel-oneapi-mkl,
^nvpl-blas, ^armpl-gcc, ^netlib-lapack or ^flexiblas.
From 1.6.0, each release's image is on ghcr.io, for x86_64, against
OpenBLAS (latest, <version>, <version>-openblas), BLIS
(<version>-blis) or Netlib (<version>-netlib). It writes to
/results, here the current directory:
IMAGE=ghcr.io/mathieucaissa/blas-microbenchmark:latest
gh attestation verify oci://$IMAGE --repo MathieuCAISSA/blas-microbenchmark
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/results" $IMAGE bmb_dgemm -m 64:1024 -o dgemm.json
apptainer exec docker://$IMAGE bmb_dgemm -m 64:1024 -o dgemm.jsonBuild the image yourself, with MKL, or for Apptainer
From a git clone, against OpenBLAS or the library BLAS_BACKEND names
(blis, netlib, or mkl, which is not published since it would
redistribute Intel's libraries):
docker build -f packaging/docker/Dockerfile --build-arg BLAS_BACKEND=openblas -t blas-microbenchmark .
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/results" blas-microbenchmark bmb_dgemm -m 64:1024 -o dgemm.jsonApptainer takes a built image too: save it where Docker is, then convert it where Apptainer is, which writes in the current directory as you:
docker save -o blas-microbenchmark.tar blas-microbenchmark
apptainer build blas-microbenchmark.sif docker-archive://blas-microbenchmark.tar
apptainer exec blas-microbenchmark.sif bmb_dgemm -m 64:1024 -o dgemm.jsonA container runs on the host's CPU, which is what the results record.
Docker's --cpus and --cpuset-cpus leave the benchmark fewer CPUs than
it sees, and -t beyond those gets a warning. Docker Desktop runs
containers in a virtual machine, whose own limits the numbers include.
Run ./autogen.sh first (it needs autoconf, automake and libtool), then
as from a release. GitHub's "Source code" archives are git exports too.
Chosen when building, and each one built and tested in CI:
| Library | configure flag |
Spack |
|---|---|---|
| OpenBLAS (default) | (none) | ^openblas |
| BLIS | --with-blas-backend=blis |
^blis |
| AMD AOCL-BLAS | --with-blas-backend=aocl |
^amdblis |
| Intel MKL | --with-blas-backend=mkl |
^intel-oneapi-mkl |
| NVPL (aarch64) | --with-blas-backend=nvpl |
^nvpl-blas |
| ArmPL (aarch64) | --with-blas-backend=armpl |
^armpl-gcc |
| Netlib reference | --with-blas-backend=netlib |
^netlib-lapack |
| FlexiBLAS | --with-blas-backend=flexiblas |
^flexiblas |
With FlexiBLAS, one build measures every library it can load
(FLEXIBLAS=BLIS-OPENMP bmb_dgemm …), each its own series in the report.
Fedora packages it; Debian and Ubuntu do not.
Sites that check their systems with ReFrame get every benchmark as a ReFrame test, installed with them: its result checked for sanity, its GFLOP/s and GB/s as performance variables, compared with the site's references.
R=/usr/local/share/blas-microbenchmark/reframe # with Spack: $(spack location -i blas-microbenchmark)/share/...
reframe -c $R/blas_microbenchmark.py -n bmb_run -r
reframe -c $R/blas_microbenchmark.py -n bmb_run -S level3_size=4096 -S reference_file=refs.json -r
bmb_report output/*/*/*/*/result.json > report.htmlSizes, threads, references, and building a release in each programming environment: packaging/reframe.
- The manual,
online or as
man blas-microbenchmarkandman bmb_report, with what a run produces (table, CSV, JSON, the report). Before installing:man -l man/blas-microbenchmark.1from the build directory. - The wiki: results measured on real machines, and a FAQ.
- CHANGELOG.md, and the roadmap.
- Contributing: CONTRIBUTING.md, then AGENTS.md and doc/dev/; every test and CI job is on the development page.
If you use it in published work, please cite it: GitHub's Cite this repository button gives the reference, from CITATION.cff. Released under the Apache License 2.0.