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

feat[next]: Optimisations for icon4py #1536

Open
wants to merge 25 commits into
base: main
Choose a base branch
from

Conversation

samkellerhals
Copy link
Contributor

@samkellerhals samkellerhals commented Apr 22, 2024

Description

Changes to reduce Python overhead when calling icon4py granules from ICON.

  • Removing isinstance checks from extract_connectivity_args and convert_args.

@samkellerhals samkellerhals requested review from egparedes and havogt May 6, 2024 08:13
@samkellerhals samkellerhals changed the title Optimisations for icon4py feat[next]: Optimisations for icon4py May 6, 2024
Copy link
Contributor

@havogt havogt left a comment

Choose a reason for hiding this comment

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

Forwarding the review to @egparedes for improving Python patterns in performance critical code parts.

src/gt4py/next/iterator/embedded.py Outdated Show resolved Hide resolved
src/gt4py/next/program_processors/runners/gtfn.py Outdated Show resolved Hide resolved
return arr, origin


type_handlers_convert_args = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

@samkellerhals samkellerhals May 7, 2024

Choose a reason for hiding this comment

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

I think it could work, however whilst nicer I have the feeling that it would be slower than a simple dictionary lookup.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be preferable to sacrifice readability only on the basis of hard evidence.

@havogt
Copy link
Contributor

havogt commented May 6, 2024

But in general, could make sense to discuss this in the context of going towards frozen programs.

@samkellerhals samkellerhals requested a review from DropD May 15, 2024 13:12
Comment on lines 95 to 110
def handle_connectivity(
conn: NeighborTableOffsetProvider, zero_tuple: tuple[int, ...], device: core_defs.DeviceType
) -> ConnectivityArg:
return (_ensure_is_on_device(conn.table, device), zero_tuple)


def handle_other_type(*args: Any, **kwargs: Any) -> None:
return None


type_handlers_connectivity_args = {
NeighborTableOffsetProvider: handle_connectivity,
common.Dimension: handle_other_type,
}


Copy link
Contributor

Choose a reason for hiding this comment

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

If this pattern proves to be a significant optimization over singledispatch, it still needs to be made more readable.

I propose to encode the pattern in a class. That class then needs a docstring explaining when to use it over standard approaches and why, for example, subclasses of the relevant types won't work with it unless they are added explicitly to the dict.

Sketch:

class FastDispatch:
    """
    Optimized version of functools.singledispatch, does not take into account inheritance or protocol membership.
    
    This leads to a speed-up of XXX, as documented in ADR YYY.
    
    Usage:
    >>> @Fastdispatch.fastdispatch(Any)
    ... def extract_connectivity_args(connectivity, *args, **kwargs):
    ...     return None
    ...
    ... @extract_connectivity_args(NeighborTableOffsetProvider):
    ... def extract_connectivity_args_from_nbtable(connectivity, device, *args, **kwargs):
    ...     return (_ensure_is_on_device(connectivity.table, device), zero_tuple)
    """
    _registry: dict[type: str]
    
    def __call__(self, dispatch_arg, *args, **kwargs):
        return getattr(self, self._registry[type(dispatch_arg)])(dispatch_arg, *args, **kwargs)
        
    def register(self, type):
        def decorator(function):
            self._registry[type] = function
            return function
        return decorator
        
    @classmethod
    def fastdispatch(cls, default_type):
        return decorator(function):
            dispatcher = cls()
            dispatcher.register(default_type)(function)
            return dispatcher
        return decorator

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.

4 participants