Skip to content

Commit eb9e507

Browse files
committed
healpy: use schedule(static) for dist2holes's dynamic OpenMP loops
CI's cp313 leg segfaulted in test_dist2holes_no_hole_filter (PR #2430, run 36412601673) on hp.dist2holes(mask), a different crash than the one 0002 already fixes. The C++ dist2holes() (mask_tools.cc) and the swap_scheme() it calls on RING masks (healpix_map.h) each contain OpenMP loops using dynamic scheduling, matching gotcha 166's libgomp signature again, this time in HEALPix C++ rather than libsharp.
1 parent e9bbe3b commit eb9e507

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: Ludovic Henry <git@ludovic.dev>
3+
Date: Mon, 28 Sep 2026 00:00:00 +0000
4+
Subject: [PATCH] use schedule(static) for dist2holes's dynamic OpenMP loops
5+
6+
Upstream-Status: Inappropriate [works around a libgomp defect on the riscv64 runners, riseproject-dev/python-wheels#617]
7+
8+
CI's cp313 leg segfaulted with "Fatal Python error: Segmentation
9+
fault" in test_dist2holes.py::test_dist2holes_no_hole_filter, at the
10+
line calling hp.dist2holes(mask) (PR #2430, run 36412601673, job
11+
108896142667, head sha e9bbe3baf5). This is a different crash than the
12+
one 0002 already fixes: same commit, different test and different
13+
function, so 0002's libsharp loops are not involved here.
14+
15+
hp.dist2holes (src/_masktools.pyx) calls straight into
16+
cextern/healpix's Healpix_cxx dist2holes() (mask_tools.cc), which
17+
contains two OpenMP loops using non-static schedules: the border-pixel
18+
scan (schedule(dynamic,10000)) and the final per-pixel distance walk
19+
(schedule(dynamic)). Because the input mask here is RING-ordered,
20+
dist2holes() also calls Healpix_Map::swap_scheme() (healpix_map.h) on
21+
its way out, which has its own schedule(dynamic,1) loop. All three run
22+
on every dist2holes() call with a RING mask, matching gotcha 166's
23+
signature exactly: a fault inside the OpenMP runtime on the riscv64
24+
runners' libgomp, specific to the dynamic/guided work-share schedules,
25+
regardless of loop size.
26+
27+
Moving these three loops to schedule(static) costs load balancing,
28+
not correctness. Tag it Inappropriate and revert once the runners'
29+
toolchain is fixed, per gotcha 166.
30+
31+
Signed-off-by: Ludovic Henry <git@ludovic.dev>
32+
---
33+
cextern/healpix/src/cxx/Healpix_cxx/healpix_map.h | 2 +-
34+
cextern/healpix/src/cxx/Healpix_cxx/mask_tools.cc | 4 ++--
35+
2 files changed, 3 insertions(+), 3 deletions(-)
36+
37+
diff --git a/cextern/healpix/src/cxx/Healpix_cxx/healpix_map.h b/cextern/healpix/src/cxx/Healpix_cxx/healpix_map.h
38+
index 126fdf8..79d63c7 100644
39+
--- a/cextern/healpix/src/cxx/Healpix_cxx/healpix_map.h
40+
+++ b/cextern/healpix/src/cxx/Healpix_cxx/healpix_map.h
41+
@@ -183,7 +183,7 @@ template<typename T> class Healpix_Map: public Healpix_Base
42+
43+
arr<int> cycle=swap_cycles();
44+
45+
-#pragma omp parallel for schedule(dynamic,1)
46+
+#pragma omp parallel for schedule(static)
47+
for (tsize m=0; m<cycle.size(); ++m)
48+
{
49+
int istart = cycle[m];
50+
diff --git a/cextern/healpix/src/cxx/Healpix_cxx/mask_tools.cc b/cextern/healpix/src/cxx/Healpix_cxx/mask_tools.cc
51+
index 9756a50..093076e 100644
52+
--- a/cextern/healpix/src/cxx/Healpix_cxx/mask_tools.cc
53+
+++ b/cextern/healpix/src/cxx/Healpix_cxx/mask_tools.cc
54+
@@ -75,7 +75,7 @@ Healpix_Map<double> dist2holes(const Healpix_Map<double> &mask, double maxdist)
55+
for (int i=0; i<mask.Npix(); ++i)
56+
maxmask[i] = (mask[i]==0) ? FULLY_IN_MASK : 0;
57+
// find border pixels
58+
-#pragma omp parallel for schedule(dynamic,10000)
59+
+#pragma omp parallel for schedule(static)
60+
for (int i=0; i<mask.Npix(); ++i)
61+
if (maxmask[i])
62+
{
63+
@@ -163,7 +163,7 @@ Healpix_Map<double> dist2holes(const Healpix_Map<double> &mask, double maxdist)
64+
submask.push_back(i);
65+
subvec.push_back(omask[0].pix2vec(i));
66+
}
67+
-#pragma omp parallel for schedule(dynamic)
68+
+#pragma omp parallel for schedule(static)
69+
for (int i=0; i<omask[0].Npix(); ++i)
70+
process(0, i, submask, subvec);
71+
72+
--
73+
2.43.0

0 commit comments

Comments
 (0)