Skip to content

Conversation

@philip-paul-mueller
Copy link
Contributor

@philip-paul-mueller philip-paul-mueller commented Oct 30, 2025

This PR changes how calls to the underlying CompiledSDFG objects are carried out.
Before, the implementation heavily relied on the internal data format of the DaCe class.
However a recent change in DaCe changed this internal data leading to errors, that had to be patched.
This PR introduces a more stable fix and builds upon a refactoring in DaCe that beside other things, exposes the tools that were needed by GT4Py to work independently of the internals.
For that reason this PR also updates the DaCe dependency to 2025.11.04.

The main change is, that the argument vector, i.e. the C representation of the arguments used for the call, are no longer managed by CompiledSDFG but instead by GT4Py's CompiledDaceProgram.

TODO:

@philip-paul-mueller
Copy link
Contributor Author

Please ignore changes in pyproject.toml they are just needed that the CI picks up the patched DaCe version.

@philip-paul-mueller philip-paul-mueller marked this pull request as ready for review October 31, 2025 15:08
Copy link
Contributor

@edopao edopao left a comment

Choose a reason for hiding this comment

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

Very nice!

pyproject.toml Outdated
]
dace-next = [
'dace==2025.10.30' # refined in [tool.uv.sources]
'dace==2025.05.35' # refined in [tool.uv.sources] and I like that book.
Copy link
Contributor

Choose a reason for hiding this comment

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

What book? :)

Copy link
Contributor Author

@philip-paul-mueller philip-paul-mueller Oct 31, 2025

Choose a reason for hiding this comment

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

It is a German children book and serves as a reminder for me that I have to undo these changes.
You see I needed a version/date that will never be selected for this hack.

…tion.py

Co-authored-by: edopao <edoardo16@gmail.com>
Copy link
Contributor

@egparedes egparedes left a comment

Choose a reason for hiding this comment

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

Just a few comments.

# `tuple` is empty then it is not initialized. The first element is used in the
# normal call and we update it, the second element is used only for initialization
# and we do not update it.
csdfg_args: Union[tuple[list[Any], Sequence[Any]], tuple[()]]
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just using None as usual for an uninitialized attribute?

Suggested change
csdfg_args: Union[tuple[list[Any], Sequence[Any]], tuple[()]]
csdfg_args: tuple[list[Any], Sequence[Any]] | None

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think changing it into a None is actually better.
Because in the first call it will raise a TypeError instead an IndexError.
And this might hide some other bugs in the update code.

Comment on lines 75 to 79
processed_csdfg_args = self.sdfg_program.construct_arguments(**kwargs)
assert isinstance(processed_csdfg_args, tuple) and len(processed_csdfg_args) == 2
# Note we only care about the first argument vector, that is used in normal call.
# Since we update it, we ensure that it is a `list`.
self.csdfg_args = (list(processed_csdfg_args[0]), processed_csdfg_args[1])
Copy link
Contributor

Choose a reason for hiding this comment

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

Using explicit unpacking achieves the same effect as the assert and it makes the coder nicer to read.
I wouldn't store the second argument if it is not needed.

Suggested change
processed_csdfg_args = self.sdfg_program.construct_arguments(**kwargs)
assert isinstance(processed_csdfg_args, tuple) and len(processed_csdfg_args) == 2
# Note we only care about the first argument vector, that is used in normal call.
# Since we update it, we ensure that it is a `list`.
self.csdfg_args = (list(processed_csdfg_args[0]), processed_csdfg_args[1])
# We only care about the first value, which stores the arguments used in a normal call.
csdfg_call_args, _ = self.sdfg_program.construct_arguments(**kwargs)
self.csdfg_args =[*csdfg_call_args]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay there are two things here.
First, I told you that we do not need the initialization arguments, there I was wrong.
We only need it the first time we do the call and then never again, we do not even update it.
So we could technically remove it, but I think it would require some additional logic that makes the code harder to understand so I would propose to keep it.
If you really want it to be removed, I can do that.

The second thing is, that I fully agree with the unpacking.

# If not called they yet, thus empty tuple.
self.csdfg_args = ()

def process_arguments(self, **kwargs: Any) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

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

I find the name of this function not informative at all because it's too generic. What do you think about something like prepare_args_list ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right the name is not that good, however, I am also not super happy about the prepare_args_list.
I would suggest prepare_arguments.

def fast_call(self) -> None:
result = self.sdfg_program.fast_call(*self.sdfg_program._lastargs)
"""Perform a call to the compiled SDFG using the processed arguments, see `self.process_arguments()`."""
assert isinstance(self.csdfg_args, tuple) and len(self.csdfg_args) == 2
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
assert isinstance(self.csdfg_args, tuple) and len(self.csdfg_args) == 2

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would keep that because it tests if prepare_arguments() has been called or not.
I know you get an error in the unpacking, but I would prefer some more information about that.
However, I added a description to the assert.

# so we just update it with the current call arguments.
update_sdfg_call_args(args, fun.sdfg_program._lastargs[0])
fun.fast_call()
# Not the first call. We will only update the first argument vector (normal call).
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# Not the first call. We will only update the first argument vector (normal call).
# Not the first call. We will only update the first argument list (normal call).

Copy link
Contributor

@egparedes egparedes Nov 3, 2025

Choose a reason for hiding this comment

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

As mentioned below.

None,
]

# Processed argument vectors that are passed to `CompiledSDFG.fast_call()`. If the
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think argument vectors is the best name for this. In Python arguments are tuples or any other sequence which can be unpacked, so arguments list or arguments sequence feels more appropriate and less awkward.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I understand your reasoning, however, I think that in this case vector is the better name, because we go to C and there we have agrv (okay we do not call main()).

fun.fast_call()
# Not the first call. We will only update the first argument vector (normal call).
# NOTE: If this is the first call then we will generate an exception because
# `fun.csdfg_args` is still the empty tuple.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# `fun.csdfg_args` is still the empty tuple.
# `fun.csdfg_args` is still the empty

Copy link
Contributor

@edopao edopao left a comment

Choose a reason for hiding this comment

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

LGTM

Comment on lines +243 to +247
[[tool.mypy.overrides]]
disallow_incomplete_defs = false
disallow_untyped_defs = false
module = 'gt4py.next.program_processors.runners.dace_iterator.*'

Copy link
Contributor

Choose a reason for hiding this comment

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

Remember to remove these lines.

Copy link
Contributor

Choose a reason for hiding this comment

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

@philip-paul-mueller did you actually remove these lines and the "and I like that book" comment of the dace-next version before merging?

assert isinstance(self.csdfg_args, tuple) and len(self.csdfg_args) == 2, (
"Argument vector was not set properly."
)
self.sdfg_program.fast_call(*self.csdfg_args)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
self.sdfg_program.fast_call(*self.csdfg_args)
self.sdfg_program.fast_call(self.csdfg_argv, self.csdfg_init_argv)

Copy link
Contributor

@egparedes egparedes left a comment

Choose a reason for hiding this comment

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

LGTM

"Argument vector was not set properly."
)
self.sdfg_program.fast_call(*self.csdfg_args)
self.sdfg_program.fast_call(self.csdfg_argv, self.csdfg_init_argv, do_gpu_check=False)
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we really sure we want to pass do_gpu_check=False? Do you know what is its overhead? Maybe we could pass do_gpu_check=__debug__?

Copy link
Contributor

Choose a reason for hiding this comment

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

@philip-paul-mueller , any thoughts on this comment?

Copy link
Contributor Author

@philip-paul-mueller philip-paul-mueller Nov 6, 2025

Choose a reason for hiding this comment

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

#2365

We should have added something here.

@philip-paul-mueller philip-paul-mueller merged commit 08213ea into GridTools:main Nov 4, 2025
30 of 31 checks passed
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.

3 participants