Skip to content

Commit

Permalink
Add flat mode to console renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
matthiasdiener committed May 3, 2023
1 parent 19c86c2 commit 4040e81
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 7 deletions.
8 changes: 8 additions & 0 deletions pyinstrument/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ def total_self_time(self) -> float:

return self_time

@property
def exclusive_time(self) -> float:
excl_time = self.time
for child in self.children:
excl_time -= child.time

return excl_time

@property
def function(self) -> str:
return self._identifier_parts[0]
Expand Down
72 changes: 65 additions & 7 deletions pyinstrument/renderers/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __init__(
self,
unicode: bool = False,
color: bool = False,
flat: bool = False,
time: LiteralStr["seconds", "percent_of_total"] = "seconds",
**kwargs: Any,
):
Expand All @@ -34,6 +35,7 @@ def __init__(

self.unicode = unicode
self.color = color
self.flat = flat
self.colors = self.colors_enabled if color else self.colors_disabled
self.time = time

Expand All @@ -48,7 +50,10 @@ def render(self, session: Session):

self.root_frame = frame

result += self.render_frame(self.root_frame)
if self.flat:
result += self.render_frame_flat(self.root_frame)
else:
result += self.render_frame(self.root_frame)
result += "\n"

return result
Expand Down Expand Up @@ -84,9 +89,9 @@ def render_frame(self, frame: Frame, indent: str = "", child_indent: str = "") -
):
if self.time == "percent_of_total":
percent = self.frame_proportion_of_total_time(frame) * 100
time_str = self._ansi_color_for_time(frame) + f"{percent:.0f}%" + self.colors.end
time_str = self._ansi_color_for_time(frame.time) + f"{percent:.0f}%" + self.colors.end
else:
time_str = self._ansi_color_for_time(frame) + f"{frame.time:.3f}" + self.colors.end
time_str = self._ansi_color_for_time(frame.time) + f"{frame.time:.3f}" + self.colors.end

name_color = self._ansi_color_for_name(frame)

Expand Down Expand Up @@ -137,11 +142,64 @@ def render_frame(self, frame: Frame, indent: str = "", child_indent: str = "") -

return result

def frame_proportion_of_total_time(self, frame: Frame):
return frame.time / self.root_frame.time
def render_frame_flat(self, frame: Frame) -> str:
frame_desc_to_excl_time = {}
frame_desc_to_frame = {}

from dataclasses import dataclass

@dataclass(frozen=True, eq=True)
class FrameDesc:
code_position_short: str
function: str

def walk(frame: Frame):
frame_desc = FrameDesc(
frame.code_position_short, frame.function)
frame_desc_to_excl_time[frame_desc] = frame_desc_to_excl_time.get(frame_desc, 0) + frame.exclusive_time
frame_desc_to_frame[frame_desc] = frame

for child in frame.children:
walk(child)

walk(frame)

cost_list = sorted(
frame_desc_to_excl_time.items(),
key=(lambda item: item[1]),
reverse=True)

res = ""

for frame_desc, excl_time in cost_list:
if self.time == "percent_of_total":
val = excl_time / frame.time * 100
unit = "%"
else:
val = excl_time
unit = "s"

color = self._ansi_color_for_time(excl_time)

res += \
"{color}{val:.3f}{unit}{c.end} {name_color}{function}{c.end} {c.faint}{code_position}{c.end}\n".format(
color=color,
val=val,
unit=unit,
c=self.colors,
name_color=self._ansi_color_for_name(
frame_desc_to_frame[frame_desc]),
function=frame_desc.function,
code_position=frame_desc.code_position_short,
)

return res

def frame_proportion_of_total_time(self, time: float):
return time / self.root_frame.time

def _ansi_color_for_time(self, frame: Frame):
proportion_of_total = self.frame_proportion_of_total_time(frame)
def _ansi_color_for_time(self, time: float):
proportion_of_total = self.frame_proportion_of_total_time(time)

if proportion_of_total > 0.6:
return self.colors.red
Expand Down

0 comments on commit 4040e81

Please sign in to comment.