Skip to content

feat(ml): thread primitive + train_hslm windows on N threads, bit-identical at any count (#10876) - #10896

Open
gHashTag wants to merge 7 commits into
masterfrom
claude/hslm-threads
Open

gHashTag wants to merge 7 commits into
masterfrom
claude/hslm-threads

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Closes #10876

What

Lever (a) of #10850: the 66 windows of one tr_train_step_k step run on N worker threads instead of one.

  • Compiler (thin Rust): threadlocal var form and thread_spawn / thread_join / thread_cores builtins for --backend ml (bootstrap/src/compiler.rs, +40/-47, dead code deleted; FROZEN_HASH moved).
  • Spec proving the primitive: specs/ml/thread_model.t27 (6 tests; parts on N threads sum bit-identically to the fixed-order sum, per-thread state starts at its initializer and does not leak).
  • specs/ml/train_hslm.t27: cfg key threads (default = cores, threads=1 is the serial path). Each window writes its own gradient slot in win_g; slots are summed in window order, so the result does not depend on the thread count. nn/hslm state and the b3_* scratch arrays are threadlocal. New test one_two_and_three_threads_give_one_step_the_same_bits_at_speed_2_and_3.

Association change (stated, not hidden)

The old step kept one running sum over windows. The new step sums per-window slots in fixed window order. Floating-point addition is not associative, so:

  • at k = 1 window per step the result is bit-equal to the old one;
  • at k > 1 it differs from the old binary: state hash 240eb9893ad8eba1 (old) vs a9f594b18f9fc17e (new). Loss agrees to 4 digits (train 6.5916, valid 6.5637) and the .bin hash is the same.

The new value is the same for every thread count, which is the point: determinism no longer depends on the machine.

Lab proof (Railway lab, 48 cores, 8 steps, seed 1729, loaded: load average 55-72 during the runs, so these are floors)

State hash after 8 steps, sha256(ckpt_8.state)[:16]: a9f594b18f9fc17e at threads = 1, 2, 4, 8, 16, 24, 48, at speed 2 and at speed 3. Loss identical at every count.

threads speed=2 tok/s speed=3 tok/s
old binary 244.6 484.1
1 238.1 / 245.6 407.3
2 470.8 773.1
4 750.7 1312.7
8 1095.8 1820.7
16 1322.4 1960.9
24 1488.1 1730.1
48 1166.6 1033.8

Speed-up at 16 threads: 5.4x at speed 2, 4.1x vs the old speed-3 binary. Past 24 threads the lab is oversubscribed (load > 48) and throughput falls.

Known costs

  • threads=1 at speed=3 is about 16% slower than the old binary (407 vs 484 tok/s): thread-local access on the b3_* scratch. At speed 2 it is level (238-246 vs 245). Not fixed here; a follow-up.
  • A Debug build wrote undefined as 0xaa into .data, 1.1 GB for win_g. win_g now starts from a zero initializer (.bss), .data is 178 MB.
  • specs/ml/eval_hslm.t27 is BLOCKED (use of undeclared identifier 'b3_q'). Inherited from spec(ml): train_hslm speed=3 -- one matrix over the 27 positions, bit-identical to speed=2 (Closes #10849) #10866 (it fails at this PR's base too), not caused here; follow-up.

Stack

This branch contains the commits of #10857 (issue #10850) until that merges; the diff of this PR alone is the thread work.

Tests on the lab: thread_model 6/6, train_hslm 30/30, t27t 17/17, ngram_hslm 8/8, all with 0 vacuous passes. Seals saved for ml_train_hslm and ml_thread_model.

🤖 Generated with Claude Code

gHashTag and others added 5 commits October 19, 2026 12:38
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nds (#10850)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…now std.os.linux.timespec (#10850)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… threads (#10876)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-19 06:38:10 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 46
PRs with All Checks Green 4
READY 3
FAILING 46
PENDING 0
NO CHECKS YET 0

These columns do not partition: 3 + 46 + 0 + 0 = 49, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=509db03c8f4d != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

gHashTag and others added 2 commits October 19, 2026 14:41
…in_hslm.t27 and its seal kept at the thread version)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

ml backend: threadlocal var + thread_spawn/join, and train_hslm windows on N threads with a fixed-order gradient sum

1 participant