Skip to content

Prototype: weighted-static partitioning for heterogeneous cores#941

Draft
jeffhammond wants to merge 1 commit into
flame:masterfrom
jeffhammond:feature/hetero-sched
Draft

Prototype: weighted-static partitioning for heterogeneous cores#941
jeffhammond wants to merge 1 commit into
flame:masterfrom
jeffhammond:feature/hetero-sched

Conversation

@jeffhammond

Copy link
Copy Markdown
Member

On a heterogeneous machine (e.g. NVIDIA GB10's Cortex-X925 + Cortex-A725 clusters) a single level-3 op loses much of its throughput to barrier sync: the equal static loop split gives every thread the same work, so the fast cores idle at each pack/compute barrier waiting for the slow ones (all-20 DGEMM: ~380 vs ~890 GFLOP/s). This partitions the dense forward loop range in proportion to each thread's core throughput instead of equally, so all threads finish each phase together.

Hooked into the unweighted branch of bli_thread_range() (where trsm/syrk's triangular weighting already lives). The weight is per datatype (measured X925:A725 GEMM optima: s 4.2 d 3.6 c 4.0 z 4.4). Compile-gated by BLIS_ENABLE_HETERO_SCHED; runtime-gated by env BLIS_HETERO_WEIGHT ("auto" = per-datatype table, a number = fixed weight, unset = disabled), so default builds are unchanged. Measured ~2.2-2.5x over the equal split across s/d/c/z; GEMM stays bit-correct (the split only chooses which rows a thread owns).

PROTOTYPE limitations: assumes the loop work_id equals the logical CPU it runs on (holds for a pinned 1D-IC layout) and hardcodes the GB10 X925 CPU set. A production version should derive per-work_id core identity from sched_getcpu() gathered through the thread communicator, so it holds for any factorization and pinning.

On a heterogeneous machine (e.g. NVIDIA GB10's Cortex-X925 + Cortex-A725
clusters) a single level-3 op loses much of its throughput to barrier sync:
the equal static loop split gives every thread the same work, so the fast
cores idle at each pack/compute barrier waiting for the slow ones (all-20
DGEMM: ~380 vs ~890 GFLOP/s). This partitions the dense forward loop range
in proportion to each thread's core throughput instead of equally, so all
threads finish each phase together.

Hooked into the unweighted branch of bli_thread_range() (where trsm/syrk's
triangular weighting already lives). The weight is per datatype (measured
X925:A725 GEMM optima: s 4.2 d 3.6 c 4.0 z 4.4). Compile-gated by
BLIS_ENABLE_HETERO_SCHED; runtime-gated by env BLIS_HETERO_WEIGHT
("auto" = per-datatype table, a number = fixed weight, unset = disabled),
so default builds are unchanged. Measured ~2.2-2.5x over the equal split
across s/d/c/z; GEMM stays bit-correct (the split only chooses which rows a
thread owns).

PROTOTYPE limitations: assumes the loop work_id equals the logical CPU it
runs on (holds for a pinned 1D-IC layout) and hardcodes the GB10 X925 CPU
set. A production version should derive per-work_id core identity from
sched_getcpu() gathered through the thread communicator, so it holds for any
factorization and pinning.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeffhammond
jeffhammond marked this pull request as draft July 16, 2026 15:23
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