This dashboard shows how the wall-clock timeElapsed real time, as opposed to CPU time, which sums the time of all threads. of a single .fit()Training a model on data. More in the scikit-learn glossary call changes with the number of CPU coresOne hardware core of the CPU. With SMT, it shows up as two logical CPUs..

How to read

Each tab is a machine and each plot an (estimator, dataset) pair, with one line per software environmentOne Pixi environment of this repository: a fixed set of package versions and builds.. The x-axis is in log scale. For tree models, the y-axis is in log scale too, and each environment has a grey dashed perfect-scaling lineThe time the fit would take if n times more cores made it n times faster. starting from its first point, so the gap to it is the lost efficiency. Look for curves that flatten or go up. On machines with hyper-threadingSimultaneous multithreading, called hyper-threading by Intel: one physical core runs two threads at once by sharing its execution units., the 0.5 point of the non-tree models is a single logical CPUWhat the operating system sees as one CPU. With SMT, each physical core shows up as two logical CPUs., without its SMT siblingThe other logical CPU of the same physical core., so the step from 0.5 to 1 shows what SMTSimultaneous multithreading, called hyper-threading by Intel: one physical core runs two threads at once by sharing its execution units. brings on one core. For RandomForest and ExtraTrees, a section below compares runs with and without SMT, one plot per environment.

Findings

On the benchmarked cases:

  • RandomForest and ExtraTrees scale best, up to the 172 cores of the Xeon server. scikit-learn-intelex makes RandomForest several times faster, but doesn't scale better. On the laptop, the gains get smaller past 4 cores, probably because the other cores are slower E-coresEfficiency cores: smaller and slower cores that recent Intel laptop CPUs have next to their fast performance cores..
  • Ridge, LogisticRegression and KMeans with scikit-learn stop scaling after a few cores, and can get slower with more cores on the Xeon server.
  • scikit-learn-intelex scales these three models much further, but on the Xeon server, they get slower past 16 to 64 cores.
  • With the PyPIThe Python Package Index, where pip installs packages from. Its scikit-learn wheels bundle their own OpenMP runtime, and NumPy and SciPy bundle OpenBLAS. build, LogisticRegression gets slower as soon as it runs on more than one logical CPUWhat the operating system sees as one CPU. With SMT, each physical core shows up as two logical CPUs.. The OpenBLASOpen-source BLAS implementation. The NumPy and SciPy wheels on PyPI each ship their own copy of it. shipped with scipy 1.18 wakes all its threadsUnits of execution that share the memory of their process. Each one can run on its own CPU core. for tiny operations in L-BFGS-BQuasi-Newton optimization algorithm, behind LogisticRegression's default lbfgs solver. L-BFGS-B is its variant with bounds.. This is fixed in scipy 2.0 (see scipy#26193), and should also be fixed in 1.18.2 (scipy#26199).
  • On the laptop, scikit-learn-intelex LogisticRegression looks much faster from 8 cores on, but that's a oneDALoneAPI Data Analytics Library: Intel's C++ library that implements the algorithms of scikit-learn-intelex. bug: on 4 threads or more, L-BFGS stops too early and returns a worse model. See oneDAL#3820.

sklearn-pypi

Python 3.12.14

Packages

  • scikit-learn 1.9.1 (pypi)
  • numpy 2.5.3 (pypi)
  • scipy 1.18.1 (pypi)
  • pandas 2.3.3 (pypi)

Threadpools

  • libscipy_openblas 0.3.31.dev (16 threads)
  • libscipy_openblas 0.3.34.106.0 (16 threads)
  • libgomp (16 threads)

OpenMP

  • GNU libgomp (OpenMP 4.5)
  • GOMP_SPINCOUNT: 300000

Full environment

view pixi env JSON

sklearn-cf-mkl

Python 3.12.14

Packages

  • scikit-learn 1.9.1 (conda-forge)
  • numpy 2.5.3 (conda-forge)
  • scipy 1.18.1 (conda-forge)
  • pandas 2.3.3 (conda-forge)

Threadpools

  • libmkl_rt 2026.1-Product (16 threads)
  • libomp (16 threads)

OpenMP

  • Intel/LLVM OpenMP (spec 201611)
  • KMP_BLOCKTIME: 0ms

Full environment

view pixi env JSON

sklearnex

Python 3.12.14

Packages

  • scikit-learn 1.8.0 (conda-forge)
  • scikit_learn_intelex 2026.1.0 (pypi)
  • daal 2026.1.0 (pypi)

Threadpools

  • libopenblas 0.3.34 (16 threads)
  • libgomp (16 threads)

OpenMP

  • GNU libgomp (OpenMP 5.2)
  • GOMP_SPINCOUNT: 1

Full environment

view pixi env JSON

Ridge

dataset: year_prediction_msd (463,810 rows x 990 features)
params: alpha=1.0

LogisticRegression

dataset: covtype (200,000 rows x 100 features, 7 classes)
params: C=10.0, max_iter=1000, solver=lbfgs

ExtraTreesClassifier

dataset: susy (2,000,000 rows x 18 features, 2 classes)
params: max_depth=16, max_features=0.5, min_impurity_decrease=3e-06, n_jobs=-1

RandomForestClassifier

dataset: fraud (150,000 rows x 30 features, 2 classes)
params: max_features=0.5, n_jobs=-1

KMeans

dataset: fashion_mnist_784 (60,000 rows x 784 features)
params: n_clusters=100

sklearn-pypi

Python 3.12.14

Packages

  • scikit-learn 1.9.1 (pypi)
  • numpy 2.5.3 (pypi)
  • scipy 1.18.1 (pypi)
  • pandas 2.3.3 (pypi)

Threadpools

  • libscipy_openblas 0.3.31.dev (64 threads)
  • libscipy_openblas 0.3.34.106.0 (64 threads)
  • libgomp (344 threads)

OpenMP

  • GNU libgomp (OpenMP 4.5)
  • GOMP_SPINCOUNT: 300000

Full environment

view pixi env JSON

sklearn-cf-mkl

Python 3.12.14

Packages

  • scikit-learn 1.9.1 (conda-forge)
  • numpy 2.5.3 (conda-forge)
  • scipy 1.18.1 (conda-forge)
  • pandas 2.3.3 (conda-forge)

Threadpools

  • libmkl_rt 2026.1-Product (172 threads)
  • libomp (344 threads)

OpenMP

  • Intel/LLVM OpenMP (spec 201611)
  • KMP_BLOCKTIME: 200ms

Full environment

view pixi env JSON

sklearnex

Python 3.12.14

Packages

  • scikit-learn 1.8.0 (conda-forge)
  • scikit_learn_intelex 2026.1.0 (pypi)
  • daal 2026.1.0 (pypi)

Threadpools

  • libopenblas 0.3.34 (128 threads)
  • libgomp (344 threads)

OpenMP

  • GNU libgomp (OpenMP 5.2)
  • GOMP_SPINCOUNT: 300000

Full environment

view pixi env JSON

Ridge

dataset: year_prediction_msd (463,810 rows x 990 features)
params: alpha=1.0

LogisticRegression

dataset: covtype (200,000 rows x 100 features, 7 classes)
params: C=10.0, max_iter=1000, solver=lbfgs

ExtraTreesClassifier

dataset: susy (2,000,000 rows x 18 features, 2 classes)
params: max_depth=16, max_features=0.5, min_impurity_decrease=3e-06, n_jobs=-1

RandomForestClassifier

dataset: fraud (150,000 rows x 30 features, 2 classes)
params: max_features=0.5, n_jobs=-1

KMeans

dataset: fashion_mnist_784 (60,000 rows x 784 features)
params: n_clusters=100

SMT vs. no SMT

SMTSimultaneous multithreading, called hyper-threading by Intel: one physical core runs two threads at once by sharing its execution units. (simultaneous multithreading, aka hyper-threading) gives each physical coreOne hardware core of the CPU. With SMT, it shows up as two logical CPUs. two logical coresWhat the operating system sees as one CPU. With SMT, each physical core shows up as two logical CPUs.. "SMT" pins both logical siblings of each selected physical core (the default used above); "no SMT" uses one logical thread per physical core.

ExtraTreesClassifier / sklearn-pypi

dataset: susy (2,000,000 rows x 18 features, 2 classes)
params: max_depth=16, max_features=0.5, min_impurity_decrease=3e-06, n_jobs=-1

ExtraTreesClassifier / sklearn-cf-mkl

dataset: susy (2,000,000 rows x 18 features, 2 classes)
params: max_depth=16, max_features=0.5, min_impurity_decrease=3e-06, n_jobs=-1

ExtraTreesClassifier / sklearnex

dataset: susy (2,000,000 rows x 18 features, 2 classes)
params: max_depth=16, max_features=0.5, min_impurity_decrease=3e-06, n_jobs=8

RandomForestClassifier / sklearn-pypi

dataset: fraud (150,000 rows x 30 features, 2 classes)
params: max_features=0.5, n_jobs=1

RandomForestClassifier / sklearn-cf-mkl

dataset: fraud (150,000 rows x 30 features, 2 classes)
params: max_features=0.5, n_jobs=1

RandomForestClassifier / sklearnex

dataset: fraud (150,000 rows x 30 features, 2 classes)
params: max_bins=150000, max_features=0.5, n_jobs=-1