The library's one copy of the automatic thread rule: how many threads an operation that
was given no explicit threads= should use right now, under a caller-supplied cap.
omp_get_max_threads() when the caller is not inside an OpenMP parallel region, and 1 when
they are, because a nested region is the caller's business. This picks a DEFAULT and refuses
nothing: an explicit threads= is still honoured inside a region, which is the distinction
CLAUDE.md's "Auto-threading: omp_in_parallel() picks a DEFAULT" note draws. Without it, T
OpenMP threads would each ask for T more, and T*T oversubscription is slower than not
threading at all.
The predicate is omp_get_level, NOT omp_in_parallel, and the difference is not
pedantic. omp_in_parallel answers "is the enclosing region ACTIVE", i.e. does its team
have more than one thread. It is therefore .false. inside a region that exists but runs on
one thread -- !$omp parallel if(cond) with cond false, or any region at all under
OMP_NUM_THREADS=1. That is still a nested region, and the rule above still applies to it,
so the old spelling let every such caller open a full team one level down. It also deadlocks
libgomp; see parquet_nested_team_unsafe below and feature_risks.md Risk-104.
The cap only ever LOWERS the answer, and never overrides the parallel-region rule -- a
caller who capped sorting at 8 said nothing about what should happen inside someone else's
parallel region, and lifting the serial answer back to 8 there is exactly the T*T
oversubscription the rule exists to prevent. cap <= 0 means "no cap", which is how every
cfg_*_threads knob spells its automatic default.
Never report more threads than can actually run. omp_get_max_threads answers an ICV,
which is what the environment ASKED for; omp_get_num_procs answers what this thread's
affinity mask allows. They differ whenever the initial thread was bound before main.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | cap |
caller's domain cap; |
||
| character(len=*), | intent(in) | :: | area |
subsystem name, for the affinity-clamp warning |
integer function parquet_auto_thread_count(cap, area) result(n) #ifdef _OPENMP use omp_lib, only: omp_get_max_threads, omp_get_level #endif integer, intent(in) :: cap !! caller's domain cap; `<= 0` means no cap character(len=*), intent(in) :: area !! subsystem name, for the affinity-clamp warning n = 1 #ifdef _OPENMP if (omp_get_level() == 0) n = omp_get_max_threads() #endif if (cap > 0 .and. cap < n) n = cap n = parquet_clamp_to_affinity(n, area) end function parquet_auto_thread_count