From c5000ce06349019f735c3472387b7ab72aba0bf3 Mon Sep 17 00:00:00 2001 From: s-sasaki-earthsea-wizard Date: Fri, 14 Aug 2026 02:11:01 +0900 Subject: [PATCH] Remove per-pixel atomics and dynamic scheduling from _normalizeRtcArea The gamma-naught normalization loop used 'omp parallel for schedule(dynamic) collapse(2)' with an unspecified chunk size, dispatching one iteration per pixel through a contended shared counter, plus an 'omp atomic' per pixel. Each (i, j) is only touched by its own iteration, so the atomics are unnecessary. At NISAR frequency-A scale (29240 x 21232 radar grid, two normalization calls) this amounted to 1.24e9 contended dynamic chunk acquisitions; profiling attributes ~20% of the RTC area-projection time (~11% of total GCOV wall time) to the dispatch and atomics alone, for a loop that is otherwise memory-bandwidth bound. The loop remains scalar with GCC 13 at -O2/-O3 either way (the NaN guard defeats if-conversion), so the entire gain comes from removing the dispatch and the atomics. Use a plain row-wise 'omp parallel for' and a conditional expression instead. Output is bit-identical: iteration-to-pixel mapping and per-pixel arithmetic are unchanged. --- cxx/isce3/geometry/RTC.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/cxx/isce3/geometry/RTC.cpp b/cxx/isce3/geometry/RTC.cpp index 5a65e7e9e..6005b5d4b 100644 --- a/cxx/isce3/geometry/RTC.cpp +++ b/cxx/isce3/geometry/RTC.cpp @@ -270,18 +270,16 @@ void _normalizeRtcArea(isce3::core::Matrix& numerator_array, pyre::journal::info_t& info) { info << "normalizing gamma-naught area..." << pyre::journal::endl; - _Pragma("omp parallel for schedule(dynamic) collapse(2)") - for (int i = 0; i < numerator_array.length(); ++i) + // Each (i, j) is read and written by exactly one iteration, so no + // atomics are required. Row-wise static scheduling avoids per-pixel + // dynamic dispatch overhead. + _Pragma("omp parallel for") + for (int i = 0; i < numerator_array.length(); ++i) for (int j = 0; j < numerator_array.width(); ++j) { const float denominator_value = denominator_array(i, j); - if (denominator_value == 0) { - _Pragma("omp atomic write") - numerator_array(i, j) = - std::numeric_limits::quiet_NaN(); - continue; - } - _Pragma("omp atomic update") - numerator_array(i, j) /= denominator_value; + numerator_array(i, j) = denominator_value == 0 + ? std::numeric_limits::quiet_NaN() + : numerator_array(i, j) / denominator_value; } }