Skip to content

perf: skip unsampled histogram bins and accelerate small-batch prediction - #177

Merged
brndnmtthws merged 1 commit into
mainfrom
perf/cpu-training-inference
Oct 22, 2026
Merged

brndnmtthws merged 1 commit into
mainfrom
perf/cpu-training-inference

Conversation

@brndnmtthws

@brndnmtthws brndnmtthws commented Oct 22, 2026 •

Copy link
Copy Markdown
Owner

What changed

Two targeted CPU optimizations, with the existing numerical contracts intact:

  • Build dense chain-order histograms only for the tree's sampled feature pool. Sweep up to four selected columns together, avoid per-feature scheduling on small nodes, and subtract only the pool's sibling bins. Level/node sampling stays inside that pool. Sparse and fixed-block builds retain the existing path; other backends inherit a full-build fallback.
  • Route margin batches below 16 rows through the existing optimized RowForest used by single-row APIs, rather than the older CompactForest row traversal. Preserve per-row base margins, iteration ranges, DART weights and output order. Wide CSR and shrinkage paths stay unchanged.

No SIMD changes, floating-point reassociation, public configuration changes or model-format changes. Default full-feature training is not the target of the histogram optimization.

Before / after

Baseline: f6c5d8f (v0.4.1).
Rust 1.99.1 / LLVM 23.1.1, release profile, default features, no extra RUSTFLAGS.
Shared virtualized x86-64 cloud host exposing AMD EPYC 9V74 and nine logical CPUs. This is not a dedicated 80-core host, and these results do not generalize to other hardware.

Medians from serial baseline/candidate/candidate/baseline runs, ten samples per binary. Each process discards a warmup. Small-batch samples average 1,000 calls. Full raw samples, min/max ranges, binary hashes and reproduction instructions are in the benchmark report.

Workload Threads Before After Speedup
Warm hist training, 20k×128, 30 rounds, colsample=0.25 1 262.26 ms 106.79 ms 2.46×
Same 4 144.95 ms 71.24 ms 2.03×
Same, fresh matrix + binning included 1 347.47 ms 204.65 ms 1.70×
Same 4 164.30 ms 101.25 ms 1.62×
Predict 1 row, 100 trees 1 1.222 µs 0.699 µs 1.75×
Predict 8 rows, 100 trees 1 9.995 µs 5.308 µs 1.88×
Predict 15 rows, 100 trees 1 18.492 µs 9.919 µs 1.86×

Synthetic deterministic regression data, depth 6, 256 bins, eta=0.1. Small-batch models train on 10k×30 rows. Warm training reuses cached bins; cold includes DMatrix construction and binning. Prediction excludes model training and lazy layout construction. Serialized-model and prediction checksums agree across both binaries, every repeat and thread count.

Controls and limitations

Full-feature training and 16-row batches are near parity. Initial four-thread large-batch prediction and 80%-feature training runs were noisy and showed overlapping slowdowns. Both initial results are retained. A 50-sample-per-binary follow-up gave:

Control, 4 threads Before After
Large-batch prediction, 100k rows 10.78 ms 10.25 ms
Full-feature training 118.96 ms 117.44 ms
80%-feature wide training 172.93 ms 143.46 ms

No large-batch prediction win is claimed. Broad-pool training is less stable than the 25%-feature case. Missing-data fallback is also measured in the full report. Single-row APIs already used RowForest, so this does not claim to speed those up. An eight-lane x86 batch-walk experiment regressed and was dropped.

Validation

  • 963 tests/doctests passed with RAYON_NUM_THREADS=4 cargo test --profile ci --all-features; five intentionally ignored tests remain ignored.
  • All-target/all-feature clippy with warnings denied, rustdoc with warnings denied, root/fuzz/CUDA rustfmt, and the runner's Ruff/ty checks passed.
  • New bitwise histogram tests cover NaNs, U8/U16 columns, irregular/repeated rows, blocked/sparse fallback, default backends, poisoned unused bins and thread/growth-policy equivalence.
  • Small-batch tests cover dense/borrowed/sentinel/CSR/gathered input, base margins, iteration ranges and existing scalar/multiclass/vector/linear/DART model cases.
  • Independent correctness review found no blockers.

GPU-dependent tests skip without a usable device. No actual GPU execution, Arm runtime measurement, Python-extension rebuild or external XGBoost/LightGBM fixture generation was done locally. CI passed all 25 jobs on published head a74a7ec35e1fea7c2b82971ad1378bfb7432047c, including Rust tests on x86 Linux/Arm Linux/macOS, MSRV, semver compatibility, XGBoost/LightGBM parity, Python wheels and sdist, CUDA build checks, and fuzz smoke.

@brndnmtthws
brndnmtthws marked this pull request as ready for review October 22, 2026 14:26
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

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

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-22T14:28:12.328982Z a74a7ec Draft marked ready
🔒 Security Review ✅ Completed 2026-10-22T14:28:59.438286Z a74a7ec Draft marked ready
ℹ️ 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.

@brndnmtthws
brndnmtthws merged commit d7b6a1e into main Oct 22, 2026
25 checks passed
@brndnmtthws
brndnmtthws deleted the perf/cpu-training-inference branch October 22, 2026 14:29
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