2
2
default stats folders.
3
3
"""
4
4
5
+ # NOTE: Bytecode introspection modules (opcode, dis, etc.) should only
6
+ # happen when loading a single dataset. When comparing datasets, it
7
+ # could get it wrong, leading to subtle errors.
8
+
5
9
import argparse
6
10
import collections
7
11
import json
8
12
import os .path
9
- import opcode
10
13
from datetime import date
11
14
import itertools
12
15
import sys
@@ -28,6 +31,16 @@ def format_ratio(num, den):
28
31
else :
29
32
return f"{ num / den :.01%} "
30
33
34
+ def percentage_to_float (s ):
35
+ """
36
+ Converts a percentage string to a float. The empty string is returned as 0.0
37
+ """
38
+ if s == "" :
39
+ return 0.0
40
+ else :
41
+ assert s [- 1 ] == "%"
42
+ return float (s [:- 1 ])
43
+
31
44
def join_rows (a_rows , b_rows ):
32
45
"""
33
46
Joins two tables together, side-by-side, where the first column in each is a
@@ -164,7 +177,12 @@ def gather_stats(input):
164
177
165
178
if os .path .isfile (input ):
166
179
with open (input , "r" ) as fd :
167
- return json .load (fd )
180
+ stats = json .load (fd )
181
+
182
+ stats ["_stats_defines" ] = {int (k ): v for k , v in stats ["_stats_defines" ].items ()}
183
+ stats ["_defines" ] = {int (k ): v for k , v in stats ["_defines" ].items ()}
184
+ return stats
185
+
168
186
elif os .path .isdir (input ):
169
187
stats = collections .Counter ()
170
188
for filename in os .listdir (input ):
@@ -179,6 +197,16 @@ def gather_stats(input):
179
197
value = int (value )
180
198
stats [key ] += value
181
199
stats ['__nfiles__' ] += 1
200
+
201
+ import opcode
202
+
203
+ stats ["_specialized_instructions" ] = [
204
+ op for op in opcode ._specialized_opmap .keys ()
205
+ if "__" not in op
206
+ ]
207
+ stats ["_stats_defines" ] = get_stats_defines ()
208
+ stats ["_defines" ] = get_defines ()
209
+
182
210
return stats
183
211
else :
184
212
raise ValueError (f"{ input :r} is not a file or directory path" )
@@ -223,13 +251,10 @@ def kind_to_text(kind, defines, opname):
223
251
return pretty (name [len (opname )+ 1 :])
224
252
return "kind " + str (kind )
225
253
226
- def categorized_counts (opcode_stats ):
254
+ def categorized_counts (opcode_stats , specialized_instructions ):
227
255
basic = 0
228
256
specialized = 0
229
257
not_specialized = 0
230
- specialized_instructions = {
231
- op for op in opcode ._specialized_opmap .keys ()
232
- if "__" not in op }
233
258
for name , opcode_stat in opcode_stats .items ():
234
259
if "execution_count" not in opcode_stat :
235
260
continue
@@ -348,7 +373,7 @@ def emit_comparative_execution_counts(
348
373
(opcode , base_entry [0 ], head_entry [0 ],
349
374
f"{ 100 * change :0.1f} %" ))
350
375
351
- rows .sort (key = lambda x : - abs (float (x [- 1 ][: - 1 ])))
376
+ rows .sort (key = lambda x : - abs (percentage_to_float (x [- 1 ])))
352
377
353
378
emit_table (
354
379
("Name" , "Base Count:" , "Head Count:" , "Change:" ),
@@ -361,32 +386,34 @@ def get_defines():
361
386
defines = parse_kinds (spec_src )
362
387
return defines
363
388
364
- def emit_specialization_stats (opcode_stats ):
365
- defines = get_defines ()
389
+ def emit_specialization_stats (opcode_stats , defines ):
366
390
with Section ("Specialization stats" , summary = "specialization stats by family" ):
367
391
for name , opcode_stat in opcode_stats .items ():
368
392
print_specialization_stats (name , opcode_stat , defines )
369
393
370
- def emit_comparative_specialization_stats (base_opcode_stats , head_opcode_stats ):
371
- defines = get_defines ()
394
+ def emit_comparative_specialization_stats (base_opcode_stats , head_opcode_stats , defines ):
372
395
with Section ("Specialization stats" , summary = "specialization stats by family" ):
373
396
opcodes = set (base_opcode_stats .keys ()) & set (head_opcode_stats .keys ())
374
397
for opcode in opcodes :
375
398
print_comparative_specialization_stats (
376
399
opcode , base_opcode_stats [opcode ], head_opcode_stats [opcode ], defines
377
400
)
378
401
379
- def calculate_specialization_effectiveness (opcode_stats , total ):
380
- basic , not_specialized , specialized = categorized_counts (opcode_stats )
402
+ def calculate_specialization_effectiveness (
403
+ opcode_stats , total , specialized_instructions
404
+ ):
405
+ basic , not_specialized , specialized = categorized_counts (
406
+ opcode_stats , specialized_instructions
407
+ )
381
408
return [
382
409
("Basic" , basic , format_ratio (basic , total )),
383
410
("Not specialized" , not_specialized , format_ratio (not_specialized , total )),
384
411
("Specialized" , specialized , format_ratio (specialized , total )),
385
412
]
386
413
387
- def emit_specialization_overview (opcode_stats , total ):
414
+ def emit_specialization_overview (opcode_stats , total , specialized_instructions ):
388
415
with Section ("Specialization effectiveness" ):
389
- rows = calculate_specialization_effectiveness (opcode_stats , total )
416
+ rows = calculate_specialization_effectiveness (opcode_stats , total , specialized_instructions )
390
417
emit_table (("Instructions" , "Count:" , "Ratio:" ), rows )
391
418
for title , field in (("Deferred" , "specialization.deferred" ), ("Misses" , "specialization.miss" )):
392
419
total = 0
@@ -404,10 +431,16 @@ def emit_specialization_overview(opcode_stats, total):
404
431
rows = [ (name , count , format_ratio (count , total )) for (count , name ) in counts [:10 ] ]
405
432
emit_table (("Name" , "Count:" , "Ratio:" ), rows )
406
433
407
- def emit_comparative_specialization_overview (base_opcode_stats , base_total , head_opcode_stats , head_total ):
434
+ def emit_comparative_specialization_overview (
435
+ base_opcode_stats , base_total , head_opcode_stats , head_total , specialized_instructions
436
+ ):
408
437
with Section ("Specialization effectiveness" ):
409
- base_rows = calculate_specialization_effectiveness (base_opcode_stats , base_total )
410
- head_rows = calculate_specialization_effectiveness (head_opcode_stats , head_total )
438
+ base_rows = calculate_specialization_effectiveness (
439
+ base_opcode_stats , base_total , specialized_instructions
440
+ )
441
+ head_rows = calculate_specialization_effectiveness (
442
+ head_opcode_stats , head_total , specialized_instructions
443
+ )
411
444
emit_table (
412
445
("Instructions" , "Base Count:" , "Base Ratio:" , "Head Count:" , "Head Ratio:" ),
413
446
join_rows (base_rows , head_rows )
@@ -419,8 +452,7 @@ def get_stats_defines():
419
452
defines = parse_kinds (stats_src , prefix = "EVAL_CALL" )
420
453
return defines
421
454
422
- def calculate_call_stats (stats ):
423
- defines = get_stats_defines ()
455
+ def calculate_call_stats (stats , defines ):
424
456
total = 0
425
457
for key , value in stats .items ():
426
458
if "Calls to" in key :
@@ -439,17 +471,17 @@ def calculate_call_stats(stats):
439
471
rows .append ((key , value , format_ratio (value , total )))
440
472
return rows
441
473
442
- def emit_call_stats (stats ):
474
+ def emit_call_stats (stats , defines ):
443
475
with Section ("Call stats" , summary = "Inlined calls and frame stats" ):
444
- rows = calculate_call_stats (stats )
476
+ rows = calculate_call_stats (stats , defines )
445
477
emit_table (("" , "Count:" , "Ratio:" ), rows )
446
478
447
- def emit_comparative_call_stats (base_stats , head_stats ):
479
+ def emit_comparative_call_stats (base_stats , head_stats , defines ):
448
480
with Section ("Call stats" , summary = "Inlined calls and frame stats" ):
449
- base_rows = calculate_call_stats (base_stats )
450
- head_rows = calculate_call_stats (head_stats )
481
+ base_rows = calculate_call_stats (base_stats , defines )
482
+ head_rows = calculate_call_stats (head_stats , defines )
451
483
rows = join_rows (base_rows , head_rows )
452
- rows .sort (key = lambda x : - float (x [- 1 ][: - 1 ]))
484
+ rows .sort (key = lambda x : - percentage_to_float (x [- 1 ]))
453
485
emit_table (
454
486
("" , "Base Count:" , "Base Ratio:" , "Head Count:" , "Head Ratio:" ),
455
487
rows
@@ -584,9 +616,9 @@ def output_single_stats(stats):
584
616
total = get_total (opcode_stats )
585
617
emit_execution_counts (opcode_stats , total )
586
618
emit_pair_counts (opcode_stats , total )
587
- emit_specialization_stats (opcode_stats )
588
- emit_specialization_overview (opcode_stats , total )
589
- emit_call_stats (stats )
619
+ emit_specialization_stats (opcode_stats , stats [ "_defines" ] )
620
+ emit_specialization_overview (opcode_stats , total , stats [ "_specialized_instructions" ] )
621
+ emit_call_stats (stats , stats [ "_stats_defines" ] )
590
622
emit_object_stats (stats )
591
623
emit_gc_stats (stats )
592
624
with Section ("Meta stats" , summary = "Meta statistics" ):
@@ -604,12 +636,13 @@ def output_comparative_stats(base_stats, head_stats):
604
636
base_opcode_stats , base_total , head_opcode_stats , head_total
605
637
)
606
638
emit_comparative_specialization_stats (
607
- base_opcode_stats , head_opcode_stats
639
+ base_opcode_stats , head_opcode_stats , head_stats [ "_defines" ]
608
640
)
609
641
emit_comparative_specialization_overview (
610
- base_opcode_stats , base_total , head_opcode_stats , head_total
642
+ base_opcode_stats , base_total , head_opcode_stats , head_total ,
643
+ head_stats ["_specialized_instructions" ]
611
644
)
612
- emit_comparative_call_stats (base_stats , head_stats )
645
+ emit_comparative_call_stats (base_stats , head_stats , head_stats [ "_stats_defines" ] )
613
646
emit_comparative_object_stats (base_stats , head_stats )
614
647
emit_comparative_gc_stats (base_stats , head_stats )
615
648
0 commit comments