Skip to content

build: Linux/aarch64 branch in the Makefile — probe DOTPROD/I8MM instead of trusting native (#631) - #755

Merged
JustVugg merged 1 commit into
JustVugg:devfrom
anrasi:fix/makefile-linux-aarch64
Aug 1, 2026
Merged

build: Linux/aarch64 branch in the Makefile — probe DOTPROD/I8MM instead of trusting native (#631)#755
JustVugg merged 1 commit into
JustVugg:devfrom
anrasi:fix/makefile-linux-aarch64

Conversation

@anrasi

@anrasi anrasi commented Aug 1, 2026

Copy link
Copy Markdown

Problem

#631 reported it precisely: on Linux/aarch64 there is no dedicated branch in
c/Makefile, so ARM falls through to the x86-64 else and gets
-march=native. On a gcc that does not recognise the core — gcc 13.3 vs
Cortex-X925 on a DGX Spark GB10, but any gcc older than its silicon qualifies —
native silently degrades to plain armv8-a: neither __ARM_FEATURE_DOTPROD
nor __ARM_FEATURE_MATMUL_INT8 is defined, the SDOT/SMMLA int8-int4 kernels
compile out with no warning, and the banner reads idot: neon.

The nastiest part is quiet: without DOTPROD, g_i4s initialises to 2
(c/quant.h:531-541), so the S>=g_i4s gate at c/colibri.c:883 sends
int4 S=1 decode — the token-generation hot path — to the f32 fallback.

-mcpu=native would not help: as #631's table shows, it degrades identically
on this toolchain, so extending the Darwin branch's approach to Linux is not
enough.

Fix

A Linux/*BSD aarch64 branch next to the PowerPC one. For the default
ARCH=native it probes the compiler once:

  1. If -mcpu=native already defines __ARM_FEATURE_MATMUL_INT8, use it
    unchanged (a gcc that knows the core keeps full native tuning).
  2. Otherwise, re-add the features the silicon itself reports in
    /proc/cpuinfo (asimddp+dotprod, i8mm+i8mm) as
    -march=armv8-a+… — kept only if this compiler accepts the modifiers
    (gcc < 10 has no +i8mm; composing blindly would turn a slow build into a
    broken one). If it doesn't, fall back to -mcpu=native and say so with a
    $(warning) — the current behaviour, minus the silence.

An explicit ARCH= is respected verbatim: armv* values go to -march,
core names to -mcpu (same convention as the Darwin branch). On *BSD there is
no /proc/cpuinfo, so the probe degrades gracefully to -mcpu=native.
Cross-compilers keep passing an explicit ARCH= exactly as before — the probe
only fires on the native default, where host = target is already assumed.

x86-64, Darwin, Windows and PowerPC branches are untouched.

Validation (DGX Spark GB10, Ubuntu 24.04, gcc 13.3.0, on top of current dev)

Flag selection, all paths:

invocation flags chosen
make (default) -march=armv8-a+dotprod+i8mm (probe)
make ARCH=armv8.6-a+i8mm -march=armv8.6-a+i8mm
make ARCH=cortex-a76 -mcpu=cortex-a76
make with a gcc that rejects +i8mm (simulated gcc 9) -mcpu=native + explicit warning

Resulting default binary, same source, same compiler as #631's evidence:

$ make clean && make
$ objdump -d colibri | grep -c smmla
22        # was 0 before this patch
$ strings colibri | grep -o 'idot: .*'
idot: neon-i8mm ==

make check green on this branch on top of current dev: all C test
binaries + 273 Python tests OK (34 skipped) — every test binary visibly
compiled with the probed -march=armv8-a+dotprod+i8mm.

Kernel-level effect of the recovered instructions at the GLM-5.2 744B expert
shapes (matmul_qt_ex, 2048×6144 / 6144×2048, best-of-3 windows, idle
machine, 2 interleaved rounds — generic-armv8-a build vs this patch's default):

shape before (GF/s) after (GF/s) Δ
gate/up int8 S=8 ~243 ~274 1.13×
gate/up int4 S=8 ~178 ~223 1.26×
down int8 S=8 ~269 ~296 1.10×
down int4 S=8 ~186 ~241 1.30×
gate/up int8 S=1 (decode) ~95 ~126 ~1.3×
gate/up int4 S=1 (decode) ~36 ~91 ~2.5× (leaves the f32 fallback)

As #631 notes, the published GB10 rows in docs/benchmarks.md were measured
matmul-bound and likely predate (or missed) the i8mm kernels; happy to
contribute a re-measured row from this box in a follow-up if useful.

Credit: the root-cause analysis is @james-fwai's in #631 — this PR adds the
fix that issue was closed without.

Closes #631.

…'t trust native (JustVugg#631)

On Linux ARM the Makefile fell through to the x86-64 else: -march=native on
a gcc that doesn't know the core (gcc 13 vs Cortex-X925) silently degrades
to plain armv8-a, the SDOT/SMMLA int8-int4 kernels compile out, and int4
S=1 decode lands on the f32 fallback (g_i4s=2 without DOTPROD).

New branch, default ARCH=native: keep -mcpu=native if it already defines
__ARM_FEATURE_MATMUL_INT8; otherwise re-add the features /proc/cpuinfo
reports (asimddp -> +dotprod, i8mm -> +i8mm) as -march=armv8-a+..., kept
only if the compiler accepts the modifiers (gcc < 10 has no +i8mm), else
fall back to -mcpu=native with a warning. Explicit ARCH= respected: armv*
-> -march, core names -> -mcpu, same convention as the Darwin branch.

GB10 default build: 0 -> 22 smmla, banner idot: neon-i8mm, int4 S=1
decode kernel ~2.5x.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@JustVugg

JustVugg commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Merging. This is a good catch on a failure mode that is worse than being slow: it is being slow silently.

-mcpu=native degrading to plain armv8-a when the compiler does not recognise the core means the SDOT/SMMLA kernels compile out, the banner prints idot: neon, and int4 S=1 decode quietly falls back to f32. Nothing errors. Nobody knows. That is the same class as the two bugs we fixed this week — engines that stopped compiling on Windows for months, and a READY sentinel mangled by the CRT — where the absence of a complaint was mistaken for the absence of a problem.

What I checked:

  • The whole branch is inside ifneq (,$(AARCH64)), and AARCH64 := $(filter aarch64 arm64,$(TARGET_CPU)), so x86 and Windows paths are untouched. Verified by building here on x86-64: colibri and kimi_k3 both clean.
  • You do not compose flags blindly — -march=armv8-a$(ARCH_EXT) is only adopted if the compiler actually defines the feature macros afterwards. That matters: gcc < 10 has no +i8mm, and blindly appending it would turn a slow build into a broken one.
  • The fallback warns rather than silently accepting less. That is the whole point of the PR and it would have been easy to leave out.

Reading /proc/cpuinfo Features for asimddp/i8mm is the right source — it is what the silicon reports, not what the compiler guessed.

Nice first contribution, and thank you for the datapoints on #165 as well. If you have the GB10 in front of you, a before/after idot: line from the banner plus decode tok/s would be worth adding to #631 — it turns "this should help" into a number, and yours is the hardware where the bug bites.

@JustVugg
JustVugg merged commit b6f4dfc into JustVugg:dev Aug 1, 2026
13 checks passed
@JustVugg JustVugg added hardware-owner-needed Serve verifica su silicio specifico performance Velocità / tok-s / ottimizzazioni labels Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hardware-owner-needed Serve verifica su silicio specifico performance Velocità / tok-s / ottimizzazioni

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants