Command-line microbenchmarks for BLAS routines: one small executable per routine, the same options for all of them, and results in text, CSV or JSON — osu-micro-benchmarks, but for BLAS instead of MPI.
Build it against OpenBLAS, BLIS, Netlib reference BLAS, NVPL, ArmPL or Intel MKL — or once against FlexiBLAS, which picks the library at run time — run the same commands on each, and compare them on one page of charts.
You need a C compiler (GCC ≥ 12) and a BLAS library — at minimum OpenBLAS
(libopenblas-dev on Debian/Ubuntu). Take
blas-microbenchmark-<version>.tar.gz from the
latest release:
tar xf blas-microbenchmark-<version>.tar.gz
cd blas-microbenchmark-<version>
./configure # --prefix=DIR to install elsewhere than /usr/local
make
make check
make installTo check the download came from this repository's release workflow, untouched (needs the GitHub CLI):
gh attestation verify blas-microbenchmark-<version>.tar.gz --repo MathieuCAISSA/blas-microbenchmarkFrom a git clone, run ./autogen.sh first (it needs autoconf, automake
and libtool); GitHub's "Source code" archives are git clones too.
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
by name:
BMB=/usr/local/libexec/blas-microbenchmark
export PATH="$BMB/level1:$BMB/level2:$BMB/level3:$PATH"On a cluster, configure finds a BLAS loaded with module load through
the variables the module sets (OPENBLAS_ROOT, BLIS_INCDIR,
ARMPL_LIBDIR, …); otherwise point at it with --with-blas-incpath=DIR
and --with-blas-libpath=DIR.
With Spack, which picks the BLAS (^openblas, ^blis, ^netlib-lapack,
^flexiblas, ^nvpl-blas, ^armpl-gcc, ^intel-oneapi-mkl):
spack repo add https://github.com/MathieuCAISSA/blas-microbenchmark.git
spack install blas-microbenchmark ^openblas
spack load blas-microbenchmark$ bmb_dgemm -m 512:2048
# blas-microbenchmark 1.4.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-08T15:11:27Z
# routine: dgemm
Thread count Matrix dim1 (M=K) Matrix dim2 (N) time [s] GFLOP/s
1 512 512 0.005897026 45.520
1 1024 1024 0.045677359 47.014
1 2048 2048 0.370463460 46.374
There are 32 benchmarks, bmb_<routine>, covering levels 1 to 3:
dasum daxpy dcopy ddot dnrm2 dscal dswap, dgemv dger
dsymv dsyr dsyr2 dtrmv dtrsv, dgemm dsymm dsyrk dsyr2k
dtrmm dtrsm in double precision; saxpy sdot sgemv sgemm
strsm ssyrk in single; cgemm zgemm ztrsm in complex, and the
complex-only zdotc zherk zhemm. They all take the same options: sizes to sweep
(-v, -m, -M), thread counts (-t), a file to save to (-o). Each
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
(-C skips the check).
bmb_dgemm --help lists them, and
man blas-microbenchmark explains everything: sweeps, how a number is
measured, threads and NUMA, the output formats.
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.htmlThe page is a single self-contained file — nothing is fetched, so it opens
without a network and can be sent as is. It shows performance against
size with the caches marked, each library compared with OpenBLAS, thread
scaling, a heatmap for sweeps over both dimensions, and the raw data.
Run each command several times, into separate files, and it shows how
far the runs spread and tells which differences are beyond that noise;
man bmb_report has the details.
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.
Chosen when building, and each one built and tested in CI:
| Backend | configure flag |
|---|---|
| OpenBLAS (default) | (none) |
| BLIS | --with-blas-backend=blis |
| Netlib reference | --with-blas-backend=netlib |
| NVPL (aarch64) | --with-blas-backend=nvpl |
| ArmPL (aarch64) | --with-blas-backend=armpl |
| FlexiBLAS | --with-blas-backend=flexiblas |
| Intel MKL | --with-blas-backend=mkl |
With FlexiBLAS, one build measures every library it can load:
FLEXIBLAS=BLIS-OPENMP bmb_dgemm …, and each comes out as its own
series in the report. Fedora packages it; Debian and Ubuntu do not.
The manual pages, also online at mathieucaissa.github.io/blas-microbenchmark:
man blas-microbenchmark(alsoman bmb_dgemm, and so on) — the benchmarks.man bmb_report— the report.- What they produce: the table, CSV and JSON of a run, and the report's summary, charts, repeated runs and raw data.
- Before installing, from the build directory:
man -l man/blas-microbenchmark.1. - Development: every test and what CI runs.
- CHANGELOG.md — what changed in each release.
- The wiki: results measured on real machines, with their files, and a FAQ.
- The roadmap: what is planned, in progress and done.
- CONTRIBUTING.md, then AGENTS.md and the files in doc/dev/ it points to — for contributors: building from git, the tests, adding a routine, CI, cutting a release.
If you use it in published work, please cite it: GitHub's Cite this repository button gives the reference, from CITATION.cff.