Skip to content

fix[next-dace]: skip failing inout data instead of whole map in local double buffering - #2941

Merged
edopao merged 5 commits into
GridTools:mainfrom
edopao:fix/local-double-buffering-war-hazard
Oct 8, 2026
Merged

edopao merged 5 commits into
GridTools:mainfrom
edopao:fix/local-double-buffering-war-hazard

Conversation

@edopao

@edopao edopao commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Problem

_check_if_map_must_be_handled in local_double_buffering.py bailed on the entire map (return None) whenever a single inout data failed the subset compatibility check (all_inner_subsets[0] == all_inner_subsets[i]). This was inconsistent with the other two checks in the same loop (the "already buffered" check and the "not scalar" check), which correctly did inout_datas.pop(inout_data_name); continue to skip just the failing data.

As a result, in a Map with multiple inout datas, if one data had mismatched read/write subsets, return None suppressed double buffering for all inout datas — including ones that genuinely need it to prevent a write-after-read (WAR) hazard after GT4PyMapBufferElimination inlines the write-back into the Map body.

Fix

Changed return None → inout_datas.pop(inout_data_name); continue in _check_if_map_must_be_handled (local_double_buffering.py:418-419), consistent with the two other checks in the same loop.

This implements the reviewer's (philip-paul-mueller) preferred approach on PR #2815:

"I like the changes and think this is a good addition, but I think that the change is applied at the wrong place. This issue is not new and to solve it gt_create_local_double_buffering() has been created. Since the error surfaced the transformation did not kicked in. Thus I would suggest to patch that one."

Instead of blocking the buffer elimination in simplify.py (PR #2815's approach), the fix lets GT4PyMapBufferElimination(assume_pointwise=True) proceed and relies on gt_create_local_double_buffering to insert a local double buffer that sequences the read before the write.

Test

Added test_local_double_buffering_war_hazard in test_create_local_double_buffering.py:

  • Builds a WAR hazard SDFG where a single Map reads G on one branch and writes G (via a tmp buffer) on an independent branch: O(i) = G(i) + 1.0 and G(i) = 2.0 * A(i).
  • Applies GT4PyMapBufferElimination(assume_pointwise=True) — asserts it fires (inlines the write-back).
  • Applies gt_create_local_double_buffering — asserts it fires (inserts the double buffer).
  • Executes the SDFG and verifies O = G_old + 1.0 and G = 2.0 * A (the reader sees the OLD value of G, not the newly written one).

QA

  • test_create_local_double_buffering.py: 6 passed (5 existing + 1 new)
  • test_map_buffer_elimination.py: 10 passed
  • Full transformation_tests/ directory: 334 passed, 3 xfailed
  • pre-commit run (ruff, mypy, tach, license): clean
  • uv run mypy src/gt4py/next/program_processors/runners/dace/transformations/local_double_buffering.py: no issues
  • uv run tach check: all modules validated

… double buffering

`_check_if_map_must_be_handled` in `local_double_buffering.py` bailed on
the entire map (`return None`) when a single inout data failed the subset
compatibility check, instead of skipping just that data like the other two
checks in the same loop did (`inout_datas.pop(...); continue`). This
suppressed double buffering for all inout datas, including ones that need
it to prevent a WAR hazard after `GT4PyMapBufferElimination` inlines the
write-back into the Map body.

Fix: `return None` → `inout_datas.pop(inout_data_name); continue`.

Adds `test_local_double_buffering_war_hazard` in
`test_create_local_double_buffering.py` which builds a WAR hazard SDFG,
applies `GT4PyMapBufferElimination(assume_pointwise=True)`, then
`gt_create_local_double_buffering`, and verifies correct numerical
results (reader sees the OLD value of G).

This implements the reviewer's preferred approach on PR GridTools#2815 (fixing
`gt_create_local_double_buffering` instead of blocking the buffer
elimination in `simplify.py`).
@edopao edopao added module: dace Integration with DaCe framework and removed module: dace Integration with DaCe framework labels Oct 8, 2026

@philip-paul-mueller philip-paul-mueller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small comments about the tests, but looks okay.

@edopao

edopao commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

cscs-ci run default

@edopao
edopao merged commit 08f1b9d into GridTools:main Oct 8, 2026
24 checks passed
@edopao
edopao deleted the fix/local-double-buffering-war-hazard branch October 8, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants