From a14924abe4580019c74d7ab6358320bc5ae35c58 Mon Sep 17 00:00:00 2001 From: Balasubramanian Narasimhan Date: Fri, 17 Jul 2026 21:07:49 -0700 Subject: [PATCH] Clamp GetThreadLimit by the live OpenMP thread limit OpenFHEParallelControls::GetThreadLimit(n) returned min(n, machineThreads), where machineThreads is latched once from omp_get_max_threads() at static init and never refreshed. Every parallel hot region emits num_threads(GetThreadLimit(...)), and an explicit num_threads clause overrides the runtime OpenMP ICV -- so a post-init omp_set_num_threads(), including one made through OpenFHEParallelControls::SetNumThreads(), is silently ignored and the library cannot be capped to fewer threads in-process. Also clamp by the live omp_get_max_threads() so a runtime thread limit is honored on every platform. The added call is a cheap ICV read; when the runtime limit is left at the machine default the result is unchanged. --- src/core/include/utils/parallel.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/core/include/utils/parallel.h b/src/core/include/utils/parallel.h index 450759bdd..5a66bd0bd 100644 --- a/src/core/include/utils/parallel.h +++ b/src/core/include/utils/parallel.h @@ -108,10 +108,23 @@ class ParallelControls { #endif } - // @Brief returns min of int n and machineThreads + // @Brief returns the thread count a parallel region should use: the + // minimum of the requested n, machineThreads, and the live OpenMP limit + // omp_get_max_threads(). + // + // The live-limit clamp is what makes runtime thread control effective. + // machineThreads is latched once from omp_get_max_threads() at static + // init and never refreshed, yet every hot region emits + // num_threads(GetThreadLimit(...)) -- a clause that overrides the runtime + // ICV. Clamping only by machineThreads therefore ignores a subsequent + // omp_set_num_threads() (including one made through SetNumThreads() below), + // so the library cannot be capped in-process. Also clamping by the live + // omp_get_max_threads() restores that. int GetThreadLimit(int n) const { #ifdef PARALLEL - return n > machineThreads ? machineThreads : n; + int lim = n > machineThreads ? machineThreads : n; + int live = omp_get_max_threads(); + return lim > live ? live : lim; #else return 1; #endif