Skip to content

Add a strided-A entry to the BF16 tile GEMM - #414

Merged
AdaWorldAPI merged 1 commit into
masterfrom
ccr-8062bcc7-l7lkz9-strided
Nov 8, 2026
Merged

AdaWorldAPI merged 1 commit into
masterfrom
ccr-8062bcc7-l7lkz9-strided

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

Problem

bf16_tile_gemm_16x16_packed accepts A only as a dense 16 × K buffer. An A operand that is already in memory with a different row pitch has to be copied before the call. For example, 16 equally spaced bf16 lanes of one slab, with row = lane and column = position within the lane.

The AMX hardware does not need that copy. TILELOADD takes the row stride as an operand. amx_path hardcoded a_stride = k * 2, so the limit came from the API.

Change

  • New bf16_tile_gemm_16x16_packed_strided(a, a_row_stride, b, c): row i of A is a[i·a_row_stride..][..K].
  • Tiers:
    • AMX TDPBF16PS and AVX-512 VDPBF16PS read A in place.
    • The decode+FMA polyfill gathers the 16 rows into a dense buffer, since that kernel consumes dense rows.
  • Checked preconditions: a_row_stride >= K and a.len() >= 15·a_row_stride + K.
  • Existing entries are unchanged. The three tier kernels now take the stride as a parameter. bf16_tile_gemm_16x16 and _packed pass K.
  • Re-exported from ndarray::simd next to _packed.

Validation

Granite Rapids host, amx_available() = true, reported by examples/amx_probe.

  • strided_entry_reads_rows_in_place_exactly: exact integer parity at pitches K, K+1, K+32 and 4K+7. Each gap is filled with a sentinel value.
  • strided_rows_are_exact_on_every_tier_this_host_has: drives the AMX, AVX-512 and gather tiers directly. A host's dispatch reaches only one of them. All three ran here; none printed SKIP.
  • strided_entry_does_not_read_the_gap: shows that a dense misread of the same slab gives a different result, so the fixture can tell pitch from K.
  • Two should_panic tests: a stride shorter than K, and a buffer that is too short.
  • Disable run: restoring a_stride = k * 2 in amx_path fails exactly the two strided parity tests (12 pass, 2 fail).
  • cargo clippy --lib --tests -D warnings and the facet-stride guard (--diff origin/master) are both clean, and the new doctest passes.

Why now

This came out of a lab that feeds source-owned SoA lanes, addressed through lance-graph's DR coordinates, into a BF16 GEMM. Without this entry, a slab of equally spaced bf16 lanes could not be loaded as an AMX A tile without staging.


Generated by Claude Code

bf16_tile_gemm_16x16_packed requires A as a dense 16xK buffer, so an A
that already lives in memory with another row pitch (for example 16
equally spaced bf16 lanes of one slab) had to be copied first. TILELOADD
takes the row stride as an operand, so the copy was an API limit, not a
hardware one.

bf16_tile_gemm_16x16_packed_strided reads row i at a[i*stride..][..K].
The AMX and AVX-512 tiers read in place; the decode+FMA tier gathers the
16 rows. The tier kernels take the stride, and the existing entries pass
K, so their behaviour is unchanged. Tests cover every tier this host
has, a fixture whose gap a dense misread would pick up, and the stride
and length checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMWgnUU9g7Ldyn6sbk
@coderabbitai

coderabbitai Bot commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 708c3926-f0f8-4f3d-aec8-b9a125c36877
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review November 8, 2026 00:15
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 8, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-08T00:42:36.755741Z 566dfdc Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a632f30c3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/hpc/bf16_tile_gemm.rs Resolved

Copy link
Copy Markdown
Owner Author

@codex review


Generated by Claude Code

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a632f30c3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/hpc/bf16_tile_gemm.rs Resolved
@AdaWorldAPI
AdaWorldAPI merged commit 566dfdc into master Nov 8, 2026
31 checks passed

Copy link
Copy Markdown
Owner Author

Added a second commit, 727342c: BF16::slice_from_bits and BF16::bits_of_slice, two zero-copy views between &[u16] bf16 encodings and &[BF16].

The tile GEMM takes &[u16] and the MKL backend takes BF16 views. Without these views, feeding one source-owned lane to both needed either a copy or an unsafe cast in the consumer. The cast now lives here, beside the #[repr(transparent)] it relies on. A unit test checks that each view aliases the same memory, and both functions have doctests.

The consumer is AdaWorldAPI/lance-graph#1984. There MKL reads the slab in place as a strided view with lda = pitch, and its result is exact against a CSR oracle.

@codex review


Generated by Claude Code

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 566dfdc3a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Owner Author

I reverted the BF16 slice-view commit, so this PR is back to the strided-A entry alone. The views existed only so upstream mkl_rt could read a u16 slab in place. The consumer now uses ndarray's own backend::cblas_gemm_bf16bf16f32, which takes &[u16].

A finding on that entry, measured in AdaWorldAPI/lance-graph#1984 (BENCH.md): it is about 20× slower than bf16_tile_gemm_16x16_packed_strided on the same 16 × 65,536 × 16 problem (3.4 ms against 172 µs, AMX host). The cause is in the call path:

  • matmul_bf16_to_f32 copies both operands with pack_contig.
  • It then calls bf16_tile_gemm_16x16 for every 16 × 16 output tile.
  • bf16_tile_gemm_16x16 VNNI-packs B and allocates on each call.

So the CBLAS-compatible entry repacks everything on every call. A prepacked-B or strided variant would close the gap. That belongs in its own PR, not this one.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Both post-merge Codex P2s on this PR (the fallback tier asserting a.len() == 16*k against a longer strided or sliced A, and k == 0 with a nonzero stride) are fixed in #415. Each has a test that was red before the fix and green after.

They were also the cause of the dr-isa-stream-lab CI failure on lance-graph #1983/#1984. That runner has no AMX, so the lab fell to the fallback tier and hit A must be 16xK BF16 row-major (131072 vs 65536). With #415 and the fallback forced on an AMX host, all 27 lab tests pass.


Generated by Claude Code

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.

2 participants