Skip to content

Commit 431c404

Browse files
committed
Timeline view: Add string memoization
1 parent 69947c2 commit 431c404

File tree

4 files changed

+136
-38
lines changed

4 files changed

+136
-38
lines changed

lglpy/timeline/data/processed_trace.py

Lines changed: 86 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,31 @@ class GPUWorkload:
6161
PARENS = re.compile(r'(\(.*\))')
6262
RESOLUTION = re.compile(r'\d+x\d+')
6363
WHITESPACE = re.compile(r'\s\s+')
64+
MEMO = dict()
65+
66+
@classmethod
67+
def memoize(cls, string: str) -> str:
68+
'''
69+
Get a memoized version of a string to reduce runtime memory use and
70+
improve rendering performance.
71+
72+
Args:
73+
string: User string to memoize.
74+
75+
Return:
76+
Memoized copy of a string.
77+
'''
78+
memo = GPUWorkload.MEMO
79+
if string not in memo:
80+
memo[string] = string
81+
return memo[string]
82+
83+
@classmethod
84+
def clear_memoize_cache(cls) -> None:
85+
'''
86+
Clear the local memoization cache.
87+
'''
88+
GPUWorkload.MEMO.clear()
6489

6590
def __init__(
6691
self, event: RenderstageEvent, metadata: Optional[MetadataWork]):
@@ -105,7 +130,8 @@ def get_label_name_full(self) -> Optional[str]:
105130
return None
106131

107132
if not LABEL_HEURISTICS:
108-
self.parsed_label_name_full = self.label_stack[-1]
133+
label = GPUWorkload.memoize(self.label_stack[-1])
134+
self.parsed_label_name_full = label
109135
return self.parsed_label_name_full
110136

111137
# Create a copy we can edit ...
@@ -146,6 +172,7 @@ def get_label_name_full(self) -> Optional[str]:
146172
else:
147173
label = '.'.join(labels)
148174

175+
label = GPUWorkload.memoize(label)
149176
self.parsed_label_name_full = label
150177
return self.parsed_label_name_full
151178

@@ -181,6 +208,7 @@ def get_label_name(self) -> Optional[str]:
181208
postfix = label[-half_max:]
182209
label = f'{prefix}...{postfix}'
183210

211+
label = GPUWorkload.memoize(label)
184212
self.parsed_label_name = label
185213
return self.parsed_label_name
186214

@@ -239,7 +267,8 @@ def get_long_label(self) -> str:
239267
'''
240268
# Subclass will override this if metadata exists
241269
# Submit ID isn't useful, but traces back to Perfetto data for debug
242-
return f'Submit: {self.submit_id}'
270+
label = f'Submit: {self.submit_id}'
271+
return GPUWorkload.memoize(label)
243272

244273
def get_short_label(self) -> str:
245274
'''
@@ -250,7 +279,8 @@ def get_short_label(self) -> str:
250279
'''
251280
# Subclass will override this if metadata exists
252281
# Submit ID isn't useful, but traces back to Perfetto data for debug
253-
return f'Submit: {self.submit_id}'
282+
label = f'Submit: {self.submit_id}'
283+
return GPUWorkload.memoize(label)
254284

255285
def get_key_value_properties(self) -> dict[str, str]:
256286
'''
@@ -353,7 +383,10 @@ def get_resolution_str(self) -> str:
353383
Returns:
354384
Returns the label for use in the UI.
355385
'''
356-
return f'{self.width}x{self.height}'
386+
label = f'{self.width}x{self.height}'
387+
label = self.memoize(label)
388+
return label
389+
357390

358391
def get_draw_count_str(self) -> str:
359392
'''
@@ -368,7 +401,8 @@ def get_draw_count_str(self) -> str:
368401
if self.draw_call_count == 1:
369402
return '1 draw'
370403

371-
return f'{self.draw_call_count} draws'
404+
label = f'{self.draw_call_count} draws'
405+
return self.memoize(label)
372406

373407
def get_subpass_count_str(self) -> str:
374408
'''
@@ -378,7 +412,8 @@ def get_subpass_count_str(self) -> str:
378412
Returns the label for use in the UI.
379413
'''
380414
es = '' if self.subpass_count == 1 else 'es'
381-
return f'{self.subpass_count} subpass{es}'
415+
label = f'{self.subpass_count} subpass{es}'
416+
return self.memoize(label)
382417

383418
def get_attachment_present_str(self) -> str:
384419
'''
@@ -388,7 +423,8 @@ def get_attachment_present_str(self) -> str:
388423
Returns the label for use in the UI.
389424
'''
390425
bindings = [x.binding for x in self.attachments]
391-
return self.get_compact_string(bindings)
426+
label = self.get_compact_str(bindings)
427+
return GPUWorkload.memoize(label)
392428

393429
def get_attachment_loadop_str(self) -> str:
394430
'''
@@ -398,7 +434,8 @@ def get_attachment_loadop_str(self) -> str:
398434
Returns the label for use in the UI.
399435
'''
400436
bindings = [x.binding for x in self.attachments if x.is_loaded]
401-
return self.get_compact_string(bindings)
437+
label = self.get_compact_str(bindings)
438+
return GPUWorkload.memoize(label)
402439

403440
def get_attachment_storeop_str(self) -> str:
404441
'''
@@ -408,10 +445,11 @@ def get_attachment_storeop_str(self) -> str:
408445
Returns the label for use in the UI.
409446
'''
410447
bindings = [x.binding for x in self.attachments if x.is_stored]
411-
return self.get_compact_string(bindings)
448+
label = self.get_compact_str(bindings)
449+
return GPUWorkload.memoize(label)
412450

413451
@classmethod
414-
def get_compact_string(cls, bindings: list[str]) -> str:
452+
def get_compact_str(cls, bindings: list[str]) -> str:
415453
'''
416454
Get the compact UI string for a set of attachment bind points.
417455
@@ -422,7 +460,8 @@ def get_compact_string(cls, bindings: list[str]) -> str:
422460
A binding string of the form, e.g. "C0124DS".
423461
'''
424462
merge = ''.join(bindings)
425-
return ''.join([j for i, j in enumerate(merge) if j not in merge[:i]])
463+
label = ''.join([j for i, j in enumerate(merge) if j not in merge[:i]])
464+
return GPUWorkload.memoize(label)
426465

427466
def get_attachment_long_label(self) -> str:
428467
'''
@@ -441,7 +480,8 @@ def get_attachment_long_label(self) -> str:
441480
if stored:
442481
stored = f' > store({stored}) '
443482

444-
return f'{loaded}[{present}]{stored}'
483+
label = f'{loaded}[{present}]{stored}'
484+
return GPUWorkload.memoize(label)
445485

446486
def get_attachment_short_label(self) -> str:
447487
'''
@@ -451,7 +491,8 @@ def get_attachment_short_label(self) -> str:
451491
A string showing attachments without load/storeOp usage.
452492
'''
453493
present = self.get_attachment_present_str()
454-
return f'[{present}]'
494+
label = f'[{present}]'
495+
return GPUWorkload.memoize(label)
455496

456497
def get_long_label(self) -> str:
457498
'''
@@ -471,7 +512,8 @@ def get_long_label(self) -> str:
471512
line = self.get_attachment_long_label()
472513
lines.append(line)
473514

474-
return '\n'.join(lines)
515+
label = '\n'.join(lines)
516+
return GPUWorkload.memoize(label)
475517

476518
def get_short_label(self) -> str:
477519
'''
@@ -488,7 +530,8 @@ def get_short_label(self) -> str:
488530
line = self.get_attachment_short_label()
489531
lines.append(line)
490532

491-
return '\n'.join(lines)
533+
label = '\n'.join(lines)
534+
return GPUWorkload.memoize(label)
492535

493536

494537
class GPUDispatch(GPUWorkload):
@@ -547,7 +590,8 @@ def get_resolution_str(self) -> str:
547590
if self.groups_z > 1:
548591
dims.append(self.groups_z)
549592

550-
return f'{"x".join([str(dim) for dim in dims])} groups'
593+
label = f'{"x".join([str(dim) for dim in dims])} groups'
594+
return GPUWorkload.memoize(label)
551595

552596
def get_long_label(self) -> str:
553597
'''
@@ -562,7 +606,8 @@ def get_long_label(self) -> str:
562606
lines.append(label_name)
563607

564608
lines.append(self.get_short_label())
565-
return '\n'.join(lines)
609+
label = '\n'.join(lines)
610+
return GPUWorkload.memoize(label)
566611

567612
def get_short_label(self) -> str:
568613
'''
@@ -574,7 +619,8 @@ def get_short_label(self) -> str:
574619
lines = []
575620
line = self.get_resolution_str()
576621
lines.append(line)
577-
return '\n'.join(lines)
622+
label = '\n'.join(lines)
623+
return GPUWorkload.memoize(label)
578624

579625

580626
class GPUTraceRays(GPUWorkload):
@@ -633,7 +679,8 @@ def get_resolution_str(self) -> str:
633679
if self.items_z > 1:
634680
dims.append(self.items_z)
635681

636-
return f'{"x".join([str(dim) for dim in dims])} items'
682+
label = f'{"x".join([str(dim) for dim in dims])} items'
683+
return GPUWorkload.memoize(label)
637684

638685
def get_long_label(self) -> str:
639686
'''
@@ -648,7 +695,8 @@ def get_long_label(self) -> str:
648695
lines.append(label_name)
649696

650697
lines.append(self.get_short_label())
651-
return '\n'.join(lines)
698+
label = '\n'.join(lines)
699+
return GPUWorkload.memoize(label)
652700

653701
def get_short_label(self) -> str:
654702
'''
@@ -659,7 +707,8 @@ def get_short_label(self) -> str:
659707
'''
660708
lines = []
661709
lines.append(self.get_resolution_str())
662-
return '\n'.join(lines)
710+
label = '\n'.join(lines)
711+
return GPUWorkload.memoize(label)
663712

664713

665714
class GPUImageTransfer(GPUWorkload):
@@ -715,7 +764,8 @@ def get_transfer_size_str(self) -> str:
715764
return f'? pixels'
716765

717766
s = 's' if self.pixel_count != 1 else ''
718-
return f'{self.pixel_count} pixel{s}'
767+
label = f'{self.pixel_count} pixel{s}'
768+
return GPUWorkload.memoize(label)
719769

720770
def get_long_label(self) -> str:
721771
'''
@@ -732,7 +782,8 @@ def get_long_label(self) -> str:
732782
line = f'{self.transfer_type} ({self.get_transfer_size_str()})'
733783
lines.append(line)
734784

735-
return '\n'.join(lines)
785+
label = '\n'.join(lines)
786+
return GPUWorkload.memoize(label)
736787

737788
def get_short_label(self) -> str:
738789
'''
@@ -797,7 +848,8 @@ def get_transfer_size_str(self) -> str:
797848
return f'? bytes'
798849

799850
s = 's' if self.byte_count != 1 else ''
800-
return f'{self.byte_count} byte{s}'
851+
label = f'{self.byte_count} byte{s}'
852+
return GPUWorkload.memoize(label)
801853

802854
def get_long_label(self) -> str:
803855
'''
@@ -814,7 +866,8 @@ def get_long_label(self) -> str:
814866
line = f'{self.transfer_type} ({self.get_transfer_size_str()})'
815867
lines.append(line)
816868

817-
return '\n'.join(lines)
869+
label = '\n'.join(lines)
870+
return GPUWorkload.memoize(label)
818871

819872
def get_short_label(self) -> str:
820873
'''
@@ -884,7 +937,8 @@ def get_transfer_size_str(self) -> str:
884937
return f'? primitives'
885938

886939
s = 's' if self.primitive_count != 1 else ''
887-
return f'{self.primitive_count} primitive{s}'
940+
label = f'{self.primitive_count} primitive{s}'
941+
return GPUWorkload.memoize(label)
888942

889943
def get_long_label(self) -> str:
890944
'''
@@ -901,7 +955,8 @@ def get_long_label(self) -> str:
901955
line = f'{self.build_type} ({self.get_transfer_size_str()})'
902956
lines.append(line)
903957

904-
return '\n'.join(lines)
958+
label = '\n'.join(lines)
959+
return GPUWorkload.memoize(label)
905960

906961
def get_short_label(self) -> str:
907962
'''
@@ -963,7 +1018,8 @@ def get_transfer_size_str(self) -> str:
9631018
return f'? bytes'
9641019

9651020
s = 's' if self.byte_count != 1 else ''
966-
return f'{self.byte_count} byte{s}'
1021+
label = f'{self.byte_count} byte{s}'
1022+
return GPUWorkload.memoize(label)
9671023

9681024
def get_long_label(self) -> str:
9691025
'''
@@ -980,7 +1036,8 @@ def get_long_label(self) -> str:
9801036
line = f'{self.transfer_type} ({self.get_transfer_size_str()})'
9811037
lines.append(line)
9821038

983-
return '\n'.join(lines)
1039+
label = '\n'.join(lines)
1040+
return GPUWorkload.memoize(label)
9841041

9851042
def get_short_label(self) -> str:
9861043
'''

0 commit comments

Comments
 (0)