metal : per-device tuned (Q, NE) for flash-attn vec (replay) - #26570
Conversation
|
Looks like the stack is wired up correctly :) |
This comment was marked as resolved.
This comment was marked as resolved.
864c08e to
2934b5b
Compare
5d79b77 to
aa4b599
Compare
|
@ggerganov Yes, the button was there on both PRs and I used it from #26561. It worked as expected |
2934b5b to
5522498
Compare
aa4b599 to
0f27935
Compare
| output_printer->print_failed_tests(failed_tests); | ||
|
|
||
| return n_ok == tests_run; | ||
| const bool slice_ok = run_fa_vec_slice(backend, backend_cpu.get()); |
There was a problem hiding this comment.
This currently runs unconditionally for every test-backend-ops. For example:
test-backend-ops -o ADDwould still run it.
There was a problem hiding this comment.
Thanks. Fixed — the slice now only runs when -o selects FLASH_ATTN_EXT, or when no -o is given (unchanged default).
|
Are you planning additional changes to the stack? |
|
@ggerganov Yes, I have one more follow-up planned from #25750 the “Aggregate target-selection gate.” Do you think it would make more sense to stack it on top of this, or submit it as a separate optimization PR? |
Can you explain the goal in some simpler way - I don't understand the paragraph. |
|
@ggerganov Sure. The table only overrides the baseline kernel when the win is large enough to justify a path that differs from today's backend. I use ~5% as the noise-floor threshold: below that, the difference is within the harness's run-to-run variation and doesn't warrant a table entry. The threshold is applied to the sum of kernel time across the entry's sampled (KV-depth, batch-width) points. As a result, an entry can be net-positive even when individual points regress. Nearly all of the regressions occur at odd batch widths, where Q>1 configurations waste padded rows. For example, q5_0 with dk=320, dv=256 at 32k KV gains 8-13% at ne01=6/8/16, but regresses 10% at ne01=5 and 5% at ne01=7. The entry is still ~5% faster in aggregate, so it passes the gate. Across the full table, this accounts for 26 of 1414 tuned sample points (1.8%), against a 1.33x median speedup. All five regressions above 5% are in the ne01>=5 bucket, which deliberately collapses everything from 5 onward into a single min-max-regret backstop, since real draft-n-max is typically <=3. Within ne01<=4, every regression is below 5%, i.e. within the noise floor the threshold is designed to filter out. The aggregate-sum gate is a deliberate trade-off for that reason, and it is net-positive in the current sweep, but it isn't the final gating strategy. |
|
Ok, up to you if you want to add it to the stack. LMK when ready - I want to do 2 things before considering to merge:
|
|
OK, I’ve been a bit tied up lately, but I should be able to fill in the stack content sometime next week. I’ll let you know once it’s ready. |
5522498 to
89eea16
Compare
040a9f2 to
1693e90
Compare
|
@ggerganov Ready now — the aggregate gate is replaced by a pointwise one: a candidate can only claim a bucket if it is no slower than the baseline at every sampled point it covers. And rebase on the latest master. |
|
Great - let's see if we can get this in over the weekend. Will work on the plan above:
|
|
2ec0cd8 adds |
|
@ggerganov Nice, do you have any end-to-end performance results? |
A quick test on M2 Ultra with the bench from #27390 (comment):
|
2ec0cd8 to
efeda76
Compare
| # ggml-metal-tuning | ||
|
|
||
| Offline kernel tuner for the Metal backend. | ||
| It sweeps a kernel's config grid on the machine it runs on and prints pasteable table rows for `ggml/src/ggml-metal/ggml-metal-tuning.cpp`. | ||
|
|
||
| This is not a test: it never reports pass/fail on performance. | ||
| A non-zero exit code means bad arguments or a wrong environment (no Metal device, missing proc bridges), never a perf result. | ||
|
|
||
| | tuner | tunes | table | | ||
| |---|---|---| | ||
| | `fa-vec` | flash-attn vec `(Q, NE)` per `(dtype, head size, KV depth, batch width)` | `fa_vec_tuned_table` | | ||
|
|
||
| ## Adding a device to the FA-vec table | ||
|
|
||
| Build on the target machine: | ||
|
|
||
| ```bash | ||
| cmake -B build -DGGML_METAL=ON | ||
| cmake --build build --target ggml-metal-tuning -j | ||
| cmake --build build --target test-backend-ops -j | ||
| ``` | ||
|
|
||
| Sweep the grid (6 dtypes x 10 head sizes x 4 KV depths x 9 batch widths; a few hours): | ||
|
|
||
| ```bash | ||
| ./build/bin/ggml-metal-tuning fa-vec > fa_vec_rows.txt 2> fa_vec_sweep.log | ||
| ``` |
There was a problem hiding this comment.
@forforever73 It would be useful to create a dedicated discussion with a summary of which families have been tuned and which haven't. This way we can get help from the community to run the tuning and collect data for more devices.
There was a problem hiding this comment.
Sounds good. I can draft a checklist in a new Discussion thread to track the progress. But my laptop is off for the night, so I’ll have to wait for my morning. Or, if you prefer, you’re more than welcome to create it first
* metal : per-device tuned (Q, NE) for flash-attn vec (ggml-org#25750) * rebase Q-generic FA vec body from 01dc936 (ggml-org#23114) * add 53 f16 (Q,NE) flash-attn vec instantiations (vec 80 -> 133) * add FA vec (Q,NE) tuning table + dispatch wiring + SMEM cap fallback * add FA vec (Q,NE) perf sweep * fill tuning result * fold family table into a per-family representative SKU * refactor tuning result format * extend FA vec tuning to quantized KV caches * sync fa vec tuner bucketing with runtime, use pointwise tuning regret * update tuned table * format and cleanup * prefix fa_vec tuning procs with ggml_backend_metal_tuning_, drop unused fa_vec_override_active * add device id -> token lookup for the offline tuning tool * add ggml-metal-tuning skeleton * add op-agnostic perf cell + median timing for the tuner * add FA-vec graph build + tensor init to the tuner * tools : add FA-vec (Q,NE) sweep, compression and table emit * cool down and re-measure the dirty window on thermal drift * test-backend-ops : replace the FA vec tune mode with a bounded (Q,NE) slice * tools : document the Metal tuner, point the table comment at it * abort on unknown KV type, single-source fa_vec_legal_ne * cleanup * honor -o in the FA vec (Q,NE) slice * retune FA-vec (Q, NE) under a pointwise no-harm gate * cont : add fa-vec tunings for M1 Pro, M2 Ultra, M5 Max --------- Co-authored-by: Georgi Gerganov <ggerganov@gmail.com>
|
This is such a cool optimization, @forforever73. Thank you for it! 🙏 |
|
@nikwen Thank you! Let’s keep making the Metal backend better together ! |
* metal : per-device tuned (Q, NE) for flash-attn vec (ggml-org#25750) * rebase Q-generic FA vec body from 01dc936 (ggml-org#23114) * add 53 f16 (Q,NE) flash-attn vec instantiations (vec 80 -> 133) * add FA vec (Q,NE) tuning table + dispatch wiring + SMEM cap fallback * add FA vec (Q,NE) perf sweep * fill tuning result * fold family table into a per-family representative SKU * refactor tuning result format * extend FA vec tuning to quantized KV caches * sync fa vec tuner bucketing with runtime, use pointwise tuning regret * update tuned table * format and cleanup * prefix fa_vec tuning procs with ggml_backend_metal_tuning_, drop unused fa_vec_override_active * add device id -> token lookup for the offline tuning tool * add ggml-metal-tuning skeleton * add op-agnostic perf cell + median timing for the tuner * add FA-vec graph build + tensor init to the tuner * tools : add FA-vec (Q,NE) sweep, compression and table emit * cool down and re-measure the dirty window on thermal drift * test-backend-ops : replace the FA vec tune mode with a bounded (Q,NE) slice * tools : document the Metal tuner, point the table comment at it * abort on unknown KV type, single-source fa_vec_legal_ne * cleanup * honor -o in the FA vec (Q,NE) slice * retune FA-vec (Q, NE) under a pointwise no-harm gate * cont : add fa-vec tunings for M1 Pro, M2 Ultra, M5 Max --------- Co-authored-by: Georgi Gerganov <ggerganov@gmail.com>
Overview
Stacked on top of #26561.
stack/metal-splitmastersince thenstack/metal-fa-vecstack/metal-tunerRequirements