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

flamegraph widget: implement scroll #32

Merged
merged 1 commit into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions flameshow/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ class Profile:
# init by post_init
lines: List = field(init=False)

frameid_to_lineno: Dict[int, int] = field(init=False)

def __post_init__(self):
"""
init_lines must be called before render
Expand All @@ -120,6 +122,7 @@ def __post_init__(self):
lines = [
[root],
]
frameid_to_lineno = {0: 0}
current = root.children
line_no = 1

Expand All @@ -129,6 +132,7 @@ def __post_init__(self):

for child in current:
line.append(child)
frameid_to_lineno[child._id] = line_no
next_line.extend(child.children)

lines.append(line)
Expand All @@ -138,3 +142,4 @@ def __post_init__(self):
t2 = time.time()
logger.info("create lines done, took %.2f seconds", t2 - t1)
self.lines = lines
self.frameid_to_lineno = frameid_to_lineno
18 changes: 14 additions & 4 deletions flameshow/render/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@

class FlameGraphScroll(VerticalScroll, inherit_bindings=False):
BINDINGS: ClassVar[list[BindingType]] = [
Binding("b", "scroll_up", "Scroll Up", show=True, key_display="B"),
Binding("b", "page_up", "Scroll Page Up", show=True, key_display="B"),
Binding(
"f,space", "scroll_down", "Scroll Down", show=True, key_display="F"
"f,space",
"page_down",
"Scroll Page Down",
show=True,
key_display="F",
),
Binding("home", "scroll_home", "Scroll Home", show=False),
Binding("end", "scroll_end", "Scroll End", show=False),
Expand Down Expand Up @@ -199,8 +203,14 @@ async def handle_view_frame_changed(self, e):
new_frame = e.frame
self.view_frame = new_frame

flamegraph = self.query_one("FlameGraph")
flamegraph.view_frame = new_frame
with self.batch_update():
flamegraph = self.query_one("FlameGraph")
flamegraph.view_frame = new_frame

region = flamegraph.get_scroll_region(new_frame)
if region:
container = self.query_one("#flamegraph-out-container")
container.scroll_to_region(region)

async def watch_sample_index(self, sample_index):
logger.info("sample index changed to %d", sample_index)
Expand Down
28 changes: 22 additions & 6 deletions flameshow/render/flamegraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
from functools import lru_cache
import logging
import time
from typing import Dict, List
from typing import Dict, List, Union

import iteround
from rich.segment import Segment
from rich.style import Style
from textual.binding import Binding
from textual.color import Color
from textual.events import Resize
from textual.geometry import Region
from textual.message import Message
from textual.reactive import reactive
from textual.strip import Strip
Expand Down Expand Up @@ -70,15 +71,17 @@ def __init__(
# pre-render
self.frame_maps = None

# manually maintain the offset
self.current_crop = None

def render_lines(self, crop):
logger.info("render_lines!! crop: %s", crop)
my_width = crop.size.width
t1 = time.time()
self.frame_maps = self.generate_frame_maps(
my_width, self.focused_stack_id
)
t2 = time.time()
logger.info("Generates frame maps, took %.4f seconds", t2 - t1)

self.current_crop = crop

return super().render_lines(crop)

@lru_cache
Expand All @@ -88,6 +91,7 @@ def generate_frame_maps(self, width, focused_stack_id):

only re-computes with width, focused_stack changing
"""
t1 = time.time()
logger.info(
"lru cache miss, Generates frame map, for width=%d,"
" focused_stack_id=%s",
Expand Down Expand Up @@ -163,7 +167,8 @@ def _generate_for_children(frame):
_generate_for_children(child)

_generate_for_children(current_focused_stack)

t2 = time.time()
logger.info("Generates frame maps done, took %.4f seconds", t2 - t1)
return frame_maps

def render_line(self, y: int) -> Strip:
Expand Down Expand Up @@ -279,6 +284,17 @@ def action_move_down(self):
return
self.post_message(self.ViewFrameChanged(new_view_info_frame))

def get_scroll_region(self, frame) -> Union[None, Region]:
crop = self.current_crop
frame_line_no = self.profile.frameid_to_lineno[frame._id]
start_y = max(0, frame_line_no - round(crop.height / 2))
if start_y == crop.y == 0:
return None
display_region = Region(crop.x, start_y, crop.width, crop.height)
logger.info("scroll to %s", display_region)
# self.scroll_to_region(display_region, top=True)
return display_region

def _get_biggest_exist_child(self, stacks):
biggest = max(stacks, key=lambda s: s.values[self.sample_index])
return biggest
Expand Down
Loading