Conversation
Add an experimental, env-gated fast path for the native CPU matmul reference used in GPU accuracy validation. When DNNL_BENCHDNN_MATMUL_PANEL_FILL=1 (and --fast-ref=false), inputs are filled so the result is periodic along M and N (K kept full); the reference is computed for a single representative panel_m x panel_n panel and broadcast across the full output. This reduces the reference cost from O(MB*M*N*K) to ~O(panel_m*panel_n*K) while the library still runs the full shape. Panels are at least 128 and aligned to dst scale/zero-point groups so no block/group quantization parameter straddles a panel boundary. Supported: common dtypes, int8/woq incl. K-grouped scales and zero-points, bias, sum/eltwise/binary/prelu post-ops, batch tiling, and runtime dimensions. Unsupported configurations (dynamic dst scales, dropout, stochastic rounding, sparse/grouped, sub-128 shapes) fall back to the normal reference and print the reason. Disabled by default. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ap 3) The per-block dynamic destination scales are periodic when the panel width is a multiple of the destination-scale group, so the native periodic reference computes the representative panel's DST_SCALES and broadcasts them across the full destination-scale tensor. Dynamic dst scales are a computed OUTPUT and are no longer periodized as an input. Validated on Linux BMG (Intel Arc B580): dst:dynamic_fp matmul PASSES with exact DST_SCALES comparison. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the DNNL_BENCHDNN_MATMUL_PANEL_FILL env variable (kept as a deprecated alias) with a first-class benchdnn mode modifier, --mode-modifier=A, that opts into the paneled (periodic) fast native reference for the matmul driver. The modifier does not disable --fast-ref. Paneling engages only on the native reference path (i.e. when no fast CPU primitive reference is available for the problem, or when --fast-ref=false is passed). When a fast CPU primitive reference exists it runs the full shape with vectorized kernels and is generally faster than the paneled scalar native reference, so paneling is skipped to avoid regressing those configs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The paneled ("periodic") fill previously did redundant full-tensor work:
fill_data filled the f32 reference and reordered it to the device, then
apply_paneled_fill periodized the reference and reordered to the device a
second time. The first device reorder was pure waste, and the periodization
itself used a per-element stride-decode loop over the whole tensor.
Two changes:
- Skip fill_data's device reorder when paneled fill is active; the single
post-periodize reorder in apply_paneled_fill now supplies the device data.
- Add a fast path to periodize_ref: when the contiguous (stride-1) dimension
is not periodized (the common src/wei case where K stays full), broadcast
whole contiguous lines with memcpy in parallel instead of per-element copy.
On Intel Arc B580, real LLM layers: s8:u4:f16 woq 4096x11008x4096 fill
8.9s->4.8s (wall 10.9s->5.6s); f4_e2m1 mx 14558x3072x3072 wall 5.6s->3.7s;
f16:u4:f16 woq 1009x14336x4096 wall 10.8s->5.1s. Correctness unchanged.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Paneled fill (--mode-modifier=A) periodized scales and zero-points using a positional role assignment on their physical dims. Quantization tensors, however, only materialize the logical dims selected by their mask (see md2dims()), so a per-batch wei scale (mask 3 -> dims [batch, K/group]) was mis-roled: the batch dim was treated as K and never collapsed. The device then kept distinct per-batch scales while the reference broadcast batch 0, producing mismatches on batches 1..MB-1. Route scales/zero-points through a new mask-aware quant_period() that walks the owner tensor's logical dims, keeps the masked ones, and assigns each the role of its logical axis (leading=batch, last two=role_2nd/role_last), with group sizes scaling the panel period. Data/bias/post-op operands keep the positional full_rank_period() path. periodize_ref() now takes an explicit period vector shared by both. Fixes batched woq (e.g. --dt=f16:s4:f16 --attr-scales=wei:3:f16:128x1 4x300x4096:4x4096x512), previously failing with -A only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
d863243 to
da36d94
Compare
| @@ -140,3 +118,54 @@ or | |||
|
|
|||
| More examples with different driver options can be found at | |||
| inputs/matmul/test_\*. | |||
|
|
|||
There was a problem hiding this comment.
There is a chance that trimmed shapes result in other strategies were selected, hence a testing gap
Rather than trying to optimize the current work, it may be simpler and faster to directly testing our strategies. For a given strategy, we really don't need to run a particularly large problem to validate all the code paths are correct (roughly 10-20 sizes smaller than 1Kx1Kx1K likely gets 100% functional validation). We could enable fairly direct strategy choice via something like #5461, by extending the configuration dispatcher to support something like entry=<index>. Exhaustive testing then just becomes running a small suite a problems against each entry until we hit the end of the supported entries.
1. Problem
benchdnn GPU matmul correctness runs can be dominated by the CPU "golden" reference. For configs with no fast CPU primitive (e.g.
f8/f4/mx, some weight-decompression cases) benchdnn falls back to the scalar native reference, which isO(MB·M·N·K). On large layers this reference alone takes minutes per case, making broad sweeps impractical.Currently, in oneDNN functional testing, we have to trim large shapes significantly (see #4355). While it works ok, two potential issues remain:
2. Solution
Fill the matmul inputs so the result is periodic along
MandN(K kept full). Both the GPU primitive and the reference then produce a periodic output, so the native reference only needs to compute one representativepanel_m × panel_npanel and broadcast it. Reference cost drops fromO(MB·M·N·K)to~O(panel_m·panel_n·K); the GPU primitive still runs the full shape. Panel width ≥128 and aligned to dst scale/zero-point groups so no block/group quantization parameter straddles a panel boundary.Opt-in via
--mode-modifier=A(env varDNNL_BENCHDNN_MATMUL_PANEL_FILL=1kept as a deprecated alias). It does not disable--fast-ref: paneling engages only on the native-reference path. When a fast CPU primitive reference exists it runs the full shape vectorized and is generally faster, so paneling is skipped there to avoid regressions.Periodic inputs can mask
M/Naddress-arithmetic bugs, so this is opt-in and not a CI replacement for the default reference.3. Implementation
utils/bench_mode.{hpp,cpp},utils/parser.cpp: newmode_modifier_t::ref_periodic_fill(A).matmul/matmul.cpp:apply_paneled_fillperiodizes src/wei/bias, scales/zero-points, sum and binary/prelu post-op operands on the M/N panel grid; gated on the native path (!prim_ref).matmul/ref_matmul.cpp:compute_ref_matmul_periodiccomputes the representative panel and broadcasts dst values and dynamic/derived dst scales (mx,dynamic_fp).doc/driver_matmul.md,doc/knobs_common.md.4. Validation
Validated on Intel Arc B580 (Battlemage), OpenCL GPU runtime.
dynamic_fpdst scales with exactDST_SCALEScomparison), bias, sum, eltwise, binary/prelu post-ops, precomputed-reductions, runtime dims, batched.5. Performance (Intel Arc B580, layers from real LLM models, naturally native path, OFF vs ON)
These are matmul layers taken from real LLM models. Their configs (weight-decompression and
mx/f4scaling) have no fast CPU primitive reference, so benchdnn naturally uses the scalar native reference — exactly the slow case this feature targets. No flags force this path;--mode-modifier=Ais the only difference between OFF and ON. All PASS.mx(e8m0) src/wei scales + biasThe native reference itself speeds up ~360–665×. Since the data is periodic, the input fill was optimized to compute the reference once and broadcast it:
fill_data's device reorder is skipped when paneling is active (the single post-periodize reorder supplies the device data), and periodization copies whole contiguous lines withmemcpyin parallel. The remaining ON wall time is now the single unavoidablef32→devicereorder (the GPU still runs the full shape).