From 710ec8b052784b9ec260af3bb62580a1db166187 Mon Sep 17 00:00:00 2001 From: Matt Graham Date: Fri, 15 Dec 2023 14:40:04 +0000 Subject: [PATCH 1/3] Add option to show total time including children in flat profiles --- pyinstrument/renderers/console.py | 6 +++++- test/test_renderers.py | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/pyinstrument/renderers/console.py b/pyinstrument/renderers/console.py index 7ed88fde..9a23ec4e 100644 --- a/pyinstrument/renderers/console.py +++ b/pyinstrument/renderers/console.py @@ -26,6 +26,7 @@ def __init__( color: bool = False, flat: bool = False, time: LiteralStr["seconds", "percent_of_total"] = "seconds", + flat_time: LiteralStr["self", "total"] = "self", **kwargs: Any, ) -> None: """ @@ -33,6 +34,7 @@ def __init__( :param color: Enable color support, using ANSI color sequences. :param flat: Display a flat profile instead of a call graph. :param time: How to display the duration of each frame - ``'seconds'`` or ``'percent_of_total'`` + :param flat_time: Show ``'self'`` time or ``'total'`` time (including children) in flat profile. """ super().__init__(**kwargs) @@ -40,6 +42,7 @@ def __init__( self.color = color self.flat = flat self.time = time + self.flat_time = flat_time if self.flat and self.timeline: raise Renderer.MisconfigurationError("Cannot use timeline and flat options together.") @@ -131,7 +134,8 @@ def render_frame(self, frame: Frame, indent: str = "", child_indent: str = "") - def render_frame_flat(self, frame: Frame) -> str: def walk(frame: Frame): frame_id_to_time[frame.identifier] = ( - frame_id_to_time.get(frame.identifier, 0) + frame.total_self_time + frame_id_to_time.get(frame.identifier, 0) + + frame.total_self_time if self.flat_time == "self" else frame.time ) frame_id_to_frame[frame.identifier] = frame diff --git a/test/test_renderers.py b/test/test_renderers.py index 9f18f0b0..b551d941 100644 --- a/test/test_renderers.py +++ b/test/test_renderers.py @@ -85,3 +85,9 @@ def test_show_all_doesnt_crash( ): renderer = frame_renderer_class(show_all=True) renderer.render(profiler_session) + + +@pytest.mark.parametrize("flat_time", ["self", "total"]) +def test_console_renderer_flat_doesnt_crash(profiler_session, flat_time): + renderer = renderers.ConsoleRenderer(flat=True, flat_time=flat_time) + renderer.render(profiler_session) From b9161148f7c320210994dfecbf3fe4d0a883cc21 Mon Sep 17 00:00:00 2001 From: Matt Graham Date: Fri, 15 Dec 2023 14:56:45 +0000 Subject: [PATCH 2/3] Run pre-commit hooks to fix formatting --- pyinstrument/renderers/console.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyinstrument/renderers/console.py b/pyinstrument/renderers/console.py index 9a23ec4e..c6c94314 100644 --- a/pyinstrument/renderers/console.py +++ b/pyinstrument/renderers/console.py @@ -134,8 +134,9 @@ def render_frame(self, frame: Frame, indent: str = "", child_indent: str = "") - def render_frame_flat(self, frame: Frame) -> str: def walk(frame: Frame): frame_id_to_time[frame.identifier] = ( - frame_id_to_time.get(frame.identifier, 0) - + frame.total_self_time if self.flat_time == "self" else frame.time + frame_id_to_time.get(frame.identifier, 0) + frame.total_self_time + if self.flat_time == "self" + else frame.time ) frame_id_to_frame[frame.identifier] = frame From be95e5348f539c80348715ab785a13c17d80d78b Mon Sep 17 00:00:00 2001 From: Matt Graham Date: Thu, 1 Aug 2024 10:21:33 +0100 Subject: [PATCH 3/3] Exposing flat and flat_time options in Profiler methods --- pyinstrument/profiler.py | 16 +++++++++++++++- pyinstrument/renderers/console.py | 4 +++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/pyinstrument/profiler.py b/pyinstrument/profiler.py index ab1434dd..ebee9d3d 100644 --- a/pyinstrument/profiler.py +++ b/pyinstrument/profiler.py @@ -11,6 +11,7 @@ from pyinstrument import renderers from pyinstrument.frame import AWAIT_FRAME_IDENTIFIER, OUT_OF_CONTEXT_FRAME_IDENTIFIER +from pyinstrument.renderers.console import FlatTimeMode from pyinstrument.session import Session from pyinstrument.stack_sampler import AsyncState, StackSampler, build_call_stack, get_stack_sampler from pyinstrument.typing import LiteralStr @@ -258,6 +259,8 @@ def print( color: bool | None = None, show_all: bool = False, timeline: bool = False, + flat: bool = False, + flat_time: FlatTimeMode = "self", ): """print(file=sys.stdout, *, unicode=None, color=None, show_all=False, timeline=False) @@ -268,6 +271,8 @@ def print( :param color: Override ANSI color support detection. :param show_all: Sets the ``show_all`` parameter on the renderer. :param timeline: Sets the ``timeline`` parameter on the renderer. + :param flat: Display a flat profile instead of a call graph. + :param flat_time: Show ``'self'`` time or ``'total'`` time (including children) in flat profile. """ if unicode is None: unicode = file_supports_unicode(file) @@ -280,6 +285,8 @@ def print( color=color, show_all=show_all, timeline=timeline, + flat=flat, + flat_time=flat_time, ), file=file, ) @@ -290,13 +297,20 @@ def output_text( color: bool = False, show_all: bool = False, timeline: bool = False, + flat: bool = False, + flat_time: FlatTimeMode = "self", ) -> str: """ Return the profile output as text, as rendered by :class:`ConsoleRenderer` """ return self.output( renderer=renderers.ConsoleRenderer( - unicode=unicode, color=color, show_all=show_all, timeline=timeline + unicode=unicode, + color=color, + show_all=show_all, + timeline=timeline, + flat=flat, + flat_time=flat_time, ) ) diff --git a/pyinstrument/renderers/console.py b/pyinstrument/renderers/console.py index c6c94314..e1739656 100644 --- a/pyinstrument/renderers/console.py +++ b/pyinstrument/renderers/console.py @@ -13,6 +13,8 @@ # pyright: strict +FlatTimeMode = LiteralStr["self", "total"] + class ConsoleRenderer(FrameRenderer): """ @@ -26,7 +28,7 @@ def __init__( color: bool = False, flat: bool = False, time: LiteralStr["seconds", "percent_of_total"] = "seconds", - flat_time: LiteralStr["self", "total"] = "self", + flat_time: FlatTimeMode = "self", **kwargs: Any, ) -> None: """