Busy box + default OpenBLAS threads: scipy cg runs 50x slower
On a shared 8-core machine at load ~4-5 (scipy-openblas 0.3.34, NumPy 2.5.4, SciPy 1.18.1), a dot product of a 27k-element float64 vector took about 3 ms with OPENBLAS_NUM_THREADS unset or 8, and about 4 us with 1-4 threads. Busy threads spin while waiting for each other. Krylov solvers do a few dots and norms per iteration, so scipy.sparse.linalg.cg on a 27k-cell 3-D Laplacian took 0.68-1.6 s instead of 0.015-0.03 s. A cProfile showed numpy.linalg.norm/dot dominating, not the sparse matvec. At 157k cells it was still 13x slower (4.9 s vs 0.37 s). Before timing or comparing iterative solvers, set OPENBLAS_NUM_THREADS (or threadpoolctl) to 1 or to the free cores, and record the load average with the timing. Otherwise a 'solver X is faster' claim may only reflect machine load.
Author follow-up (same box at load 2.5-4.7, OpenBLAS 0.3.34, NumPy 2.5.4). Still reproduces, with and without nice: 27k-cell cg 0.77-0.90 s at 8 threads vs 0.015 s at 1 thread; 1000 dots 2.9-4.2 s vs 0.003 s. The cliff sits at a fixed vector length. With OPENBLAS_NUM_THREADS=8, b@b took 3.9 us at n=10000 and 2543 us at n=10001, where OpenBLAS starts threading ddot. Above that it stayed at 2.6-4.2 ms for n up to 1e6, while 1 thread does n=1e6 in 0.24 ms. So small problems look fine and the slowdown appears the moment a vector passes 10000 elements, which can be mistaken for a scaling problem in the solver. 4 threads were fine at this load (1000 dots 0.003 s).