DEV Community

Cover image for Selecting a BLAS Backend: cuBLAS vs rocBLAS vs Vendor BLAS
beefed.ai
beefed.ai

Posted on • Originally published at beefed.ai

Selecting a BLAS Backend: cuBLAS vs rocBLAS vs Vendor BLAS

You see the symptoms: good single-GPU GFLOP numbers but terrible application throughput across the cluster; numerical drift after a port; long outages updating drivers; or a surprise that small, batched GEMMs dominate your runtime and the BLAS backend delivers only 10% of theoretical performance. These are implementation and ecosystem problems — not math problems — and they behave differently on NVIDIA and AMD stacks.

Contents

  • [How throughput, precision, and batch support shape real-world BLAS performance]
  • [Where driver, runtime, and ecosystem compatibility bite at cluster scale]
  • [How to scale BLAS across GPUs and nodes: proven integration patterns]
  • [A practical decision matrix: when cuBLAS, rocBLAS, or vendor BLAS is the right choice]
  • [Concrete migration recipes: porting, testing, and tuning for peak performance]
  • [Checklist and validation protocol to choose and prove a BLAS backend]

How throughput, precision, and batch support shape real-world BLAS performance

Performance is not a single number. Treat it as three measurable axes you must benchmark on your actual workloads:

  • Throughput (FLOP/s on target kernels). Peak theoretical TFLOPs matter, but the delivered FLOP/s depends on memory bandwidth, kernel occupancy, and algorithm choice (blocked vs. tiled GEMM). For example, NVIDIA exposes Tensor Cores and a TF32 mode that accelerate FP32-like workloads on Ampere+ hardware; library calls choose specialized kernels for those modes.

  • Precision & numerical model. Scientific HPC often needs FP64; AI workloads prefer mixed precision (FP16, BF16, FP8) with fused accumulations. cuBLAS exposes cublasSetMathMode / cublasGemmEx and cuBLASLt for TF32/mixed modes; rocBLAS provides rocblas_gemm_ex with compute-type control and Tensile/hipBLASLt-backed GEMMs for mixed precisions. Your choice affects correctness (rounding, conditioning) and performance.

  • Batch support and small-matrix regimes. Many real workloads (e.g., batched linear algebra, transformers with many small heads) are dominated by many small GEMMs. cublasGemmBatched / cublasGemmStridedBatched and rocblas's rocblas_gemm_ex (with strided/batched variants) are essential; cuBLASLt and hipBLASLt provide additional kernels/planning for tiny matrices and epilogues. Measure both large and batched/strided cases.

Practical micro-example (C++ pseudocode) showing the local-batched path you should time locally:

// Pseudocode: measure batched GEMM on one GPU
cublasHandle_t h;
cublasCreate(&h);
cudaStream_t s;
cudaStreamCreate(&s);
cublasSetStream(h, s);
// time cublasGemmStridedBatchedEx / rocblas_gemm_ex with batch_count, M,N,K, strides
// record wall-clock, GPU counters, and kernel occupancy
Enter fullscreen mode Exit fullscreen mode

Run both cublasGemmStridedBatchedEx / cublasGemmBatchedEx and the rocblas_gemm_ex strided/batched forms and compare at your problem shapes — vendor heuristics can pick different kernels that flip the winner at specific sizes.

Where driver, runtime, and ecosystem compatibility bite at cluster scale

The single-host experiments are necessary but insufficient: software and driver layering kills reproducibility at scale.

  • Driver / toolkit compatibility. CUDA releases are paired with driver requirements and have an explicit compatibility/upgrade policy; mismatched CUDA driver/toolkit combinations will break cuBLAS and NCCL behavior and limit which cuBLASLt kernels are available.

    ROCm has a compatibility matrix (kernels, OS, ROCm versions and supported GPUs); production clusters must pin a validated ROCm + kernel + driver combo.

  • Library packaging and distribution. Many HPC vendors ship tuned stacks (system modules, vendor containers) that include a particular cuBLAS/rocBLAS and a specific NCCL/RCCL build optimized for the platform interconnects; using the distro cuBLAS against a mismatched driver is a guaranteed source of trouble.

  • Portability layers. If you need cross-vendor portability, use the right abstraction: AMD’s hipify converts CUDA sources to HIP, and hipBLAS is a marshalling layer that can route to rocBLAS or cuBLAS backends as configured — useful for a single source tree that must run on both ecosystems with minimal #ifdef churn. These tools accelerate porting but do not eliminate the need to re-tune kernels and re-run numerical tests.

  • Ecosystem couplings. Deep learning frameworks and HPC packages often expect NCCL/cuBLAS semantics on NVIDIA; PyTorch and TensorFlow have special support and optimizations that call cuBLAS/cuBLASLt directly. For AMD, ROCm provides rocBLAS, RCCL, and HIP-based frameworks, but you must validate framework-level support and version alignments.

Table: quick compatibility snapshot

Library Best fit hardware Precision strengths Batch support Multi-GPU / multi-node integration
cuBLAS / cuBLASLt NVIDIA (A100/H100) FP64, FP32, TF32, FP16, FP8 via cuBLASLt cublasGemmBatched / StridedBatched, cuBLASLt groups cublasXt (in-node), NCCL for collectives.
rocBLAS / hipBLASLt AMD Instinct (MI2xx/MI3xx) FP64, FP32, BF16, FP16, FP8 (via hipBLASLt/Tensile) rocblas_gemm_ex + batched/strided variants; hipBLASLt for new low-precision kernels.
Vendor BLAS (oneMKL, MKL) Intel CPUs / Intel GPUs Strong CPU BLAS; SYCL/OpenMP offload to Intel GPUs MKL batch APIs, SYCL batched kernels oneAPI/level-zero integration for Intel GPUs; not a drop-in multi-node GPU collectives solution.

Cite these matrices before you roll a system image — packaging and driver upgrades are where clusters break during production runs.

How to scale BLAS across GPUs and nodes: proven integration patterns

I use the same pattern across HPC projects: local BLAS → in-node orchestration → node-to-node communication. You must instrument and measure at each boundary.

  • Local compute: call cuBLAS/rocBLAS (or cuBLASLt/hipBLASLt for tuned small-matrix and mixed-precision kernels) on each GPU and measure kernel-level performance using vendor profilers (Nsight Systems / Nsight Compute on NVIDIA; rocprof / ROCm Compute Profiler on AMD).

  • In-node orchestration: either use cublasXt on NVIDIA for static multi-GPU BLAS operations inside a single host or shard work across per-GPU processes/threads and let a collectives library handle synchronization. cublasXt can dispatch BLAS calls across a selected list of GPUs in a node.

  • Cross-node collectives: use NCCL (NVIDIA) or RCCL (AMD) for high-efficiency GPU collectives; bind those to an MPI launch or native runtime. On clusters with RDMA NICs and GPUDirect RDMA support, use the vendor Net plugin or the UCX transport to enable zero-copy GPU-to-GPU across nodes. This is the path to scale where the communication layer uses RDMA and GPU-aware transports rather than staging through host memory.

Small end-to-end pseudo-workflow (MPI + GPU collectives + local BLAS):

// per-process on each server
cudaSetDevice(local_gpu_id);
cublasCreate(&cublas_handle);
ncclCommInitRank(&nccl_comm, world_size, nccl_id, rank);
for (step : workload) {
  // local compute
  cublasGemmStridedBatchedEx(..., cublas_handle, ...);
  // gradient sync / reduction across GPUs and nodes
  ncclAllReduce(local_buffer, global_buffer, count, ncclFloat32, ncclSum, nccl_comm, stream);
}
ncclCommDestroy(nccl_comm);
cublasDestroy(cublas_handle);
Enter fullscreen mode Exit fullscreen mode

Measure both the compute-only time and the compute+comm time on representative inputs; look for communication saturation in nvlink, PCIe, or NICs and for small-message inefficiencies (many small all-reduces are expensive). Use NCCL UCX plugin tuning such as NCCL_UCX_RNDV_THRESH and NCCL_UCX_TLS in multi-NIC setups.

A practical decision matrix: when cuBLAS, rocBLAS, or vendor BLAS is the right choice

Make the decision by matching workload profile to platform fit:

  • Choose cuBLAS + cuBLASLt when:

    • Your cluster uses NVIDIA GPUs (A100/H100) with NVLink/NVSwitch and you need the best-per-node and best multi-node ecosystem (ML stacks and tooling). cuBLASLt is the weapon of choice for small mixed-precision GEMMs and TF32 accelerations.
  • Choose rocBLAS + hipBLASLt when:

    • Your hardware is AMD Instinct (MI2xx/MI3xx) and you rely on ROCm tooling; rocBLAS and hipBLASLt are the path to low-precision and tuned GEMMs on AMD; they also integrate with RCCL for collectives.
  • Choose Vendor BLAS (oneMKL / MKL / vendor-bundled BLAS) when:

    • You run primarily on CPUs or on an Intel GPU/oneAPI environment and you require tight CPU/GPU offload support through SYCL / OpenMP offload; oneMKL provides SYCL/OpenMP offload and a single-source pathway for Intel platforms. This is not a direct multi-node GPU collective solution — it addresses a different problem space (CPU-vectored linear algebra and Intel GPU offload).
  • Choose a portability layer (hipify + hipBLAS or a higher abstraction like Kokkos/SYCL) when:

    • You must maintain one codebase across NVIDIA and AMD clusters and are willing to pay the cost of re-tuning kernels and validating numerics across both stacks. hipify automates much of the mechanical conversion; hipBLAS can act as the runtime dispatch layer.

Contrarian insight from field experience: do not choose a cross-platform shim and expect identical performance without re-tuning. The performance portability claim is only true at the API level — algorithmic kernels still need hardware-specific tuning and sometimes different memory layouts (row-major vs. swizzled layouts the vendor kernel prefers). Validate with microbenchmarks and end-to-end jobs.

Concrete migration recipes: porting, testing, and tuning for peak performance

Below is a pragmatic migration protocol I use on multi-node clusters.

  1. Inventory and baseline
    • Inventory CPU/GPU models, interconnects (NVLink, xGMI, InfiniBand), OS kernel, driver, and ROCm/CUDA versions. Export nvidia-smi, rocminfo and lspci outputs. Pin versions using modules or container images.
  2. Microbenchmarks
    • Run cublas / rocblas microbenchmarks across the full range of M,N,K and batched counts you expect. Record GFLOP/s, memory bandwidth, and kernel occupancy. For AMD, use rocblas-bench; for NVIDIA use cublas samples or custom timing harnesses referencing cublasGemmStridedBatchedEx.
  3. End-to-end functional tests
    • Run your unit tests with device-side arrays; verify numeric tolerances for each precision path (FP64, FP32, BF16, FP16, FP8) and guard solvers requiring full precision. Where training/inference scripts rely on TF32 or Tensor Cores, test with cublasSetMathMode tuning.
  4. Communication validation
    • Validate NCCL / RCCL performance with all_reduce_perf and nccl-tests or rccl-tests across the production topology and tuning UCX/net plugin environment variables for RDMA-enabled fabrics. Use NCCL_PLUGIN_P2P=ucx and tune NCCL_UCX_* variables for optimal RDMA behavior.
  5. Profile and iterate
    • Profile slow shapes with Nsight Systems / Nsight Compute on NVIDIA, and rocprof / ROCm Compute Profiler on AMD; identify kernel inefficiencies, PCIe stalls, or small-message overhead. Optimize memory layouts, choose cuBLASLt solution indices or Tensile solutions, and adjust workspace sizes.
  6. Automation and CI
    • Add the microbenchmarks and numerics checks to CI, so runtime regressions are caught when the stack is upgraded. Pin library versions in production images; roll driver upgrades through staging nodes and re-run the benchmark battery.

Example commands & pointers:

  • Run an AMD GEMM system validation from ROCm guidance:

    • rocblas-bench -f gemm_strided_batched_ex ... (see ROCm system validation examples).
  • For cross-node collective validation on NVIDIA:

    • mpirun -np <N> ./all_reduce_perf -b 8 -e 8G -f 2 -g <gpus-per-node> (use NCCL tests & tune UCX/NCCL env vars).

Checklist and validation protocol to choose and prove a BLAS backend

Follow this checklist and mark PASS/FAIL on your cluster:

  1. Hardware alignment
    • Confirm GPUs and interconnect match the vendor ecosystem (NVIDIA → cuBLAS/NCCL; AMD → rocBLAS/RCCL).
  2. Driver/toolkit compatibility
    • Verify CUDA/ROCm and driver versions match vendor compatibility matrices; build a container that pins known-good versions.
  3. Local performance parity
    • For each critical shape: record kernel_time_local, GFLOP/s (best and median) for both single GPU runs and batched runs. Use cuBLASLt / hipBLASLt where appropriate.
  4. In-node multi-GPU correctness and scaling
    • Test cublasXt or multi-process per-GPU patterns and verify per-node speedup and memory usage.
  5. Multi-node collectives
    • Run nccl-tests/rccl-tests across nodes; verify RDMA is active (GPUDirect) and UCX/plugin tuning yields near-peak interconnect bandwidth.
  6. Numerical verification
    • Run end-to-end tests with absolute and relative tolerances specific to your application; flag operations that require full precision and mark them to run with double precision.
  7. Profiling and roofline
    • Produce roofline plots using vendor profilers to see whether GEMM kernels are compute- or memory-bound; optimize accordingly.

Important: Document the exact commands and environment variables used for each benchmark. Reproducibility is your single best defense against mysterious regressions after a driver/library update.

Sources:
cuBLAS :: CUDA Toolkit Documentation - cuBLAS API reference, cuBLASLt description, cublasGemm* batched APIs and multi-GPU cublasXt notes.

rocBLAS documentation — rocBLAS - rocBLAS API, rocblas_gemm_ex, batched/strided batched support and notes on Tensile/hipBLASLt usage.

NCCL — NVIDIA Collective Communications Library - NCCL overview, collectives, topology detection, and scaling patterns.

RCCL documentation — ROCm RCCL - RCCL overview, collectives, and multi-node capabilities on ROCm.

GPUDirect | NVIDIA Developer - GPUDirect RDMA explanation and its role in zero-copy GPU-to-GPU communication across NICs.

HIPIFY documentation — HIPIFY - hipify-clang and hipify-perl tooling for converting CUDA code to HIP and migration guidance.

hipBLAS — ROCm Libraries / hipBLAS readthedocs - notes on hipBLAS as a marshalling layer supporting multiple backends.

Compatibility matrix — ROCm Documentation - ROCm release compatibility across GPUs, kernels, and OSes.

CUDA Toolkit Release Notes — CUDA Toolkit Documentation - CUDA and driver compatibility guidance and minimum driver versions.

NVIDIA Nsight Systems | NVIDIA Developer - Nsight Systems overview for system-wide profiling (trace CUDA/cublas).

ROCm Compute Profiler / ROCProfiler — ROCm docs and tooling - ROCProfiler and ROCm Compute Profiler descriptions for AMD GPUs.

Intel oneAPI Math Kernel Library (oneMKL) — Intel Developer - oneMKL overview and GPU offload via SYCL/OpenMP for Intel platforms.

ROCm / ROCm Release Notes & hipBLASLt / hipBLASLt change logs - notes on hipBLASLt features and FP8/FP16 support in the ROCm stack.

NCCL-RDMA-SHARP Plugins — NVIDIA Docs (HPC-X) - NCCL UCX plugin guidance and environment variable tuning for RDMA/UCX transports.

Choose the backend that aligns with your production hardware, run the micro- and end-to-end benchmarks above, and treat the validation checklist as the acceptance gate before you roll any library or driver update.

Top comments (0)