Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable default recursion for Transformation.apply #136

Conversation

reuterbal
Copy link
Collaborator

This is a proposal to fix #131.

By default, the Transformation class recurses to all contained nodes, i.e., calling apply on a Sourcefile recurses into all Module and Subroutine nodes in that file, and so on. Arguably, this was a questionable design choice, however, the Scheduler.process method relies on this behaviour to apply transformations. There, we invoke the transformation always on the source file that contains the IR node corresponding to an Item. (And then do some silly filtering afterwards, which possibly even prevents us from applying transformations to contained member subroutines...? 🤔)

This PR switches off the recursion by default but allows to retain current behaviour via the recurse_to_contained_nodes option.

I'll file a separate PR on top of the current one that changes also the Scheduler behaviour by directly applying transformations only to the IR node corresponding to a scheduler graph item. This requires some more careful regression testing for ecphys, and therefore this might only be sensible to do with the new Scheduler (hence the separate PR).

Important to note is that the change does have API implications when not using the Scheduler, because it requires to be more careful to which IR node a Transformation is applied - by either explicitly applying it to the target file, module, or subroutine directly, or explicitly enabling the recursion.

@github-actions
Copy link

github-actions bot commented Sep 1, 2023

Documentation for this branch can be viewed at https://sites.ecmwf.int/docs/loki/136/index.html

@reuterbal reuterbal force-pushed the 131-calling-a-transformation-on-a-subroutine-automatically-applies-itself-recursively-on-contained-subroutines branch from 18b61a4 to 47b86a8 Compare September 1, 2023 09:04
@codecov
Copy link

codecov bot commented Sep 1, 2023

Codecov Report

Merging #136 (87bd488) into main (75fc36f) will decrease coverage by 0.04%.
The diff coverage is 87.23%.

@@            Coverage Diff             @@
##             main     #136      +/-   ##
==========================================
- Coverage   92.12%   92.08%   -0.04%     
==========================================
  Files          89       89              
  Lines       16508    16533      +25     
==========================================
+ Hits        15208    15225      +17     
- Misses       1300     1308       +8     
Flag Coverage Δ
lint_rules 96.22% <ø> (ø)
loki 92.03% <87.23%> (-0.02%) ⬇️
transformations 91.48% <ø> (-0.22%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Changed Coverage Δ
loki/transform/transformation.py 90.47% <ø> (-1.31%) ⬇️
loki/transform/fortran_c_transform.py 87.72% <28.57%> (-1.54%) ⬇️
loki/bulk/scheduler.py 81.17% <87.50%> (+0.08%) ⬆️
loki/transform/build_system_transform.py 98.18% <100.00%> (+0.18%) ⬆️
loki/transform/dependency_transform.py 96.93% <100.00%> (+0.33%) ⬆️

... and 5 files with indirect coverage changes

@reuterbal reuterbal force-pushed the 131-calling-a-transformation-on-a-subroutine-automatically-applies-itself-recursively-on-contained-subroutines branch from 47b86a8 to 562c63d Compare September 1, 2023 12:39
@reuterbal reuterbal force-pushed the 131-calling-a-transformation-on-a-subroutine-automatically-applies-itself-recursively-on-contained-subroutines branch from 562c63d to 9fd7318 Compare September 6, 2023 12:26
@reuterbal reuterbal force-pushed the 131-calling-a-transformation-on-a-subroutine-automatically-applies-itself-recursively-on-contained-subroutines branch from 35f6390 to 2889c4a Compare September 8, 2023 19:17
@reuterbal
Copy link
Collaborator Author

Merged #137 and rebased over main

Copy link
Collaborator

@mlange05 mlange05 left a comment

Choose a reason for hiding this comment

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

Ok, first of all many thanks for sticking with it through this change. This one was quite tricky, because the underlying assumptions of the DependencyTransformation are basically broken and ill designed (for context, this transformation also predates most of the scheduler "smarts").

Nevertheless, full removing recursion and letting transformations implement the complex file=>module=>routine=>member recursion manually is a good move, for now, until we have more flexibility to configure transformations generically (the "manifest" idea).

But, there is a lot(!) of great housekeeping, testing and general quality of life stuff in here, so GT to merge this, and I'll attempt any simplification and clean-up on top of this.

is_member = isinstance(routine.parent, Subroutine)

# Pick out correct item for current subroutine if processed via recursion
if 'items' in kwargs:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I do not understand this logic here: Why are we recovering item from items if item is given by the scheduler?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's gone after yesterday's push, the file entry point is the place now where we do the item-picking and dispatch to program unit-specific entry points.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, and after diving through this a little more, I think I understand how/why this was done.

@@ -29,9 +28,6 @@
)

# pylint: disable=wrong-import-order
from transformations.argument_shape import (
ArgumentArrayShapeAnalysis, ExplicitArgumentArrayShapeTransformation
Copy link
Collaborator

Choose a reason for hiding this comment

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

These should not have been removed. This is an error in #142 and is fixed in #149. Good catch, and thanks for "flagging" this though. 😉

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Apologies for blindly trusting the linter instead of using my brain...

@@ -638,9 +650,16 @@ def process(self, transformation, reverse=False, item_filter=SubroutineItem, use
# Use entry from item_map to ensure the original item is used in transformation
_item = self.item_map[item.name]

# Pick out the IR node to which to apply the transformation
# TODO: should this become an Item property?
Copy link
Collaborator

Choose a reason for hiding this comment

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

[no action] Yes, it should, but it requires the SGraph development to make this behaviour neat. So good for now.

if items:
# Recursion into all subroutine items in the current file
for item in items:
self.transform_subroutine(item.routine, item=item, role=item.role, targets=item.targets, **kwargs)
Copy link
Collaborator

Choose a reason for hiding this comment

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

[no action] This interwoven subtlety highlights that the DependencyTransform is actually deeply flawed and needs to be re-designed. As already discussed offline, like as a combination of several individual transformations, so thanks for keeping this functional! 🙏

driver = Sourcefile.from_source(driver_fcode, frontend=frontend)

# Because the renaming is intended to be applied to the routines as well as the enclosing module,
# we need to invoke the transformation on the full source file and activate recursion to contained nodes
Copy link
Collaborator

Choose a reason for hiding this comment

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

With the removal of the recurse_to_contained_nodes option, this comment seems outdated. It's also repeated a few times throughout the test file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes! I removed the branching in the test related to this but overlooked the comments. Will fix

@reuterbal reuterbal force-pushed the 131-calling-a-transformation-on-a-subroutine-automatically-applies-itself-recursively-on-contained-subroutines branch from fdf59cd to 87bd488 Compare September 12, 2023 14:08
@reuterbal reuterbal merged commit 258eae5 into main Sep 13, 2023
12 checks passed
@reuterbal reuterbal deleted the 131-calling-a-transformation-on-a-subroutine-automatically-applies-itself-recursively-on-contained-subroutines branch September 13, 2023 11:17
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.

Calling a Transformation on a subroutine automatically applies itself recursively on contained subroutines.
2 participants