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

Improve info panel handling for new timeline #42

Merged
merged 5 commits into from
Jan 9, 2025
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
3 changes: 1 addition & 2 deletions lglpy/android/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,8 @@ def is_package_32bit(cls, conn: ADBConnect, package: str) -> bool:
command = f'pm dump {package} | grep primaryCpuAbi'
log = conn.adb_run(command)
pattern = re.compile('primaryCpuAbi=(\\S+)')
match = pattern.search(log)

if match:
if match := pattern.search(log):
log_abi = match.group(1)
if log_abi != 'null':
preferred_abi = log_abi
Expand Down
113 changes: 104 additions & 9 deletions lglpy/timeline/data/processed_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,15 @@
single combined representation.
'''

import re
from typing import Optional, Union

from .raw_trace import RawTrace, RenderstageEvent, MetadataWork, \
MetadataRenderPass, MetadataDispatch, MetadataBufferTransfer, \
MetadataImageTransfer, GPUStreamID
MetadataImageTransfer, GPUStreamID, GPUStageID

LABEL_HEURISTICS = True
LABEL_MAX_LEN = 60


class GPUWorkload:
Expand All @@ -47,6 +51,11 @@ class GPUWorkload:
label_stack: Application debug label stack.
'''

FRAME_LABEL = re.compile(r'^Frame (\d+)$')
PARENS = re.compile(r'(\(.*\))')
RESOLUTION = re.compile(r'\d+x\d+')
WHITESPACE = re.compile(r'\s\s+')

def __init__(
self, event: RenderstageEvent, metadata: Optional[MetadataWork]):
'''
Expand All @@ -66,10 +75,96 @@ def __init__(
# Common data we get from the layer metadata
self.frame = None
self.label_stack = None
self.parsed_label_name = None

if metadata:
self.frame = metadata.frame
self.label_stack = metadata.label_stack

def get_label_name(self) -> Optional[str]:
'''
Get a cleaned up label name for a workload.

Warning: The heuristics here are not robust.

Returns:
A modified label for use in the UI.
'''
# No label to parse
if not self.label_stack:
return None

# Cached label already parsed
if self.parsed_label_name is not None:
return self.parsed_label_name

if not LABEL_HEURISTICS:
return self.label_stack[-1]

# Create a copy we can edit ...
labels = list(self.label_stack)

# Heuristic to remove app-concatenated leaf nodes in UE
if 'Scene.' in labels[-1]:
del labels[-1]

# Pop off low value root nodes in UE captures
if labels and self.FRAME_LABEL.match(labels[0]):
del labels[0]

if labels and labels[0] == 'Scene':
del labels[0]

# String substitutions
for i, label in enumerate(labels):
label = self.PARENS.sub('', label)
label = self.RESOLUTION.sub('', label)
label = self.WHITESPACE.sub(' ', label)
label = label.replace('Light::', '')
labels[i] = label.strip()

# Stack prefix substitutions
for i, label in enumerate(labels):
for j in range(i + 1, len(labels)):
next_label = labels[j]
if not next_label.startswith(label):
break
labels[j] = next_label[len(label):].strip()

# Remove labels that are now empty
labels = list(filter(bool, labels))

if not labels:
label = ''
else:
label = '.'.join(labels)

if len(label) > LABEL_MAX_LEN:
half_max = LABEL_MAX_LEN // 2
prefix = label[0:half_max]
postfix = label[-half_max:]
label = f'{prefix}...{postfix}'

self.parsed_label_name = label
return self.parsed_label_name

def get_workload_name(self) -> str:
'''
Get a name for the workload.

This is based on the application debug label if there is one, but
with some heuristics to try and clean is up ...

Returns:
Returns the label for use in the UI.
'''
if not self.label_stack:
return GPUStageID.get_ui_name(self.stage)

label = self.get_label_name()
assert label
return label

def get_long_label(self) -> str:
'''
Get the long form label for this workload.
Expand Down Expand Up @@ -177,8 +272,8 @@ def get_long_label(self) -> str:
'''
lines = []

if self.label_stack:
lines.append(self.label_stack[-1])
if label_name := self.get_label_name():
lines.append(label_name)

if self.draw_call_count < 0:
draw_str = 'Unknown draws'
Expand Down Expand Up @@ -243,8 +338,8 @@ def get_long_label(self) -> str:
'''
lines = []

if self.label_stack:
lines.append(self.label_stack[-1])
if label_name := self.get_label_name():
lines.append(label_name)

lines.append(self.get_short_label())
return '\n'.join(lines)
Expand Down Expand Up @@ -309,8 +404,8 @@ def get_long_label(self) -> str:
'''
lines = []

if self.label_stack:
lines.append(self.label_stack[-1])
if label_name := self.get_label_name():
lines.append(label_name)

# If indirect then show a placeholder
if self.pixel_count == -1:
Expand Down Expand Up @@ -365,8 +460,8 @@ def get_long_label(self) -> str:
'''
lines = []

if self.label_stack:
lines.append(self.label_stack[-1])
if label_name := self.get_label_name():
lines.append(label_name)

# If indirect then show a placeholder
if self.byte_count == -1:
Expand Down
4 changes: 2 additions & 2 deletions lglpy/timeline/data/raw_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
JSONType = Any


class GPUStreamID(enum.Enum):
class GPUStreamID(enum.IntEnum):
'''
Symbolic mapping of known GPU scheduling stream IDs.

Expand Down Expand Up @@ -80,7 +80,7 @@ def get_ui_name(cls, stream_id) -> str:
return human_names[stream_id]


class GPUStageID(enum.Enum):
class GPUStageID(enum.IntEnum):
'''
Symbolic mapping of known GPU workload stage IDs.

Expand Down
Loading