21
21
from pathlib import Path
22
22
import re
23
23
import sys
24
+ import textwrap
24
25
from typing import Any , Callable , TextIO , TypeAlias
25
26
26
27
@@ -389,17 +390,58 @@ def get_optimization_stats(self) -> dict[str, tuple[int, int | None]]:
389
390
low_confidence = self ._data ["Optimization low confidence" ]
390
391
391
392
return {
392
- "Optimization attempts" : (attempts , None ),
393
- "Traces created" : (created , attempts ),
394
- "Trace stack overflow" : (trace_stack_overflow , attempts ),
395
- "Trace stack underflow" : (trace_stack_underflow , attempts ),
396
- "Trace too long" : (trace_too_long , attempts ),
397
- "Trace too short" : (trace_too_short , attempts ),
398
- "Inner loop found" : (inner_loop , attempts ),
399
- "Recursive call" : (recursive_call , attempts ),
400
- "Low confidence" : (low_confidence , attempts ),
401
- "Traces executed" : (executed , None ),
402
- "Uops executed" : (uops , executed ),
393
+ Doc (
394
+ "Optimization attempts" ,
395
+ """
396
+ The number of times a potential trace is identified. Specifically,
397
+ this occurs in the JUMP BACKWARD instruction when the counter reaches
398
+ a threshold.
399
+ """ ,
400
+ ): (
401
+ attempts ,
402
+ None ,
403
+ ),
404
+ Doc (
405
+ "Traces created" , "The number of traces that were successfully created."
406
+ ): (created , attempts ),
407
+ Doc (
408
+ "Trace stack overflow" ,
409
+ "A trace is truncated because it would require more than 5 stack frames." ,
410
+ ): (trace_stack_overflow , attempts ),
411
+ Doc (
412
+ "Trace stack underflow" ,
413
+ "A potential trace is abandoned because it pops more frames than it pushes." ,
414
+ ): (trace_stack_underflow , attempts ),
415
+ Doc (
416
+ "Trace too long" ,
417
+ "A trace is truncated because it is longer than the instruction buffer." ,
418
+ ): (trace_too_long , attempts ),
419
+ Doc (
420
+ "Trace too short" ,
421
+ "A potential trace is abandoced because it it too short." ,
422
+ ): (trace_too_short , attempts ),
423
+ Doc (
424
+ "Inner loop found" , "A trace is truncated because it has an inner loop"
425
+ ): (inner_loop , attempts ),
426
+ Doc (
427
+ "Recursive call" ,
428
+ "A trace is truncated because it has a recursive call." ,
429
+ ): (recursive_call , attempts ),
430
+ Doc (
431
+ "Low confidence" ,
432
+ """
433
+ A trace is abandoned because the likelihood of the jump to top being
434
+ taken is too low.
435
+ """ ,
436
+ ): (low_confidence , attempts ),
437
+ Doc ("Traces executed" , "The number of traces that were executed" ): (
438
+ executed ,
439
+ None ,
440
+ ),
441
+ Doc ("Uops executed" , "The total number of uops that were executed" ): (
442
+ uops ,
443
+ executed ,
444
+ ),
403
445
}
404
446
405
447
def get_histogram (self , prefix : str ) -> list [tuple [int , int ]]:
@@ -415,12 +457,21 @@ def get_histogram(self, prefix: str) -> list[tuple[int, int]]:
415
457
def get_rare_events (self ) -> list [tuple [str , int ]]:
416
458
prefix = "Rare event "
417
459
return [
418
- (key [len (prefix ) + 1 : - 1 ].replace ("_" , " " ), val )
460
+ (key [len (prefix ) + 1 : - 1 ].replace ("_" , " " ), val )
419
461
for key , val in self ._data .items ()
420
462
if key .startswith (prefix )
421
463
]
422
464
423
465
466
+ class Doc :
467
+ def __init__ (self , text : str , doc : str ):
468
+ self .text = text
469
+ self .doc = textwrap .dedent (doc ).strip ()
470
+
471
+ def markdown (self ) -> str :
472
+ return f'{ self .text } [ⓘ](## "{ self .doc } ")'
473
+
474
+
424
475
class Count (int ):
425
476
def markdown (self ) -> str :
426
477
return format (self , ",d" )
@@ -568,13 +619,16 @@ def __init__(
568
619
title : str = "" ,
569
620
summary : str = "" ,
570
621
part_iter = None ,
622
+ * ,
571
623
comparative : bool = True ,
624
+ doc : str = "" ,
572
625
):
573
626
self .title = title
574
627
if not summary :
575
628
self .summary = title .lower ()
576
629
else :
577
630
self .summary = summary
631
+ self .doc = textwrap .dedent (doc )
578
632
if part_iter is None :
579
633
part_iter = []
580
634
if isinstance (part_iter , list ):
@@ -628,6 +682,10 @@ def execution_count_section() -> Section:
628
682
join_mode = JoinMode .CHANGE_ONE_COLUMN ,
629
683
)
630
684
],
685
+ doc = """
686
+ The "miss ratio" column shows the percentage of times the instruction
687
+ executed that it deoptimized.
688
+ """ ,
631
689
)
632
690
633
691
@@ -655,7 +713,7 @@ def calc_pair_count_table(stats: Stats) -> Rows:
655
713
656
714
return Section (
657
715
"Pair counts" ,
658
- "Pair counts for top 100 pairs " ,
716
+ "Pair counts for top 100 Tier 1 instructions " ,
659
717
[
660
718
Table (
661
719
("Pair" , "Count:" , "Self:" , "Cumulative:" ),
@@ -705,7 +763,7 @@ def iter_pre_succ_pairs_tables(base_stats: Stats, head_stats: Stats | None = Non
705
763
706
764
return Section (
707
765
"Predecessor/Successor Pairs" ,
708
- "Top 5 predecessors and successors of each opcode" ,
766
+ "Top 5 predecessors and successors of each Tier 1 opcode" ,
709
767
iter_pre_succ_pairs_tables ,
710
768
comparative = False ,
711
769
)
@@ -1073,8 +1131,19 @@ def iter_optimization_tables(base_stats: Stats, head_stats: Stats | None = None)
1073
1131
1074
1132
1075
1133
def rare_event_section () -> Section :
1134
+ RARE_DOCS = {
1135
+ "set class" : "Setting an object's class, `obj.__class__ = ...`" ,
1136
+ "set bases" : "Setting the bases of a class, `cls.__bases__ = ...`" ,
1137
+ "set eval frame func" : (
1138
+ "Setting the PEP 523 frame eval function "
1139
+ "`_PyInterpreterState_SetFrameEvalFunc()`"
1140
+ ),
1141
+ "builtin dict" : "Modifying the builtins, `__builtins__.__dict__[var] = ...`" ,
1142
+ "func modification" : "Modifying a function, e.g. `func.__defaults__ = ...`, etc." ,
1143
+ }
1144
+
1076
1145
def calc_rare_event_table (stats : Stats ) -> Table :
1077
- return [(x , Count (y )) for x , y in stats .get_rare_events ()]
1146
+ return [(Doc ( x , RARE_DOCS [ x ]) , Count (y )) for x , y in stats .get_rare_events ()]
1078
1147
1079
1148
return Section (
1080
1149
"Rare events" ,
@@ -1134,6 +1203,9 @@ def to_markdown(x):
1134
1203
print ("<details>" , file = out )
1135
1204
print ("<summary>" , obj .summary , "</summary>" , file = out )
1136
1205
print (file = out )
1206
+ if obj .doc :
1207
+ print (obj .doc , file = out )
1208
+
1137
1209
if head_stats is not None and obj .comparative is False :
1138
1210
print ("Not included in comparative output.\n " )
1139
1211
else :
0 commit comments