From f8674a7be8ec320d4d0c66afe509c9f1e063557a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Hamb=C3=BCchen?= Date: Tue, 12 May 2026 05:18:55 +0200 Subject: [PATCH 1/3] Make OpenBLAS's usage of OpenMP respect openblas_set_num_threads(). Fixes #5806. Until now, the code in `num_cpu_avail()`, if (blas_cpu_number != openmp_nthreads) { goto_set_num_threads(openmp_nthreads); } would just always set the threads back to OpenMP's thread count. --- common_thread.h | 9 +++++++++ driver/others/blas_server_omp.c | 9 +++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/common_thread.h b/common_thread.h index 4a8db682bf..cefe881c7b 100644 --- a/common_thread.h +++ b/common_thread.h @@ -138,10 +138,19 @@ typedef struct blas_queue { extern int blas_server_avail; extern int blas_omp_number_max; extern int blas_omp_threads_local; +extern int blas_is_num_threads_set_explicitly; static __inline int num_cpu_avail(int level) { #ifdef USE_OPENMP + /* If the user explicitly called openblas_set_num_threads(), + respect that setting instead of overriding it with + `omp_get_max_threads()` below (which is to get a default + in case the user hasn't made an explicit choice). */ + if (blas_is_num_threads_set_explicitly) { + return blas_cpu_number; + } + int openmp_nthreads; openmp_nthreads=omp_get_max_threads(); if (omp_in_parallel()) openmp_nthreads = blas_omp_threads_local; diff --git a/driver/others/blas_server_omp.c b/driver/others/blas_server_omp.c index 38b48fc842..532f44dcb2 100644 --- a/driver/others/blas_server_omp.c +++ b/driver/others/blas_server_omp.c @@ -70,6 +70,7 @@ int blas_server_avail = 0; int blas_omp_number_max = 0; int blas_omp_threads_local = 1; +int blas_is_num_threads_set_explicitly = 0; // tracks whether the user called openblas_set_num_threads() extern int openblas_omp_adaptive_env(void); @@ -122,7 +123,7 @@ void goto_set_num_threads(int num_threads) { } void openblas_set_num_threads(int num_threads) { - + blas_is_num_threads_set_explicitly = 1; goto_set_num_threads(num_threads); } @@ -145,7 +146,7 @@ extern int openblas_omp_num_threads_env(void); if(blas_omp_number_max <= 0) blas_omp_number_max= openblas_omp_num_threads_env(); - if (blas_omp_number_max <= 0) + if (blas_omp_number_max <= 0) blas_omp_number_max=MAX_CPU_NUMBER; #else blas_omp_number_max = omp_get_max_threads(); @@ -365,14 +366,14 @@ static void exec_threads(int thread_num, blas_queue_t *queue, int buf_index){ #ifdef BUILD_COMPLEX16 sb = (void *)(((BLASLONG)sa + ((ZGEMM_P * ZGEMM_Q * 2 * sizeof(double) + GEMM_ALIGN) & ~GEMM_ALIGN)) + GEMM_OFFSET_B); -#else +#else fprintf(stderr,"UNHANDLED COMPLEX16\n"); #endif } else if ((queue -> mode & BLAS_PREC) == BLAS_SINGLE) { #ifdef BUILD_COMPLEX sb = (void *)(((BLASLONG)sa + ((CGEMM_P * CGEMM_Q * 2 * sizeof(float) + GEMM_ALIGN) & ~GEMM_ALIGN)) + GEMM_OFFSET_B); -#else +#else fprintf(stderr,"UNHANDLED COMPLEX\n"); #endif } else { From afb597ba1de14817786c65c01f47e31cee8b29a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Hamb=C3=BCchen?= Date: Tue, 12 May 2026 04:18:39 +0200 Subject: [PATCH 2/3] Document openblas_set_num_threads_local(). See #4425 Also see https://github.com/OpenMathLib/OpenBLAS/pull/5907#issuecomment-4951191764 --- cblas.h | 33 +++++++++++++++++++++++++++++++++ driver/others/blas_server_omp.c | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/cblas.h b/cblas.h index 8395f1b8b2..81d7904e49 100644 --- a/cblas.h +++ b/cblas.h @@ -40,6 +40,39 @@ extern "C" { /*Set the number of threads on runtime.*/ void openblas_set_num_threads(int num_threads); void goto_set_num_threads(int num_threads); +/* + * Intent: + * Sets the thread-local number of threads that OpenBLAS functions should request. + * This thread-local number only affects the current execution thread + * and, when set, overrides the global default. + * This is useful for controlling nested parallelism. + * For example when the caller's own (e.g. OpenMP) threads each invoke + * OpenBLAS, `num_threads` determines how many threads OpenBLAS may use + * per such call, instead of the process-wide default of + * `omp_get_max_threads()`. + * + * The intent of this was likely to match MKL's `mkl_set_num_threads_local()` + * but implementation may not live up to the original intent yet. + * + * TODO: + * Currently the implementation doesn't really do any of that: + * * The setting is NOT thread-local. + * * This function currently just calls `openblas_set_num_threads(num_threads)`, + * changing the same process-wide thread count as that function, + * and additionally records `num_threads` in an internal (global, not per-thread) + * variable that is only consulted when OpenBLAS is invoked from within + * a caller's OpenMP parallel region and the user has not made an + * explicit thread-count choice. + * * There is no special handling of `num_threads == 0` + * (or other MKL-style reset values); the value is forwarded to + * `openblas_set_num_threads()`, where values < 1 are treated + * as "use the default" and large values are clamped to the number of cores. + * + * Returns the *previous* number of threads (as reported by + * `openblas_get_num_threads()`), so the caller can save and later restore it. + * + * On single-threaded OpenBLAS builds this is a no-op that returns 1. + */ int openblas_set_num_threads_local(int num_threads); /*Get the number of threads on runtime.*/ diff --git a/driver/others/blas_server_omp.c b/driver/others/blas_server_omp.c index 532f44dcb2..f7ec8edfa3 100644 --- a/driver/others/blas_server_omp.c +++ b/driver/others/blas_server_omp.c @@ -69,7 +69,7 @@ int blas_server_avail = 0; int blas_omp_number_max = 0; -int blas_omp_threads_local = 1; +int blas_omp_threads_local = 1; // num threads to use when already inside omp_in_parallel() int blas_is_num_threads_set_explicitly = 0; // tracks whether the user called openblas_set_num_threads() extern int openblas_omp_adaptive_env(void); From 2cd33e82b5b1f29a7b792714e041b01b488315f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Hamb=C3=BCchen?= Date: Tue, 12 May 2026 05:49:32 +0200 Subject: [PATCH 3/3] Refactor: Simplify num_cpu_avail() syntax --- common_thread.h | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/common_thread.h b/common_thread.h index cefe881c7b..16453558d3 100644 --- a/common_thread.h +++ b/common_thread.h @@ -151,27 +151,19 @@ static __inline int num_cpu_avail(int level) { return blas_cpu_number; } -int openmp_nthreads; - openmp_nthreads=omp_get_max_threads(); - if (omp_in_parallel()) openmp_nthreads = blas_omp_threads_local; -#endif + int openmp_nthreads = omp_in_parallel() ? blas_omp_threads_local : omp_get_max_threads(); -#ifndef USE_OPENMP - if (blas_cpu_number == 1 -#else - if (openmp_nthreads == 1 -#endif - ) return 1; + if (openmp_nthreads == 1) return 1; -#ifdef USE_OPENMP - if (openmp_nthreads > blas_omp_number_max){ + if (openmp_nthreads > blas_omp_number_max) { #ifdef DEBUG - fprintf(stderr,"WARNING - more OpenMP threads requested (%d) than available (%d)\n",openmp_nthreads,blas_omp_number_max); + fprintf(stderr, "WARNING - more OpenMP threads requested (%d) than available (%d)\n", openmp_nthreads, blas_omp_number_max); #endif - openmp_nthreads = blas_omp_number_max; - } - if (blas_cpu_number != openmp_nthreads) { - goto_set_num_threads(openmp_nthreads); + openmp_nthreads = blas_omp_number_max; + } + + if (blas_cpu_number != openmp_nthreads) { + goto_set_num_threads(openmp_nthreads); // mutates `blas_cpu_number` } #endif