A threadUnits of execution that share the memory of their process. Each one can run on its own CPU core. scaling curve shows whether a fitTraining a model on data. More in the scikit-learn glossary got faster, but not why. This dashboard breaks HistGradientBoosting's fit time into its phases (binningMapping each feature to a small number of integer bins (a few hundred at most) before building trees., histogram computationFor each tree node, summing the gradients of the samples in each bin of each feature., split findingScanning the histograms to find the best feature and threshold to split each node.) to see which ones scale.
How to read
There is one tab per machine, buildOne packaging of the same scikit-learn version. Here, builds differ by their BLAS and OpenMP libraries. and thread affinityPinning threads to given CPU cores, so the operating system doesn't move them around. setting, and
one stacked bar per workload. The x-axis is the requested thread count
(OMP_NUM_THREADSEnvironment variable setting how many threads OpenMP code uses.). If a bar stops shrinking or grows as
threads are added, the extra threads bring nothing or cost time, and the segments
show which phase is responsible.
Findings
On the benchmarked cases, adding more threads can be highly counter-productive:
- On the high-end server, the best thread count grows with the workload. The smallest workloads are fastest on 1 thread, medium ones stop scaling after 4 to 8 threads, and the largest after 16 to 64. Past the best thread count, fits get slower, sometimes dramatically: every workload is 2x to 30x slower at 128 or 172 threads than at its best thread count.
- On the laptop, active waitIdle OpenMP threads spin on the CPU for a while before sleeping, so they start the next parallel loop faster, at the cost of CPU time. matters for small and medium workloads. Without active wait (the conda-forgeCommunity-maintained channel of conda packages. Its scikit-learn can be installed with different BLAS and OpenMP libraries. build), they get several times slower at 8 and 16 threads: for instance, covtype goes from 11s on 4 threads to 38s on 8. With it (PyPIThe Python Package Index, where pip installs packages from. Its scikit-learn wheels bundle their own OpenMP runtime, and NumPy and SciPy bundle OpenBLAS.), they stay roughly flat or keep improving up to 8 threads. The largest workloads scale up to 16 threads either way. For details about active wait, see scikit-learn#34764.
- We're working on fixing this. With scikit-learn#34935, using all the threads is rarely much slower than the best thread count.
Hardware
CPU
Intel(R) Core(TM) Ultra X7 358H
X86_64, 16 physical cores, 16 logical CPUs
31 GB RAM
$1,299, released 2026
GPU(s)
level_zero:gpu:0: Intel(R) Arc(TM) B390 GPU (29 GB, integrated, priced with the CPU)
sklearn
Python 3.12.14
Packages
scikit-learn1.9.1 (conda-forge)numpy2.5.3 (conda-forge)scipy1.18.0 (conda-forge)pandas2.3.3 (conda-forge)
Threadpools
- libopenblas 0.3.34 (pthreads, 16 threads)
- libgomp (16 threads)
OpenMP
- GNU libgomp (OpenMP 5.2)
- GOMP_SPINCOUNT: 1
Full environment
XS (1,000 x 10)
S (1,000 x 100)
ames_housing (1,168 x 79)
S-thin (5,000 x 10)
M (20,000 x 50)
amazon_employee_access (26,215 x 9)
kddcup09_churn (40,000 x 207)
M-very-thin (50,000 x 5)
L (100,000 x 100)
L-leaf255 (100,000 x 100)
year_prediction_msd (463,810 x 90)
covtype (464,809 x 12)
L-thin (500,000 x 10)
L-stumps (1,000,000 x 100)
susy (4,500,000 x 18)
Hardware
CPU
Intel(R) Core(TM) Ultra X7 358H
X86_64, 16 physical cores, 16 logical CPUs
31 GB RAM
$1,299, released 2026
GPU(s)
level_zero:gpu:0: Intel(R) Arc(TM) B390 GPU (29 GB, integrated, priced with the CPU)
sklearn
Python 3.12.14
Packages
scikit-learn1.9.1 (pypi)numpy2.5.3 (pypi)scipy1.18.1 (pypi)pandas2.3.3 (pypi)
Threadpools
- libscipy_openblas 0.3.31.dev (pthreads, 16 threads)
- libscipy_openblas 0.3.34.106.0 (pthreads, 16 threads)
- libgomp (16 threads)
OpenMP
- GNU libgomp (OpenMP 4.5)
- GOMP_SPINCOUNT: 300000
Full environment
XS (1,000 x 10)
S (1,000 x 100)
ames_housing (1,168 x 79)
S-thin (5,000 x 10)
M (20,000 x 50)
amazon_employee_access (26,215 x 9)
kddcup09_churn (40,000 x 207)
M-very-thin (50,000 x 5)
L (100,000 x 100)
L-leaf255 (100,000 x 100)
year_prediction_msd (463,810 x 90)
covtype (464,809 x 12)
L-thin (500,000 x 10)
L-stumps (1,000,000 x 100)
susy (4,500,000 x 18)
Where these results come from (1 source)
| Recorded | Hardware | Records | Source | Envs | Config |
|---|---|---|---|---|---|
| 2026-11-03 | Intel Core Ultra desktop | 90 |
Manual run
· ec8228b4 by Arthur Lacote
|
sklearn-cf-default |
configs/hgb_scalability.py |
Hardware
CPU
Intel(R) Core(TM) Ultra 9 285
X86_64, 24 physical cores, 24 logical CPUs
61 GB RAM
GPU(s)
level_zero:gpu:0: Intel(R) Arc(TM) B580 Graphics (12 GB)
sklearn
Python 3.14.8
Packages
scikit-learn1.9.1 (conda-forge)numpy2.5.3 (conda-forge)scipy1.18.1 (conda-forge)pandas2.3.3 (conda-forge)
Threadpools
- libopenblas 0.3.34 (pthreads, 24 threads)
- libgomp (24 threads)
OpenMP
- GNU libgomp (OpenMP 5.2)
- GOMP_SPINCOUNT: 1
Full environment
XS (1,000 x 10)
S (1,000 x 100)
ames_housing (1,168 x 79)
S-thin (5,000 x 10)
M (20,000 x 50)
amazon_employee_access (26,215 x 9)
kddcup09_churn (40,000 x 207)
M-very-thin (50,000 x 5)
L (100,000 x 100)
L-leaf255 (100,000 x 100)
year_prediction_msd (463,810 x 90)
covtype (464,809 x 12)
L-thin (500,000 x 10)
L-stumps (1,000,000 x 100)
susy (4,500,000 x 18)
Where these results come from (1 source)
| Recorded | Hardware | Records | Source | Envs | Config |
|---|---|---|---|---|---|
| 2026-11-03 | Intel Core Ultra desktop | 90 |
Manual run
· ec8228b4 by Arthur Lacote
|
sklearn-pypi |
configs/hgb_scalability.py |
Hardware
CPU
Intel(R) Core(TM) Ultra 9 285
X86_64, 24 physical cores, 24 logical CPUs
61 GB RAM
GPU(s)
level_zero:gpu:0: Intel(R) Arc(TM) B580 Graphics (12 GB)
sklearn
Python 3.14.8
Packages
scikit-learn1.9.1 (pypi)numpy2.5.3 (pypi)scipy1.18.1 (pypi)pandas2.3.3 (pypi)
Threadpools
- libscipy_openblas 0.3.31.dev (pthreads, 24 threads)
- libscipy_openblas 0.3.34.106.0 (pthreads, 24 threads)
- libgomp (24 threads)
OpenMP
- GNU libgomp (OpenMP 4.5)
- GOMP_SPINCOUNT: 300000
Full environment
XS (1,000 x 10)
S (1,000 x 100)
ames_housing (1,168 x 79)
S-thin (5,000 x 10)
M (20,000 x 50)
amazon_employee_access (26,215 x 9)
kddcup09_churn (40,000 x 207)
M-very-thin (50,000 x 5)
L (100,000 x 100)
L-leaf255 (100,000 x 100)
year_prediction_msd (463,810 x 90)
covtype (464,809 x 12)
L-thin (500,000 x 10)
L-stumps (1,000,000 x 100)
susy (4,500,000 x 18)
Hardware
CPU
AMD Ryzen 7 3700X 8-Core Processor
X86_64, 8 physical cores, 16 logical CPUs
16 GB RAM
$1,100, released 2019
GPU(s)
cuda:0: NVIDIA GeForce RTX 2060 (6 GB, priced with the CPU)
sklearn
Python 3.12.14
Packages
scikit-learn1.9.1 (conda-forge)numpy2.5.3 (conda-forge)scipy1.18.0 (conda-forge)pandas2.3.3 (conda-forge)
Threadpools
- libomp (16 threads)
- vcomp (16 threads)
OpenMP
- LLVM OpenMP (spec 201611)
- KMP_BLOCKTIME: 200ms
Full environment
XS (1,000 x 10)
S (1,000 x 100)
ames_housing (1,168 x 79)
S-thin (5,000 x 10)
M (20,000 x 50)
amazon_employee_access (26,215 x 9)
kddcup09_churn (40,000 x 207)
M-very-thin (50,000 x 5)
L (100,000 x 100)
L-leaf255 (100,000 x 100)
year_prediction_msd (463,810 x 90)
covtype (464,809 x 12)
L-thin (500,000 x 10)
L-stumps (1,000,000 x 100)
susy (4,500,000 x 18)
Hardware
CPU
AMD Ryzen 7 3700X 8-Core Processor
X86_64, 8 physical cores, 16 logical CPUs
16 GB RAM
$1,100, released 2019
GPU(s)
cuda:0: NVIDIA GeForce RTX 2060 (6 GB, priced with the CPU)
sklearn
Python 3.12.14
Packages
scikit-learn1.9.1 (pypi)numpy2.5.3 (pypi)scipy1.18.1 (pypi)pandas2.3.3 (pypi)
Threadpools
- libscipy_openblas 0.3.31.dev (pthreads, 16 threads)
- libscipy_openblas 0.3.34.106.0 (pthreads, 16 threads)
- vcomp (16 threads)
Full environment
XS (1,000 x 10)
S (1,000 x 100)
ames_housing (1,168 x 79)
S-thin (5,000 x 10)
M (20,000 x 50)
amazon_employee_access (26,215 x 9)
kddcup09_churn (40,000 x 207)
M-very-thin (50,000 x 5)
L (100,000 x 100)
L-leaf255 (100,000 x 100)
year_prediction_msd (463,810 x 90)
covtype (464,809 x 12)
L-thin (500,000 x 10)
L-stumps (1,000,000 x 100)
susy (4,500,000 x 18)
Hardware
CPU
Intel(R) Xeon(R) 6787P
X86_64, 172 physical cores, 344 logical CPUs
499 GB RAM
$11,648, released 2025
GPU(s)
No GPU detected.
sklearn
Python 3.12.14
Packages
scikit-learn1.9.1 (conda-forge)numpy2.5.3 (conda-forge)scipy1.18.0 (conda-forge)pandas2.3.3 (conda-forge)
Threadpools
- libopenblas 0.3.34 (pthreads, 128 threads)
- libgomp (344 threads)
OpenMP
- GNU libgomp (OpenMP 5.2)
- GOMP_SPINCOUNT: 300000
Full environment
XS (1,000 x 10)
S (1,000 x 100)
ames_housing (1,168 x 79)
S-thin (5,000 x 10)
M (20,000 x 50)
amazon_employee_access (26,215 x 9)
kddcup09_churn (40,000 x 207)
M-very-thin (50,000 x 5)
L-leaf255 (100,000 x 100)
L (100,000 x 100)
year_prediction_msd (463,810 x 90)
covtype (464,809 x 12)
L-thin (500,000 x 10)
L-stumps (1,000,000 x 100)
susy (4,500,000 x 18)
Hardware
CPU
Intel(R) Xeon(R) 6787P
X86_64, 172 physical cores, 344 logical CPUs
499 GB RAM
$11,648, released 2025
GPU(s)
No GPU detected.
sklearn
Python 3.12.14
Packages
scikit-learn1.9.1 (pypi)numpy2.5.3 (pypi)scipy1.18.1 (pypi)pandas2.3.3 (pypi)
Threadpools
- libscipy_openblas 0.3.31.dev (pthreads, 64 threads)
- libscipy_openblas 0.3.34.106.0 (pthreads, 64 threads)
- libgomp (344 threads)
OpenMP
- GNU libgomp (OpenMP 4.5)
- GOMP_SPINCOUNT: 300000