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

extend hoist variables functionality #357

Merged
merged 3 commits into from
Sep 2, 2024

Conversation

MichaelSt98
Copy link
Collaborator

to account for possibly uninitialised variables used as dimensions (if wanted via flag)

This

subroutine driver(NLON, NB, FIELD1)
    use kernel_mod, only: kernel
    implicit none
    INTEGER, INTENT(IN) :: NLON, NB
    integer :: b
    integer, intent(inout) :: field1(nlon, nb)
    integer :: local_nlon
    local_nlon = nlon
    do b=1,nb
        call KERNEL(local_nlon, field1(:,b))
    end do
end subroutine driver

would be transformed to

SUBROUTINE driver (NLON, NB, field1)
  USE kernel_mod, ONLY: kernel
  implicit none
  INTEGER, INTENT(IN) :: NLON, NB
  INTEGER :: b
  INTEGER, INTENT(INOUT) :: field1(nlon, nb)
  INTEGER :: local_nlon
  INTEGER :: kernel_tmp1(local_nlon)
  local_nlon = nlon
  DO b=1,nb
    CALL KERNEL(local_nlon, field1(:, b), kernel_tmp1)
  END DO
END SUBROUTINE driver

which would be a problem as local_nlon is not initialised.

Setting remap_dimensions=True the transformation will produce

SUBROUTINE driver (NLON, NB, field1)
  USE kernel_mod, ONLY: kernel
  implicit none
  INTEGER, INTENT(IN) :: NLON, NB
  INTEGER :: b
  INTEGER, INTENT(INOUT) :: field1(nlon, nb)
  INTEGER :: local_nlon
  INTEGER :: kernel_tmp1(nlon)
  local_nlon = nlon
  DO b=1,nb
    CALL KERNEL(local_nlon, field1(:, b), kernel_tmp1)
  END DO
END SUBROUTINE driver

Copy link

github-actions bot commented Aug 7, 2024

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

Copy link

codecov bot commented Aug 7, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 95.40%. Comparing base (1f87624) to head (11cffba).
Report is 6 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #357   +/-   ##
=======================================
  Coverage   95.40%   95.40%           
=======================================
  Files         178      178           
  Lines       37267    37293   +26     
=======================================
+ Hits        35555    35581   +26     
  Misses       1712     1712           
Flag Coverage Δ
lint_rules 96.39% <ø> (ø)
loki 95.39% <100.00%> (+<0.01%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Collaborator

@reuterbal reuterbal left a comment

Choose a reason for hiding this comment

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

Thanks, this looks great! I left two remarks, please have a look if that makes sense or point out what I'm missing there. Otherwise this is fantastic.

Comment on lines 346 to 349
dim_map = {}
assignments = FindNodes(Assignment).visit(routine.body)
for assignment in assignments:
dim_map[assignment.lhs] = assignment.rhs
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just to point out how to do this in a "single line", or single list comprehension at least. For larger kernels like CLOUDSC with hundreds of assignments I expect you might actually be able to measure a small advantage with below change.

Suggested change
dim_map = {}
assignments = FindNodes(Assignment).visit(routine.body)
for assignment in assignments:
dim_map[assignment.lhs] = assignment.rhs
dim_map = {
assignment.lhs: assignment.rhs
for assignment in FindNodes(Assignment).visit(routine.body)
}

Also, this map might become quite big, so we might want to build a list of candidates first and then create the mapping? Suggestion (untested) would be something like this:

Suggested change
dim_map = {}
assignments = FindNodes(Assignment).visit(routine.body)
for assignment in assignments:
dim_map[assignment.lhs] = assignment.rhs
dim_vars = [
dim_var
for var in variables
for dim_var in FindVariables().visit(var.dimensions)
if isinstance(var, sym.Array)
]
dim_map = {
assignment.lhs: assignment.rhs
for assignment in FindNodes(Assignment).visit(routine.body)
if assignment.lhs in dim_vars
}

@@ -204,12 +205,17 @@ class HoistVariablesTransformation(Transformation):
----------
as_kwarguments : boolean
Whether to pass the hoisted arguments as `args` or `kwargs`.
remap_dimensions : boolean
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there a situation where we wouldn't want to do this? It seems to me like we might not need to make this an option and instead always do this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good question ... I can't think of a situation we don't want to do that but on the other hand I think having a switch is not a bad idea?!
Anyway, I switched the default but if you insist we can remove this flag.

Copy link
Collaborator

Choose a reason for hiding this comment

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

No, flipping the default should be enough. Thanks!

Copy link
Collaborator

@reuterbal reuterbal left a comment

Choose a reason for hiding this comment

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

Thanks, looks great and gtg from me!
I'll rebase the branch and will merge once green

@@ -204,12 +205,17 @@ class HoistVariablesTransformation(Transformation):
----------
as_kwarguments : boolean
Whether to pass the hoisted arguments as `args` or `kwargs`.
remap_dimensions : boolean
Copy link
Collaborator

Choose a reason for hiding this comment

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

No, flipping the default should be enough. Thanks!

@reuterbal reuterbal force-pushed the nams_hoist_variables_remap_dimensions branch from 4fcb538 to 817b1e7 Compare August 30, 2024 09:39
@reuterbal reuterbal added the ready for merge This PR has been approved and is ready to be merged label Aug 30, 2024
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.

Looks good to me; clean and nicely tested. I left a general comment for later development, but no action needed and GTG from me. :shipit:

@@ -319,6 +330,33 @@ def driver_variable_declaration(self, routine, variables):
"""
routine.variables += tuple(v.rescope(routine) for v in variables)

@staticmethod
def driver_variable_declaration_dim_remapping(routine, variables):
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]: Just a general note: we keep hitting this remapping problem in many use cases - so eventually we might want a general utility that can do this. But for this use case this looks great.

@reuterbal reuterbal merged commit 2263f78 into main Sep 2, 2024
13 checks passed
@reuterbal reuterbal deleted the nams_hoist_variables_remap_dimensions branch September 2, 2024 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready for merge This PR has been approved and is ready to be merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants