Skip to content

Experimental feature: Schedule tree representation#2262

Open
romanc wants to merge 172 commits intospcl:mainfrom
romanc:romanc/stree-v2
Open

Experimental feature: Schedule tree representation#2262
romanc wants to merge 172 commits intospcl:mainfrom
romanc:romanc/stree-v2

Conversation

@romanc
Copy link
Copy Markdown
Contributor

@romanc romanc commented Jan 9, 2026

Description

Schedule trees are an alternative representation of code in DaCe. It is a tree of nodes that represent the execution order of the SDFG. The tree can be used to perform schedule transformations on the SDFG, i.e., erasing an empty if branch, or merging two consecutive for-loops.

A first version of the schedule tree representation was merged with PR #1145, which adds support for creating schedule trees from SDFGs. This PR builds on #1466 and brings a first version of the transformation from schedule tree to SDFG.

tbennun and others added 30 commits December 3, 2023 12:50
Author: @romanc

@romanc is on leave for the next few days, thus I have replayed the
changes made in spcl#1808 here for faster
turnaround.
)

Fixes a reported failure mode of scalar to symbol promotion.
Backport of PR spcl#1917.

Co-authored-by: Roman Cattaneo <1116746+romanc@users.noreply.github.com>
Backport of typo fix for `v1/maintenance` (see
spcl#1944).

@phschaad would you mind hitting the merge button?

Co-authored-by: Roman Cattaneo <1116746+romanc@users.noreply.github.com>
Copy link
Copy Markdown
Collaborator

@tbennun tbennun left a comment

Choose a reason for hiding this comment

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

Looking great! I would like to see it more feature complete (as it is very close to being!) and I left some comments on the code. Maybe more preprocessing passes can make the implementations simpler

raise RuntimeError("Expected schedule tree root.")

for child in stree.children:
if id(child.parent) != id(stree):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

should use child.parent is not stree - better and has similar effect

Comment on lines +26 to +66
@dataclass
class Context:
root: 'ScheduleTreeRoot'
current_scope: Optional['ScheduleTreeScope']

access_cache: Dict[Tuple[SDFGState, str], Dict[str, nodes.AccessNode]]
"""Per scope (hashed by id(scope_node) access_cache."""


class ContextPushPop:
"""Append the given node to the scope, then push/pop the scope."""

def __init__(self, ctx: Context, state: SDFGState, node: 'ScheduleTreeScope') -> None:
if ctx.current_scope is None and not isinstance(node, ScheduleTreeRoot):
raise ValueError("ctx.current_scope is only allowed to be 'None' when node it tree root.")

self._ctx = ctx
self._parent_scope = ctx.current_scope
self._node = node
self._state = state

cache_key = (state, id(node))
assert cache_key not in self._ctx.access_cache
self._ctx.access_cache[cache_key] = {}

def __enter__(self) -> None:
assert not self._ctx.access_cache[(self._state, id(
self._node))], "Expecting an empty access_cache when entering the context."

self._ctx.current_scope = self._node

def __exit__(
self,
exc_type: Optional[type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType],
) -> None:
cache_key = (self._state, id(self._node))
assert cache_key in self._ctx.access_cache

self._ctx.current_scope = self._parent_scope
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what are these classes? They are missing docstrings and their purpose

return [tn.StateBoundaryNode(), visited]
return visited

stree = NestedSDFGStateBoundaryInserter().visit(stree)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

oh dear, needs a RefSet state boundary inserter

:return: The newly created state.
"""
if behavior != StateBoundaryBehavior.STATE_TRANSITION:
raise NotImplementedError("Only STATE_TRANSITION is supported as StateBoundaryBehavior in this prototype.")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
raise NotImplementedError("Only STATE_TRANSITION is supported as StateBoundaryBehavior in this prototype.")
raise NotImplementedError("Only STATE_TRANSITION is currently supported as StateBoundaryBehavior.")

if behavior != StateBoundaryBehavior.STATE_TRANSITION:
raise NotImplementedError("Only STATE_TRANSITION is supported as StateBoundaryBehavior in this prototype.")

# TODO: Some boundaries (control flow, state labels with goto) could not be fulfilled with every
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
# TODO: Some boundaries (control flow, state labels with goto) could not be fulfilled with every
# TODO: Some boundaries (control flow, state labels with goto, pending assignments) could not be fulfilled with every

after_state: Optional[ControlFlowBlock] = None,
*,
label: Optional[str] = None,
assignments: Optional[Dict] = None,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

type hint incomplete (key, value?)

insertion order since python 3.7 (which we rely on in this function
too). Depending on code generation it could(TM) be that we can
weaken (best case remove) the corresponding check from the sdfg
validator.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The check on the validator is on purpose (and we have seen cases where transformations trigger race conditions, e.g., in special cases where constant propagation modifies something). The semantics of the SDFG should be clear in that you should not make assignments that can cause a cycle or assume any order in the application of inter-state edge assignments. The only order is that conditions precede assignments.

romanc added 4 commits March 5, 2026 16:03
Avoid costly calls to `inspect` by adding a dummy `DebugInfo` object.
The call to `inspect` would anyway just return the line in the stree ->
sdfg translation layer. If we really wanted to have real `DebugInfo`,
we'd need a way to annotate the reads/writes in the stree and then
propagate this.
@romanc romanc force-pushed the romanc/stree-v2 branch 5 times, most recently from 948e333 to 4b22dc5 Compare March 16, 2026 09:12
romanc added 2 commits March 16, 2026 11:05
Much has changed on the pyFV3 / NDSL side that needs updating in this
workflow configuration.

We're using a temporary branch for pyFV3 since there are changes needed
and that side too 🙈.
@romanc romanc force-pushed the romanc/stree-v2 branch 8 times, most recently from 37255cd to a20292b Compare March 16, 2026 11:06
romanc added 4 commits March 16, 2026 18:17
`Range` subsets have a `reorder()` function that re-orders the
dimensions in-place. So far, it only re-ordered the ranges, but not the
tile sizes (which are stored in a separate list). This PR makes sure
both, ranges and tile sizes, are re-ordered according to the given
permutation. The PR adds a simple test case.
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.

5 participants