Benchmark suite

July 21, 2026 · View on GitHub

Primus ships microbenchmarks for GPU compute and distributed communication. They are exposed as the benchmark subcommand of the Primus CLI. Use them to validate a node or cluster before long training jobs.

Implementation: primus/cli/subcommands/benchmark.py (initializes distributed execution, runs the selected suite, then finalizes).

Related documentation: Preflight diagnostics (broader cluster checks), Memory and performance projection (training-scale estimates), Installation (environment setup).


Overview and command syntax

primus-cli [global-options] <mode> [mode-args] -- benchmark <suite> [suite-specific-args]
  • <mode> is typically direct, container, or slurm so that WORLD_SIZE, RANK, MASTER_ADDR, and related variables are set consistently.
  • benchmark runs inside the Primus Python CLI; the runner wires up the process environment the same way as training.

The CLI also registers an attention suite; the subsections below cover gemm, gemm-dense, gemm-deepseek, strided-allgather, and rccl.


Quick start

Single-node GEMM:

primus-cli direct -- benchmark gemm --M 4096 --N 4096 --K 4096 --dtype bf16 --duration 10

Multi-node RCCL on Slurm:

primus-cli slurm srun -N 4 -- benchmark rccl --op all_reduce --min-bytes 1M --max-bytes 128M

Suite reference

gemm

Single-shape general matrix multiply (GEMM) microbenchmark.

ArgumentDescription
--M, --N, --KMatrix dimensions (defaults: 4096 / 4096 / 4096).
--trans_aTranspose the A matrix.
--trans_bTranspose the B matrix.
--dtypebf16, fp16, fp32, or fp8 (fp8 requires torchao). Default: bf16.
--durationRun duration in seconds (default: 10).
--output-fileDestination for results (.md, .csv, .tsv, .jsonl, .jsonl.gz). Default: ./gemm_report.md. Use - or omit for Markdown on stdout.

Example

primus-cli direct -- benchmark gemm --M 8192 --N 8192 --K 8192 --dtype bf16 --duration 10 --output-file ./gemm_report.md

gemm-dense

Dense GEMM workload using Llama-like shape parameters (model-derived GEMMs).

ArgumentDescription
--modelOptional label (for example Llama3.1_8B).
--seqlenSequence length (default: 2048).
--hidden-sizeHidden size (default: 4096).
--intermediate-sizeFFN intermediate size (default: 11008).
--num-attention-headsAttention heads (default: 32).
--num-key-value-headsKV heads (default: 32).
--head-dimPer-head dimension (default: 128).
--vocab-sizeVocabulary size (default: 32000).
--dtypebf16, fp16, fp32, or fp8 (fp8 requires torchao). Default: bf16.
--mbsMicrobatch size (default: 1).
--durationSeconds per shape (default: 3).
--output-fileReport path (default: ./gemm-dense_report.md).

Example

primus-cli direct -- benchmark gemm-dense --model Llama3.1_8B --seqlen 4096 --dtype bf16

gemm-deepseek

Dense GEMM workload using DeepSeek-style shapes (MoE / MLA-related dimensions).

ArgumentDescription
--modelLabel (for example Deepseek_V2, Deepseek_V3).
--seqlenSequence length (default: 4096).
--hidden-sizeHidden size (default: 4096).
--intermediate-sizeDense FFN intermediate (default: 12288).
--kv-lora-rankKV LoRA rank (default: 512).
--moe-intermediate-sizeMoE expert intermediate (default: 1536).
--num-attention-headsAttention heads (default: 64).
--num-experts-per-tokExperts per token (default: 6).
--n-routed-expertsNumber of routed experts (default: 128).
--n-shared-expertsShared experts (default: 2).
--q-lora-rankOptional Q LoRA rank.
--qk-nope-head-dim, --qk-rope-head-dim, --v-head-dimHead dimensions for MLA-style attention (defaults: 128 / 64 / 128).
--vocab-sizeVocabulary size (default: 128256).
--dtypebf16 or fp16 (default: bf16).
--mbsMicrobatch size (default: 1).
--durationSeconds per shape (default: 3).
--output-fileReport path (default: ./gemm-deepseek_report.md).
--appendAppend to an existing report instead of overwriting.

Example

primus-cli direct -- benchmark gemm-deepseek --model Deepseek_V3 --dtype bf16 --append

strided-allgather

Strided all-gather microbenchmark (useful for multi-rank communication patterns).

ArgumentDescription
--sizes-mbComma-separated message sizes in MB per rank (default: 64,128,256).
--strideRank stride for group formation (default: 8).
--parallelRun multiple groups’ all-gathers in parallel.
--itersTimed iterations per size (default: 50).
--warmupWarmup iterations per size (default: 10).
--dtypefp16, bf16, or fp32 (default: bf16).
--backendnccl, gloo, or mpi (default: nccl).

Example

primus-cli slurm srun -N 2 -- benchmark strided-allgather --sizes-mb 64,128 --stride 8 --iters 50

rccl

RCCL collective benchmark: sweeps message sizes and reports bandwidth and latency statistics.

ArgumentDescription
--opOne or more of: all_reduce, broadcast, reduce_scatter, all_gather, alltoall (default: all_reduce).
--sizesExplicit size list (for example 1K,2K,4K,8K,1M). Overrides generated sweep.
--min-bytesMinimum message size for generated sweep (default: 1K).
--max-bytesMaximum message size (default: 128M).
--num-sizesNumber of points in generated sweep (default: 12).
--scalelog2 or linear for generated sweeps (default: log2).
--dtypebf16, fp16, or fp32 (default: bf16).
--warmupWarmup iterations (default: 20).
--itersTimed iterations (default: 100).
--repeatRepeat each (op, size) for stability (default: 1).
--aggregate-repeatEmit an extra summary row aggregating repeat runs.
--checkEnable lightweight correctness checks.
--output-fileReport path (.md, .csv, .tsv, .jsonl, .jsonl.gz; default: ./rccl_report.md).
--appendAppend instead of overwrite.
--per-rankPer-rank summary lines.
--per-rank-filePath for per-rank stats (if empty, derived from --output-file with _rank suffix).
--per-iter-traceEmit per-iteration trace (can be large).
--trace-fileTrace output path (if empty, derived from --output-file).
--trace-limitMax iterations to record per (op, size); 0 means all.
--trace-opsComma-separated ops to include in trace (empty = all).
--trace-sizesComma-separated sizes to include in trace (empty = all).
--clusterLabel for the report preamble. Defaults to $PRIMUS_CLUSTER, falling back to a built-in placeholder (amd-aig-poolside) when it is unset—set PRIMUS_CLUSTER or pass --cluster to record your own cluster name.

Example

primus-cli slurm srun -N 4 -- benchmark rccl --op all_reduce --min-bytes 1M --max-bytes 128M --dtype bf16

Understanding results

  • GEMM suites emit throughput-oriented metrics suitable for comparing dtypes, shapes, and durations across runs. Keep duration long enough to smooth variance on shared clusters.
  • rccl reports collective latency and bandwidth across a size sweep; use it to verify inter-node behavior and to compare against expected NIC bandwidth.
  • Markdown / CSV / TSV / JSONL output formats support post-processing in notebooks or CI; gzip JSONL is supported for large traces.

Tips

  1. Distributed initialization: If jobs hang or report uninitialized distributed state, launch through primus-cli (direct / container / slurm) rather than calling Python entrypoints manually without the right environment.
  2. Paths: Prefer absolute paths for --output-file when using containers or Slurm so the working directory matches your expectations.
  3. Multi-node: Use your scheduler integration (primus-cli slurm …) so rank and address assignment matches your cluster.
  4. Full cluster validation: Combine targeted benchmark runs with Preflight for host, GPU, network, and integrated perf checks.