|
| 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