-
Notifications
You must be signed in to change notification settings - Fork 49
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
base: main
Are you sure you want to change the base?
feat[next]: Optimisations for icon4py #1536
Conversation
…' into optimisations-for-icon4py
There was a problem hiding this 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.
return arr, origin | ||
|
||
|
||
type_handlers_convert_args = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would functools.singledispatch work?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
But in general, could make sense to discuss this in the context of going towards frozen programs. |
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, | ||
} | ||
|
||
|
There was a problem hiding this comment.
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
…sations-for-icon4py
Description
Changes to reduce Python overhead when calling icon4py granules from ICON.
isinstance
checks fromextract_connectivity_args
andconvert_args
.