Reproducer
#include <cblas.h>
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char ** argv)
{
const int blas_threads = argc > 1 ? atoi(argv[1]) : 2;
const int n = 512;
double * a = calloc((size_t)n * n, sizeof(*a));
double * b = calloc((size_t)n * n, sizeof(*b));
double * c = calloc((size_t)n * n, sizeof(*c));
if (!a || !b || !c)
return 2;
for (int i = 0; i < n * n; ++i)
a[i] = b[i] = 1.0;
omp_set_dynamic(0);
omp_set_max_active_levels(1);
openblas_set_num_threads(blas_threads);
printf("outer_threads=2 blas_threads=%d max_active_levels=%d\n",
blas_threads,
omp_get_max_active_levels());
fflush(stdout);
#pragma omp parallel num_threads(2)
#pragma omp single
{
#pragma omp task
{
printf("dgemm starting on outer thread %d of %d\n",
omp_get_thread_num(),
omp_get_num_threads());
fflush(stdout);
cblas_dgemm(
CblasColMajor, CblasNoTrans, CblasNoTrans, n, n, n, 1.0, a, n, b, n, 0.0, c, n);
printf("dgemm finished\n");
fflush(stdout);
}
}
free(c);
free(b);
free(a);
return 0;
}
Summary
Commit f8674a7 introduced a regression in OpenBLAS builds using USE_OPENMP=1. After openblas_set_num_threads(N) is called, num_cpu_avail() now returns N before checking whether the BLAS call is already inside an active OpenMP region.
When nested OpenMP parallelism is unavailable—for example, omp_set_max_active_levels(1) inside an outer two-thread region—OpenBLAS plans an inner BLAS operation for two threads even though OpenMP serializes the nested region to one. This mismatch causes DGEMM to hang.
The immediate parent, 8cecf89, detects the existing OpenMP region and reduces the inner BLAS operation to one thread, so the same reproducer completes. With f8674a7 ./openblas_nested_repro 1 succeeds while ./openblas_nested_repro 2 hangs
Reproducer
Summary
Commit f8674a7 introduced a regression in OpenBLAS builds using
USE_OPENMP=1. Afteropenblas_set_num_threads(N)is called,num_cpu_avail()now returnsNbefore checking whether the BLAS call is already inside an active OpenMP region.When nested OpenMP parallelism is unavailable—for example,
omp_set_max_active_levels(1)inside an outer two-thread region—OpenBLAS plans an inner BLAS operation for two threads even though OpenMP serializes the nested region to one. This mismatch causes DGEMM to hang.The immediate parent, 8cecf89, detects the existing OpenMP region and reduces the inner BLAS operation to one thread, so the same reproducer completes. With f8674a7
./openblas_nested_repro 1succeeds while./openblas_nested_repro 2hangs