cuBLASLt
Installation
using Pkg
Registry.add(url="https://registry.jool.space")
Pkg.add("cuBLASLt")Index
cuBLASLt.MatmulPlancuBLASLt.MatmulPlancuBLASLt.UnsupportedConfigErrorcuBLASLt.activation_symbolcuBLASLt.empty_plan_cache!cuBLASLt.handlecuBLASLt.ltdatacuBLASLt.ltptrcuBLASLt.ltscalecuBLASLt.ltstridecuBLASLt.matmul!cuBLASLt.matmul_supportedcuBLASLt.plan_candidatescuBLASLt.plan_matmulcuBLASLt.scale_modecuBLASLt.version
API
cuBLASLt.MatmulPlan — Type
MatmulPlan(; M, N, K, typeA, typeB, typeD, kwargs...)An execution plan for D = α ⋅ op(A) ⋅ op(B) + β ⋅ C, where op(A) is M × K, op(B) is K × N, and C/D are M × N (column-major).
The type parameter is the element type of α/β (Float32, or Float16/ Float64 for the :f16/:f64 compute types).
Keywords
M,N,K: shapes ofop(A) ⋅ op(B) = D(required).typeA,typeB,typeD,typeC = typeD: Julia types orcudaDataTypes.transA,transB:'N','T', or'C'(default'N').lda,ldb,ldc,ldd: leading dimensions of the stored matrices.batch = 1: strided-batch count;strideA/strideB/strideC/strideDare element strides between batch entries (default: densely packed).compute = :f32: one of :f32, :tf32, :fastf16, :fastbf16, :bf16x9, :f16, :f64.scale_modeA,scale_modeB: scale mode (affects algorithm choice);:noneor one of :scalarf32, :vec32ue8m0, :vec16ue4m3, :outervecf32, :vec128f32, :blk128x128f32, :perbatchscalarf32. The scale arrays are apply-time arguments (scaleA/scaleB).pointer_mode = :host::host(α/β areNumbers) or:device(α/β are 0-dimensionalCuArrays, read at execution time; graph-capture safe).alignA,alignB,alignC,alignD(default 256): minimum byte alignment the corresponding operand pointer is guaranteed to have at call time, as a power of two. Alignment gates algorithm validity — pass the true alignment when operands will be views into larger arrays.epilogue = :none: fused epilogue, one of :relu, :reluaux, :bias, :relubias, :reluauxbias, :drelu, :drelubgrad, :gelu, :geluaux, :gelubias, :geluauxbias, :dgelu, :dgelubgrad, :bgrada, :bgradb. Forward:D = act(α ⋅ op(A) ⋅ op(B) + β ⋅ C + bias), with*_auxvariants stashing the activation input (GELU: values; ReLU: a sign bit-mask) for the backward pass. Backward::drelu/:dgelumultiply the matmul result elementwise byact′(aux); the*_bgradvariants additionally reduce the result into a bias-gradient vector, and:bgrada/:bgradbreduce operand A/B over K into one. Thebias/bgrad/auxpointers are apply-time arguments.bias_type: element type of the bias/bgrad vector (defaults to cuBLASLt's rule: D's type, or BF16/FP16 for FP8 matmuls).aux_type,aux_ld,aux_stride: aux-buffer element type (GELU only), leading dimension (elements; bits for the ReLU bit-mask, divisible by 128), and batch stride.scale_modeC,scale_modeD: likescale_modeA/B, for the C input and the D output (quantization scale);scaleC/scaleDare apply-time.out_scale_modeD: block-scale mode of the kernel-computed output scales (MXFP8/NVFP4 output); theout_scaleDarray they are written to is apply-time. Requires cuBLASLt ≥ 12.9, and only supported inside a block-scaled matmul (A/B in matching block modes) — the heuristic rejects it on unscaled or tensor-wide-scaled inputs.fast_accum = false: FP8 fast accumulation.max_workspace = 32 << 20: workspace-size ceiling for the heuristic; the chosen algorithm's actual requirement is stored asplan.workspace_size.
cuBLASLt.MatmulPlan — Method
(plan::MatmulPlan)(D, A, B; α = true, β = false, C = D,
scaleA = nothing, scaleB = nothing,
scaleC = nothing, scaleD = nothing,
out_scaleD = nothing, amaxD = nothing,
bias = nothing, bgrad = nothing, aux = nothing,
workspace = nothing)Compute D = α ⋅ op(A) ⋅ op(B) + β ⋅ C according to plan, in place.
Operands are anything cuBLASLt.ltdata/cuBLASLt.ltptr/ cuBLASLt.ltstride accept; Transpose/Adjoint/PermutedDimsArray wrappers on A/B (and NNlib's batched wrappers, with the NNlib extension loaded) are unwrapped and checked against the plan's orientation, raw arrays (and identity permutations) are trusted as the stored matrices. α/β are host Numbers (pointer_mode = :host) or 0-dimensional CuArrays (pointer_mode = :device). scaleA/scaleB are device scale arrays, required iff the plan's corresponding scale mode is not :none and the operand does not carry its own (see cuBLASLt.ltscale). For the block modes (:vec32_ue8m0, :vec16_ue4m3) cuBLASLt reads scales through its tiled layout of 128(outer)×4(inner)-entry tiles: data must be swizzled accordingly and the allocation padded to whole tiles, or the kernel reads out of bounds. Epilogue arguments (mandatory iff the plan's epilogue uses them): bias is the input vector of length M for the forward *_bias epilogues; bgrad the output vector the gradient epilogues reduce into (length M, or N for :bgradb); aux the activation-input stash — written by the forward *_aux epilogues, read by the backward d* ones (GELU: a matrix of pre-activations; ReLU: a bit-mask; both sides of a forward/backward pair must agree on its dtype/ld/stride, which nothing checks for you).
Output quantization: scaleD (with scale_modeD) is the quantization scale applied to a narrow D; out_scaleD (with out_scale_modeD) the array the kernel writes computed block scales to (or carried by a scale-bearing D, see cuBLASLt.ltscale); amaxD an optional 1-element Float32 device array the pre-quantization absmax of D is written to; scaleC dequantizes a narrow C.
workspace is an optional preallocated buffer of at least plan.workspace_size bytes, owned by the caller: nothing is allocated, nothing is freed. By default one is allocated from the stream-ordered pool and freed right after the launch.
Under graph capture, always pass workspace explicitly. The pool default allocates on every apply, and CUDA's allocator may synchronize to reclaim — illegal inside a capture. The plan is the seam that makes this easy: it knows its own workspace_size before any launch, so a caller carves that many bytes from wherever it keeps memory (an arena, a slab, a reused buffer) and hands them to the apply, which is then allocation-free.
plan = plan_matmul(D, A, B)
ws = my_allocator(plan.workspace_size)
plan(D, A, B; workspace = ws) # no allocation, capture-safecuBLASLt.UnsupportedConfigError — Type
cuBLASLt.UnsupportedConfigErrorThe heuristic found no algorithm for a configuration: this device, this cuBLASLt, these types/shapes/modes. Distinct from an ArgumentError — those say a caller spelled something wrong, this one says the library cannot serve a well-formed request, which is a routing fact, not a bug.
Consequently it is the one exception the plan cache memoizes (a negative result is as worth caching as a positive one; the heuristic query is not cheap), and the one cuBLASLt.matmul_supported answers false to instead of throwing.
cuBLASLt.activation_symbol — Method
cuBLASLt.activation_symbol(f) -> Symbol or nothingThe epilogue activation f stands for: :relu or :gelu (cuBLASLt's GELU is the tanh approximation) — those two are the entire menu the library fuses. Returns nothing for anything unfusable, so layer code can branch on fusability (the branch constant-folds: this is dispatch on typeof(f)) instead of catching exceptions; passing an unfusable activation = to plan_matmul/matmul! is what throws. Symbols pass through, identity means :none. Register a function with
cuBLASLt.activation_symbol(::typeof(f)) = :relu # or :geluso callers can pass activation = f (e.g. NNlib.relu).
cuBLASLt.empty_plan_cache! — Method
cuBLASLt.empty_plan_cache!()Empty the cache used by the planless matmul! methods (benchmarking hygiene; freed plans are reclaimed by the GC).
cuBLASLt.handle — Method
cuBLASLt.handle() -> cublasLtHandle_tThe cuBLASLt handle for the current CUDA context.
cuBLASLt.ltdata — Method
cuBLASLt.ltdata(x) -> storage arrayThe storage array behind an operand — the thing whose eltype and size describe what cuBLASLt reads. Identity by default; block-scaled container types overload this to hand over their payload without this package knowing their layout. Pointer and stride customization live in cuBLASLt.ltptr and cuBLASLt.ltstride.
cuBLASLt.ltptr — Method
cuBLASLt.ltptr(x) -> CuPtr{Cvoid}The device pointer cuBLASLt reads an operand's storage through. Defaults to reinterpret(CuPtr{Cvoid}, pointer(x)).
cuBLASLt.ltscale — Method
cuBLASLt.ltscale(x) -> device scale array or nothingThe device scale array an operand carries, nothing by default. Operand types that bundle their scales overload this so plan_matmul and plan application extract scale pointers without explicit scaleA/scaleB arguments (which, when passed, take precedence).
cuBLASLt.ltstride — Method
cuBLASLt.ltstride(x, d) -> IntegerThe distance between adjacent elements along dimension d, in logical elements. Defaults to stride(x, d). Packed-storage owners overload this when their logical element stride differs from their physical container.
cuBLASLt.matmul! — Method
matmul!(D, A, B; α = true, β = false, C = D,
scaleA = nothing, scaleB = nothing, scaleC = nothing,
scaleD = nothing, out_scaleD = nothing, amaxD = nothing,
activation = nothing, bias = nothing, bgrad = nothing,
aux = nothing, workspace = nothing, kws...)Planless convenience: plan_matmul through the plan cache, then apply. Same signature as both; kws override derived plan kwargs (e.g. compute = :tf32, transA = 'T', epilogue = :dgelu_bgrad).
cuBLASLt.matmul_supported — Method
matmul_supported(D, A, B; kws...) -> BoolWhether cuBLASLt can serve this matmul! — same signature, no launch. Value-returning: an unsupported configuration answers false rather than throwing, so a router can pick between cuBLASLt and a fallback without try/catch.
The probe builds the plan and leaves it in the cache, so a true answer costs the following matmul! nothing, and a false answer is cached too (the heuristic query is not cheap, and "no algorithm exists" is a stable fact about this device and this library).
Malformed arguments still throw: false means cuBLASLt has no algorithm, not you called this wrong.
matmul_supported(D, A, B; compute = :tf32) ? matmul!(D, A, B; compute = :tf32) :
mul!(D, A, B)cuBLASLt.plan_candidates — Method
plan_candidates(D, A, B; count = 8, kws...) -> Vector{MatmulPlan}
plan_candidates(; count = 8, M, N, K, typeA, typeB, typeD, kws...) -> Vector{MatmulPlan}The algorithm escape hatch: like plan_matmul (or the MatmulPlan kwargs constructor in the second form), but returns up to count candidate plans, heuristic-ranked. Each is independently callable — benchmark them and keep the winner; that is the canonical cuBLASLt autotuning loop, with the plan cache ownership on the caller's side.
cuBLASLt.plan_matmul — Method
plan_matmul(D, A, B; α = true, β = false, C = D,
scaleA = nothing, scaleB = nothing, workspace = nothing,
kws...) -> MatmulPlanBuild a MatmulPlan for D = α ⋅ op(A) ⋅ op(B) + β ⋅ C from prototype arguments — the same signature the returned plan is applied with, so every call-time argument doubles as the prototype its plan-time counterpart is derived from:
- shapes, element types, leading dimensions, batching, and pointer alignments come from the arrays (via
cuBLASLt.ltdata); Transpose/Adjointwrappers onA/BsettransA/transB, as doesPermutedDimsArraywith the first two dims swapped —(2,1)or, for a batched transpose,(2,1,3)— which sets'T'(identity permutations are accepted as'N'; anything else throws). With the NNlib extension loaded,NNlib.batched_transposesets'T'andNNlib.batched_adjoint'C'the same way;- the types of
α/βsetpointer_mode(Numbers →:host, 0-dimensionalCuArrays →:device); scaleA/scaleB/scaleC/scaleDarrays (or scales carried by the operands, seecuBLASLt.ltscaleandcuBLASLt.scale_mode) set the scale modes;out_scaleD(or a scale-carryingD) setsout_scale_modeD— kernel-computed output block scales for quantized output;activation(aSymbolor a function registered viacuBLASLt.activation_symbol) composed with the presence ofbias/auxprototypes sets theepilogue; the gradient epilogues (:drelu_bgrad,:dgelu_bgrad,:bgrada,:bgradb) are spelled with an explicitepiloguekwarg. Bias/aux prototypes setbias_type,aux_type,aux_ld, and the batch strides;workspacesetsmax_workspace = sizeof(workspace), guaranteeing the chosen algorithm fits the buffer.
Remaining kws override anything derived and are passed through to MatmulPlan (e.g. compute, scale_modeA, epilogue, max_workspace).
Alignment caveat: the plan promises the heuristic the prototypes' pointer alignments, and application checks that later operands keep the promise — plan with your worst-aligned representative.
cuBLASLt.scale_mode — Method
cuBLASLt.scale_mode(x) -> SymbolThe scale mode implied by an operand's type, :none by default. Block-scaled container types overload this (block shape + scale eltype → one of :scalarf32, :vec32ue8m0, :vec16ue4m3, :outervecf32, :vec128f32, :blk128x128f32, :perbatchscalarf32).
cuBLASLt.version — Method
cuBLASLt.version() -> VersionNumberThe version of the loaded libcublasLt.