Running and Submitting Benchmarks

The performance tables in The CUDA Handbook were measured on old hardware: GeForce GTX 280, Tesla M2050, and GRID K520. The numbers are still instructive, but difficult to reproduce today, even if such benchmark results were deemed interesting enough to reproduce. One of the benefits of lofting The CUDA Handbook text into the website is that we can make the repository of benchmarks more of a living document: by enabling readers to submit their own results, measured on their own current hardware, for eventual publication on the website.

This page explains who may submit results, what the harness measures, and how to build, run, and submit it.

Important

Benchmarking is a notoriously difficult process to administer fairly, and this feature is being added to the website for pedagogical purposes, to drive engagement, and to inject a bit of fun. It is a non-goal to become some sort of arbiter of performance reporting. If that ever changes, it will be done explicitly and under auspices distinct from The CUDA Handbook, which is first and foremost an educational property.

Who may submit

Submitting results is a perk of membership. An active CUDA Handbook membership qualifies, as does a paid subscription to The Parallel Programmer on Substack; both are honored through the same entitlement, and a new Substack subscription becomes eligible within a day. The membership requirement is not a paywall on the data, which is public. It exists so that every submission is attached to an accountable identity, which is what makes a review-based pipeline workable.

Beyond membership, a submission must meet four conditions.

Run on an otherwise idle machine. A benchmark that shares its GPU with a compositor, a compile job, or another CUDA process measures the contention, not the hardware.

Build from a clean tree. The submission records the commit it was built from, and a modified working tree makes that commit an incomplete description of the code that ran. A dirty tree does not disqualify a run, but is flagged for the reviewer.

Submit what the harness produced. Results are validated against the raw log they came from: every reported number is re-derived from the program output by the same parsers that produced it, and a number that does not re-derive is rejected. The idea is to defend against submitters editing a results file by hand.

Report the hardware the run used. The harness records a hardware fingerprint automatically (see below). Submissions whose measurements are impossible for the hardware they claim—bandwidth above the memory system's peak, arithmetic above the card's FP32 throughput, a kernel launch faster than any launch can be—may be rejected.

What the harness measures

For now, we have six (6) suites, in two (2) groups. Each suite corresponds to material in the book, and the results appear on that suite's page.

Suite Chapter Metrics What it measures
histogram 16 15 Every histogram implementation in the chapter, swept from 256 possible input values down to 1 (the contention curve of Tables 16-3 and 16-4)
nbody 14 12 Each N-body kernel, CPU and GPU, in billions of body-body interactions per second
global 5 3 Peak global memory read, write, and copy bandwidth by operand size
memcpy 6 8 Pinned and pageable transfer bandwidth, null-transfer latency, and the small-transfer breakeven sweeps of Figures 6-4 and 6-5
launch 6 4 Kernel launch overhead, synchronous and asynchronous, and the cost of launching with managed memory resident
concurrency 6 6 The copy/kernel overlap shmoo of Figures 6-7 and 6-8

The canonical arguments are part of the contract: results are comparable across machines only because everyone runs the same workload. Run all six unless a suite fails to build; a partial submission is accepted, and the missing measurements are omitted from the tables.

Build

The benchmark programs are the book's sample code, built with CMake.

git clone https://github.com/ArchaeaSoftware/cudahandbook.git
cd cudahandbook
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j

Build the whole tree rather than individual targets. The harness locates each program in the build directory and skips the ones it cannot find, so a partial build silently produces a partial submission.

One target deserves specific mention: microbench/deviceProps reports the device properties that nvidia-smi does not expose—the SM count, memory bus width, L2 size, and copy-engine count. Those values are the fingerprint that the plausibility checks measure a submission against, so a run without them carries a reduced fingerprint and cannot be checked as thoroughly.

Requirements are a CUDA toolkit and driver recent enough for your GPU, Python 3.8 or later, and nvidia-smi on the path. No Python packages are needed.

Run

python3 bench/run.py --bin-dir build --suite all --device 0 \
    --name "Your Name" --github yourhandle \
    --out results/$(hostname)-$(date +%F).json

The harness detects the GPU, driver, CUDA version, CPU, and operating system, records the fingerprint, runs each suite, and writes two files: the results JSON and a .raw.txt log holding the verbatim output of every program it ran. Keep the two together; the log is the evidence behind the numbers, and the validator reads both.

--name and --github are how you are credited on the site. Omit them and the submission is published without attribution.

Useful variations: --suite microbench or --suite histogram,nbody to run a subset, --platform "aws g6e.xlarge" to record a cloud instance type, and --device N on a multi-GPU machine—run once per GPU, producing one submission per device.

Expect the full sweep to take tens of minutes. The global-memory and managed-memory sweeps dominate, since both walk a large parameter space; the launch, memcpy, and concurrency suites finish in a few minutes together.

Before submitting, check the run:

python3 bench/validate.py results/<your-file>.json

The validator reports two kinds of finding. Errors mean the submission is invalid: malformed, physically impossible for the hardware it claims, or inconsistent with its own raw log. Warnings are advisory—a value close enough to a hardware limit to be worth a second look, a dirty build tree, a missing fingerprint—and do not block submission, though the reviewer sees them. The same check runs again at review time, so a clean run here is the best predictor of a smooth submission.

Submit

python3 bench/submit.py results/<your-file>.json

or pass --submit to the original run.py command to submit as soon as the run finishes. The client asks for your membership email, sends a one-time 6-digit code to that address, and asks for the code; entering it uploads the results and the raw log. The code expires in fifteen minutes, and both the code request and the submission are rate-limited to five per day.

Your email verifies membership and nothing else. It is stored only as a hash, is never published, and is not recoverable from the review tooling. The public record carries the name and handle you chose, and the fingerprint deliberately excludes the GPU UUID and PCI bus address, which would identify a machine without making a single measurement more verifiable.

What happens next

Submissions are queued for review rather than published on arrival. Review re-runs the full validation, examines the raw log, and either approves the submission or rejects it with a reason. Turnaround should take, at most, a few days.

An approved submission is committed to the public repository under results/<gpu-slug>/, authored to you, and appears on the site at the next deployment:

  • as a row in that suite's tables, grouped with its architecture generation, showing the median across all submissions for the GPU together with the number of runs behind it and their range;
  • in the charts, where it can be compared against other GPUs running the same algorithm, or against the other algorithms running on the same GPU;
  • on a page of your own at /benchmarks/by/<handle>/, listing your systems and your numbers beside the site-wide medians;
  • in the hardware list on the benchmarks index, which describes each GPU by its fingerprint.

Results for a GPU that has been submitted before are aggregated with the existing ones rather than replacing them, so a second run of the same hardware tightens the median instead of overwriting it.

A rejected submission is archived with its reason rather than discarded, and rejection is usually a matter of a repeatable problem—a busy machine, a partial build, an edited file—rather than a verdict on the hardware. Fix the cause and submit again.

Finally, some of the book's own performance tables are generated from this data. Table 16-2 already is: its book-era rows are fixed, and its modern rows come from community submissions, so an approved result from a new GPU adds a row to the book itself.