Repository navigation
v0.7 pre-release candidate: benchmark report (v0.7-release @ 5f6ee09) — tree fit instruction regression 4-6% #506
Description
What was measured
The v0.7 pre-release candidate (branch v0.7-release, commit 5f6ee09) was benchmarked with smartcore-benches run 40069239471, dispatched with smartcore_ref=v0.7-release.
- iai-callgrind (instruction counts): deterministic, machine-independent. This is the gate (fails above a 4% increase). Baseline: the published 0.6.16 from crates.io, measured with the same toolchain on the same day. Instruction counts do not depend on the runner, so this comparison is exact.
- criterion (wall clock): advisory. See the note below.
Verification: the run log shows Compiling smartcore v0.7.0 (.../smartcore), so the benches compiled the candidate, not the crates.io release. (Earlier runs did not: see "Harness fixes" below.)
Results: instruction counts (iai-callgrind)
| Benchmark | 0.6.16 | candidate | Change |
|---|---|---|---|
random_forest_regressor::fit_200x10 |
10,325,384 | 10,914,944 | +5.71% |
extra_trees_regressor::fit_200x10 |
7,947,139 | 8,274,337 | +4.12% |
decision_tree_classifier::fit_200x10 |
9,944,096 | 9,944,096 | 0.00% |
random_forest_classifier::fit_200x10 |
31,242,298 | 31,242,298 | 0.00% |
lasso (3 layouts) |
— | — | −0.00% |
elastic_net (3 layouts) |
— | — | +0.01% |
matmul, ab, svd, cover_tree, iterator_mut |
— | — | 0.00% (bit-identical) |
Analysis
The regression is isolated to the regression-tree fit path (BaseTree/BaseForest for regressors). Classifier trees are unchanged and are flat. This matches the code that changed in the candidate:
- Use MSE criterion in base tree regressor #492 (@slievens):
MSECriterionwith a numerically stable improvement formula, plus removal of zero-weight rows. The CHANGELOG documents this as added work per split. - Add feature importances to DecisionTreeRegressor, RandomForestRegressor and ExtraTreesRegressor #497 (@slievens): feature-importance bookkeeping stored during fit.
- Make BaseTree(Regressor) and BaseForest(Regressor) generic over criterion #502 (@slievens): generics over criterion and leaf output; possible code-generation differences.
- feat: add lazy normalization for Lasso and Elastic Net #480 (@jolars, lazy normalization) and feat: make ndarray std support conditional #472 (@mvanhorn, ndarray std) are neutral in the default configuration (±0.01% or less).
Suggested corrections
In order of preference:
- Attribute the cost per PR. Bench Use MSE criterion in base tree regressor #492, Add feature importances to DecisionTreeRegressor, RandomForestRegressor and ExtraTreesRegressor #497 and Make BaseTree(Regressor) and BaseForest(Regressor) generic over criterion #502 one at a time against
main. The +5.71% is the sum; one PR may carry most of it. Use the lazy/eager comparison from the benches README as a template. - Optimize the split loop. Profile the
Criterion::improvementpath (src/tree/criterion.rs, grow loop in `src/tree/base_tree.rs)). The stable formula costs extra operations per candidate split. Candidates: hoist loop-invariant sums, compute the improvement from running sums instead of per-row statistics, or filter zero-weight rows once before the recursion starts instead of per node. - Accept and document. If the cost buys the numerical stability and the feature importances, accept a one-time budget increase for the tree benches and record it in the CHANGELOG. The gate stays at 104% for everything else.
- Revert the tree commits from the candidate (fallback). If the v0.7 timeline is short and the budget cannot be recovered, remove the regression-tree changes and move them to the next cycle. Because all PRs landed through the single squash
cd217dd(v0.7 Release #504), the clean procedure is:Then re-pointgit checkout -b v0.7-release-r2 origin/main git revert cd217dd # removes tree work, lazy normalization, ndarray bump # re-land the neutral parts as a fresh PR: # - #480 lazy normalization (jolars branch feat/lazy-normalization) # - ndarray 0.17.2 requirement # - CHANGELOG [v0.7] entries for the kept changes
v0.7-releaseand re-run the benches.
Criterion note (advisory)
The wall-clock numbers of this run are 8%–45% below the nightly baseline for all benchmarks, including unchanged paths. This is runner variance, not a real speedup. Do not use cross-run criterion numbers for decisions; use the instruction counts above. Within-run comparisons on the same runner are still useful.
Harness fixes (smartcore-benches)
- Before this report, a
smartcore_refrun silently benched the crates.io release (patch was not used in the crate graph), becausesmartcore = \"0.6\"rejected the 0.7.0 patch. Fixed in smartcore-benches#12 (the repoint step now relaxes the version requirement to the ref's major.minor). - The gh-pages history push failed on ref runs because the repoint step edits the tracked
Cargo.toml. Fixed in smartcore-benches#13 (restore before the chart push). This run's results are in the run artifacts; the trend charts do not include it. - The
BENCHES_STATUS_PATsecret is not configured, so status checks cannot post back to smartcore commits. An admin must add it (fine-grained PAT,commit_status:writeonsmartcorelib/smartcore). The step is nowcontinue-on-errorso it cannot fail measurement runs.
Data
- Run: https://github.com/smartcorelib/smartcore-benches/actions/runs/40069239471 (artifact
iai-json, logs contain the full criterion output) - Trend charts: iai-dev · criterion dev
- Candidate ref:
v0.7-release=5f6ee09
Activity
Mec-iS commentedon Oct 24, 2026
@slievens please take a look