Skip to content

Port from Apps#644 to review in Psytrans also#113

Open
MetBenjaminWent wants to merge 16 commits intoMetOffice:mainfrom
MetBenjaminWent:add_transmute_cpu
Open

Port from Apps#644 to review in Psytrans also#113
MetBenjaminWent wants to merge 16 commits intoMetOffice:mainfrom
MetBenjaminWent:add_transmute_cpu

Conversation

@MetBenjaminWent
Copy link
Collaborator

I've done work in LFRic Apps #644 to generate Psyclone Transformation scripts for OpenMP on CPUs for across the domain.

Testing in this ticket and Apps#629 show that there is a beneficial performance change as a result of these scripts.

These are designed to be called by a generic global or override script which runs over all loops present.

It will span parallel sections where possible within list of rules.

Then will OpenMP the loops in line with rules provided, such as check for array of struct Nodes (types).

These have been checked in #644 with Pylint and flake8 in line with LFRic Python coding standards and pass.

@MetBenjaminWent
Copy link
Collaborator Author

MetBenjaminWent commented Jun 2, 2025

Related to changes in https://code.metoffice.gov.uk/trac/lfric_apps/ticket/644.

Until there is a PsyTrans link accessible by Apps HoT, changes will also go onto trunk with Apps#644 to put performance benefits on trunk.

@MetBenjaminWent
Copy link
Collaborator Author

See issue #114

@MetBenjaminWent
Copy link
Collaborator Author

MetBenjaminWent commented Jun 12, 2025

Based on our discussion this morning, I've done a slight refactor on the App Branch:

https://code.metoffice.gov.uk/trac/lfric_apps/changeset?reponame=&new=11203%40main%2Fbranches%2Fdev%2Fbenjaminwent%2Fr11135_v2_omp_transmute_glob&old=11193%40main%2Fbranches%2Fdev%2Fbenjaminwent%2Fr11135_v2_omp_transmute_glob

Will port relevant changes post your review.

I'm thinking making it obvious where the rules are might be helpful.

Copy link
Collaborator

@oakleybrunt oakleybrunt left a comment

Choose a reason for hiding this comment

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

I'm stopping my review here for now. This needs refactoring and condensing. My main points I'd like you to look at are:

  • Don't return boolean values from functions. Please throw exceptions which can be handled properly
  • Stop storing boolean values which inform if statements within the same function. Just move the stuff that needs to be executed to that point!
  • Stop using global variables

Comment on lines 46 to 52
# Setup transformations and their properties
# OMP parallel do transformation
omp_transform_par_do = OMPLoopTrans(omp_schedule="static",
omp_directive="paralleldo")
omp_parallel = OMPParallelTrans()
omp_transform_do = OMPLoopTrans(omp_schedule="static",
omp_directive="do")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please refrain from using global variables. If you need them within a function, just create the transformation object as and when you need it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is global as its a transformation that everything will use within that context.

I'd rather set them up once (like so), and use them as needed.

We could come up with a better storage solution sure that makes these as accessible (like in a class), but I think the way these are handled personally is fine.

Did you have a solution for where to store these? We could start a new script that is pre-designated calls in an object, but the result is the same really....

Copy link
Collaborator

Choose a reason for hiding this comment

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

The class is in PSyclone, that's where you get it from. If you need to use one of these transformations, please make it within the function so it is easily readable - i.e. you can see exactly what was passed to OMPLoopTrans if you are just looking at the function.

Global variables are notoriously annoying when trying to read and understand code. "What is this variable?" "where did it come from?" are questions that I found myself asking when reviewing this change. Please remove them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

How about this as a solution?

It is called by:
trans = PropTrans()
trans.omp_transform_do()


'''
Getter wrappers for global transformations to be condensed and accessible
'''

from psyclone.transformations import (OMPLoopTrans, OMPParallelTrans)


class PropTrans:
    '''
    Class to store pre-configured transformations with getters
    '''
    def __init__(self):
        '''
        Initialise class with default properties
        '''
        
        # Setup transformations and their properties
        # OMP parallel do transformation
        self._omp_transform_par_do = OMPLoopTrans(
            omp_schedule="static",
            omp_directive="paralleldo")
        self._omp_parallel = OMPParallelTrans()
        self._omp_transform_do = OMPLoopTrans(
            omp_schedule="static",
            omp_directive="do")


    # Getters
    def omp_transform_par_do(self):
        '''
        Get pre configured omp_transform_par_do
        '''
        return self._omp_transform_par_do

    def omp_parallel(self):
        '''
        Get pre configured omp_parallel
        '''
        return self._omp_parallel

    def omp_transform_do(self):
        '''
        Get pre configured omp_transform_do
        '''
        return self._omp_transform_do

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this could work as a solution but can you move this into a different PR please? For now, just call the transformations directly from PSyclone.

else:
ret_shed = False

return ret_shed
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function's docstring says it returns a schedule but it sometimes returns a bool. Please make it return a schedule or throw an exception

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See the comment, I've updated this on the main branch on trac

Copy link
Collaborator Author

@MetBenjaminWent MetBenjaminWent Jun 17, 2025

Choose a reason for hiding this comment

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

I can update the doc string.

The intent though is to later check and return the presence of the object.

I don't want it throw an error.

I want it to return the schedule if there is one, and otherwise report there inst for checks that utilise.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you make it so the function returns None as default but return shed_list[0] if it gets to that point?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I can look at swapping this over if its possible.

I think I had some issues in the past converting a type none to an object in the past however

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The None type in this instance seems to be working when converting from None to a Schedule, output is consistent post change, will add to commit with fix

Copy link
Collaborator

@joewallwork joewallwork left a comment

Choose a reason for hiding this comment

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

On a quick scan, would it be possible to break this PR down slightly? It adds a lot of new functions but none of the tests to support them. Perhaps one module at a time, or (better still) a handful of functions at a time.

return omp_ancestry_presence


def get_last_child_shed(loop_node):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any chance we could expand the name to get_last_child_schedule? Just because it's not immediately obvious that shed is meant to refer to schedule.

if loop_continue:
# Try the transformation - either a OMP parallel do or do
error = try_transformation(loop_node, transformation, options)
print(error)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Remove debug prints

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