Skip to content

⚡ Thunderbolt: Softmax — AVX2 8x Unrolling#80

Open
bugparty wants to merge 1 commit into
mainfrom
thunderbolt-softmax-8x-17337070163629464084
Open

⚡ Thunderbolt: Softmax — AVX2 8x Unrolling#80
bugparty wants to merge 1 commit into
mainfrom
thunderbolt-softmax-8x-17337070163629464084

Conversation

@bugparty

@bugparty bugparty commented Jul 17, 2026

Copy link
Copy Markdown
Owner

💡 What: Implemented softmax_v6 utilizing an 8x unrolled structure to parallelize compute.
🎯 Why: Max reduction and exp approximations are bounded by instruction latencies (like the 4-cycle max and add) rather than throughput when unrolled only 4x. 8x perfectly saturates these.
🏗️ How: By interleaving 8 independent accumulators and Horner chains for exp across all three kernel phases without spilling YMM.
📊 Impact: ~6% throughput over softmax_v5 on large workloads (N=1048576, Fixed Memory).
🖥️ Tested on: Standard test runner VM w/ GCC 13.
🔬 How to reproduce: cd build && DISABLE_CPU_BINDING=1 ./ml_kernels/ml_kernel_bench --filter "softmax_v[56]"


PR created automatically by Jules for task 17337070163629464084 started by @bugparty

Summary by CodeRabbit

  • New Features

    • Added an optimized AVX2 softmax implementation for improved processing of larger inputs.
    • Added benchmarking support for comparing the new softmax variant.
  • Bug Fixes

    • Added validation to confirm accurate softmax results and normalized output totals.
  • Documentation

    • Documented performance findings and guidance for AVX2 softmax optimization.

💡 What: Implemented `softmax_v6` utilizing an 8x unrolled structure to parallelize compute.
🎯 Why: Max reduction and exp approximations are bounded by instruction latencies (like the 4-cycle max and add) rather than throughput when unrolled only 4x. 8x perfectly saturates these.
🏗️ How: By interleaving 8 independent accumulators and Horner chains for exp across all three kernel phases without spilling YMM.
📊 Impact: ~6% throughput over `softmax_v5` on large workloads (N=1048576, Fixed Memory).
🖥️ Tested on: Standard test runner VM w/ GCC 13.
🔬 How to reproduce: `cd build && DISABLE_CPU_BINDING=1 ./ml_kernels/ml_kernel_bench --filter "softmax_v[56]"`

Co-authored-by: bugparty <1510776+bugparty@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 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 @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds softmax_v6, an AVX2 softmax implementation with 64-element unrolled phases, benchmark registration, numerical validation, and documentation of the 8x-unrolling performance observation.

Changes

Softmax v6

Layer / File(s) Summary
8x-unrolled AVX2 kernel
ml_kernels/include/ml_kernels/softmax.h
Adds softmax_v6 with vectorized max reduction, exponentiation, sum accumulation, normalization, and 8-element/scalar tails.
Benchmark, validation, and performance note
ml_kernels/src/kernel_bench.cpp, ml_kernels/src/test_naive_ops.cpp, .jules/thunderbolt.md
Registers the new benchmark, compares results with softmax_naive, checks normalization, and records the 8x-unrolling observation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Benchmark
  participant softmax_v6
  participant Test
  participant softmax_naive

  Benchmark->>softmax_v6: Run benchmark on input/output buffers
  Test->>softmax_naive: Compute reference output
  Test->>softmax_v6: Compute optimized output
  softmax_v6-->>Test: Return vectorized output
  Test->>Test: Compare elements and output sum
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: an AVX2 softmax implementation with 8x unrolling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch thunderbolt-softmax-8x-17337070163629464084

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
ml_kernels/src/test_naive_ops.cpp (1)

196-205: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add elements to test the scalar tail.

The input array currently has exactly 96 elements (a multiple of 8). This completely bypasses the scalar tail loops (i < n) in the softmax_v6 implementation. Adding a few extra elements will ensure that these boundary condition fallback paths are properly exercised.

🧪 Proposed fix to increase coverage
         1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
         1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-        1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
+        1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
+        // Add elements to trigger the scalar tail (not a multiple of 8)
+        2.0f, -1.0f, 0.5f
     };
🤖 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/src/test_naive_ops.cpp` around lines 196 - 205, Extend the input
array in the test around softmax_v6 beyond its current 96 elements by adding a
few additional values, ensuring the test length is not divisible by the vector
width of 8 and exercises the scalar tail loop while preserving the existing test
setup.
.jules/thunderbolt.md (1)

36-36: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix typographical error.

The phrase "map-reduce map math kernels" contains a redundant "map". Consider simplifying it to "map-reduce math kernels" for clarity.

🔤 Proposed fix
-**Action:** Default to 8x unrolling across all phases for multi-pass map-reduce map math kernels (like softmax) when using `_mm256_max_ps` and `_mm256_add_ps` to perfectly match their 4-cycle latency and hide FMA chains, without risking register spilling since YMM allows 16 registers.
+**Action:** Default to 8x unrolling across all phases for multi-pass map-reduce math kernels (like softmax) when using `_mm256_max_ps` and `_mm256_add_ps` to perfectly match their 4-cycle latency and hide FMA chains, without risking register spilling since YMM allows 16 registers.
🤖 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 @.jules/thunderbolt.md at line 36, Correct the wording in the multi-pass
kernel guidance by changing “map-reduce map math kernels” to “map-reduce math
kernels,” leaving the rest of the unrolling and instruction details unchanged.
🤖 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 @.jules/thunderbolt.md:
- Line 36: Correct the wording in the multi-pass kernel guidance by changing
“map-reduce map math kernels” to “map-reduce math kernels,” leaving the rest of
the unrolling and instruction details unchanged.

In `@ml_kernels/src/test_naive_ops.cpp`:
- Around line 196-205: Extend the input array in the test around softmax_v6
beyond its current 96 elements by adding a few additional values, ensuring the
test length is not divisible by the vector width of 8 and exercises the scalar
tail loop while preserving the existing test setup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8be6b1e7-82a6-46b1-88ea-318b9b45f729

📥 Commits

Reviewing files that changed from the base of the PR and between acca01e and cbc1978.

📒 Files selected for processing (4)
  • .jules/thunderbolt.md
  • ml_kernels/include/ml_kernels/softmax.h
  • ml_kernels/src/kernel_bench.cpp
  • ml_kernels/src/test_naive_ops.cpp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant