diff --git a/README.rst b/README.rst index cd9f709..2809a62 100644 --- a/README.rst +++ b/README.rst @@ -60,6 +60,9 @@ Marker API command line, this function performs no operation. - ``pylikwid.markerreset(regiontag)``: Reset the values stored using the region name ``regiontag``. On success, 0 is returned. +- ``@pylikwid.profile``: Decorator that wraps a function in a LIKWID marker + region. By default, the function name is used as the region name. It can + also be called with a custom name: ``@pylikwid.profile(region_name="work")``. - ``pylikwid.markerclose()``: Close the connection to the LIKWID Marker API and write out measurement data to file. This file will be evaluated by ``likwid-perfctr``. diff --git a/src/pylikwid/__init__.py b/src/pylikwid/__init__.py index 183e0ad..f2c4bed 100644 --- a/src/pylikwid/__init__.py +++ b/src/pylikwid/__init__.py @@ -1 +1,34 @@ +import functools + from .pylikwid import * + + +def profile(_func=None, *, region_name=None): + """Decorator that wraps a function in a LIKWID marker region. + + Usage:: + + @profile + def my_func(): ... # region name = "my_func" + + @profile(region_name="work") + def my_func(): ... # region name = "work" + """ + def decorator(func): + name = region_name if region_name is not None else func.__name__ + + @functools.wraps(func) + def wrapper(*args, **kwargs): + markerstartregion(name) + try: + return func(*args, **kwargs) + finally: + markerstopregion(name) + + return wrapper + + if _func is not None: + # Used as @profile without parentheses + return decorator(_func) + # Used as @profile(...) with parentheses + return decorator diff --git a/tests/testmarker.py b/tests/testmarker.py index ee6651e..abb3dcb 100755 --- a/tests/testmarker.py +++ b/tests/testmarker.py @@ -26,3 +26,40 @@ def test_marker_region(): assert count >= 0 pylikwid.markerclose() + +def test_profile_decorator(): + pylikwid.markerinit() + pylikwid.markerthreadinit() + + @pylikwid.profile + def my_work(): + return list(range(100_000)) + + result = my_work() + assert len(result) == 100_000 + + nr_events, elist, time, count = pylikwid.markergetregion("my_work") + assert nr_events >= 0 + assert time >= 0 + assert count >= 0 + + pylikwid.markerclose() + + +def test_profile_decorator_with_custom_region_name(): + pylikwid.markerinit() + pylikwid.markerthreadinit() + + @pylikwid.profile(region_name="custom") + def my_work(): + return list(range(100_000)) + + result = my_work() + assert len(result) == 100_000 + + nr_events, elist, time, count = pylikwid.markergetregion("custom") + assert nr_events >= 0 + assert time >= 0 + assert count >= 0 + + pylikwid.markerclose()