⚡ Thunderbolt: Softmax — 8x unroll via single-FMA range reduction#72
⚡ Thunderbolt: Softmax — 8x unroll via single-FMA range reduction#72bugparty wants to merge 1 commit into
Conversation
This change introduces `softmax_v6`, a highly optimized softmax kernel targeting AVX2/FMA architectures. The primary microarchitectural enhancement is optimizing the transcendental approximation `exp256_ps_v3` by computing `r = x - n * ln(2)` within a single fused multiply-add (FMA). This reduces register pressure and instruction count, enabling an aggressive 8x unroll (processing 64 elements per iteration) instead of a 4x unroll. The increased unrolling perfectly saturates modern x86 execution ports and more efficiently hides the execution latency of standard instructions. Benchmarks display a significant throughput increase from ~4.12 GFLOP/s to ~4.61 GFLOP/s on N=1048576 fixed memory buffers, an ~11.8% gain over `softmax_v5`. Numerical accuracy holds steady within typical `1e-4` margins. Test harnesses (`test_naive_ops`) and benchmark definitions (`kernel_bench`) were appended accordingly. All modifications are documented per the Thunderbolt criteria. Co-authored-by: bugparty <1510776+bugparty@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
📝 WalkthroughWalkthroughAdds a new AVX2/FMA softmax kernel (softmax_v6) using a single-FMA exp approximation (exp256_ps_v3), registers a benchmark for it, adds a correctness test comparing against softmax_naive, and documents the technique with benchmark results. Changessoftmax_v6 kernel implementation
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
ml_kernels/include/ml_kernels/softmax.h (1)
138-166: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDrop the function-level
target("avx2,fma")here, or annotate the rest of the AVX2/FMA helpers in this header the same way.ml_kernels/CMakeLists.txtalready compiles the ml_kernels targets with-march=native, so this looks redundant and inconsistent.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ml_kernels/include/ml_kernels/softmax.h` around lines 138 - 166, The function-level target attribute on exp256_ps_v3 is redundant and inconsistent with the rest of the header. Remove the target("avx2,fma") annotation from exp256_ps_v3, or apply the same AVX2/FMA annotation strategy consistently to the other helper functions in softmax.h so the SIMD helpers match the build settings used by ml_kernels/CMakeLists.txt.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@ml_kernels/include/ml_kernels/softmax.h`:
- Around line 138-166: The function-level target attribute on exp256_ps_v3 is
redundant and inconsistent with the rest of the header. Remove the
target("avx2,fma") annotation from exp256_ps_v3, or apply the same AVX2/FMA
annotation strategy consistently to the other helper functions in softmax.h so
the SIMD helpers match the build settings used by ml_kernels/CMakeLists.txt.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6ffd0ada-1dba-4754-871b-62e1bd4a6435
⛔ Files ignored due to path filters (1)
a.outis excluded by!**/*.out
📒 Files selected for processing (4)
.jules/thunderbolt.mdml_kernels/include/ml_kernels/softmax.hml_kernels/src/kernel_bench.cppml_kernels/src/test_naive_ops.cpp
💡 What:
Implemented a new AVX2 kernel,
softmax_v6, heavily optimizing the underlying range reduction inexp256_ps_v3. We reduced the computation ofr = x - n * ln(2)down to a single FMA operation, trading exact ln(2) split-precision logic for lower instruction count. This lowered register pressure allowed for an 8x unrolling pattern (64 elements per loop cycle) across the max, exp, and sum normalization phases.🎯 Why:
Prior implementations (
softmax_v5) utilized a 4x unroll structure. While a 4x unroll hides some FMA latency overhead, the additional overhead in range reduction meant there were idle cycles for the execution ports. The 8x unrolling ensures that modern Out-of-Order execution engines remain completely saturated, thereby turning the execution from latency-bound to strictly throughput-bound.🏗️ How:
I isolated the exponential logic to
exp256_ps_v3, compressing the constant factors forx - n * ln2into_mm256_fnmadd_ps. The core routinesoftmax_v6then unrolls 8 separate__m256accumulators. The kernel natively handles main loop processing and smoothly falls back to 8-element masked loads and scalar remainders. Validation explicitly confirms the1e-4tolerance is unharmed.📊 Impact:
softmax_v5): ~4.12 GFLOP/s on N=1048576 (Fixed Memory)softmax_v6): ~4.61 GFLOP/s on N=1048576 (Fixed Memory)🖥️ Tested on:
x86-64 CPU, AVX2 + FMA extensions enabled, Ubuntu GCC 13.3.0.
🔬 How to reproduce:
cd build && make -j$(nproc) ml_kernel_bench && ./ml_kernels/ml_kernel_bench --filter "softmax_v6"PR created automatically by Jules for task 4357814967358400920 started by @bugparty
Summary by CodeRabbit