Skip to content

Commit 5dcbbd8

Browse files
authored
GH-109330: Dump and compare stats using opcode names, not numbers (GH-109335)
1 parent 90cf345 commit 5dcbbd8

File tree

2 files changed

+35
-53
lines changed

2 files changed

+35
-53
lines changed

Python/specialize.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,19 @@ _Py_GetSpecializationStats(void) {
123123

124124
#define PRINT_STAT(i, field) \
125125
if (stats[i].field) { \
126-
fprintf(out, " opcode[%d]." #field " : %" PRIu64 "\n", i, stats[i].field); \
126+
fprintf(out, " opcode[%s]." #field " : %" PRIu64 "\n", _PyOpcode_OpName[i], stats[i].field); \
127127
}
128128

129129
static void
130130
print_spec_stats(FILE *out, OpcodeStats *stats)
131131
{
132132
/* Mark some opcodes as specializable for stats,
133133
* even though we don't specialize them yet. */
134-
fprintf(out, "opcode[%d].specializable : 1\n", BINARY_SLICE);
135-
fprintf(out, "opcode[%d].specializable : 1\n", STORE_SLICE);
134+
fprintf(out, "opcode[BINARY_SLICE].specializable : 1\n");
135+
fprintf(out, "opcode[STORE_SLICE].specializable : 1\n");
136136
for (int i = 0; i < 256; i++) {
137137
if (_PyOpcode_Caches[i]) {
138-
fprintf(out, "opcode[%d].specializable : 1\n", i);
138+
fprintf(out, "opcode[%s].specializable : 1\n", _PyOpcode_OpName[i]);
139139
}
140140
PRINT_STAT(i, specialization.success);
141141
PRINT_STAT(i, specialization.failure);
@@ -147,14 +147,14 @@ print_spec_stats(FILE *out, OpcodeStats *stats)
147147
for (int j = 0; j < SPECIALIZATION_FAILURE_KINDS; j++) {
148148
uint64_t val = stats[i].specialization.failure_kinds[j];
149149
if (val) {
150-
fprintf(out, " opcode[%d].specialization.failure_kinds[%d] : %"
151-
PRIu64 "\n", i, j, val);
150+
fprintf(out, " opcode[%s].specialization.failure_kinds[%d] : %"
151+
PRIu64 "\n", _PyOpcode_OpName[i], j, val);
152152
}
153153
}
154154
for (int j = 0; j < 256; j++) {
155155
if (stats[i].pair_count[j]) {
156-
fprintf(out, "opcode[%d].pair_count[%d] : %" PRIu64 "\n",
157-
i, j, stats[i].pair_count[j]);
156+
fprintf(out, "opcode[%s].pair_count[%s] : %" PRIu64 "\n",
157+
_PyOpcode_OpName[i], _PyOpcode_OpName[j], stats[i].pair_count[j]);
158158
}
159159
}
160160
}

Tools/scripts/summarize_stats.py

Lines changed: 27 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,6 @@
1616
else:
1717
DEFAULT_DIR = "/tmp/py_stats/"
1818

19-
#Create list of all instruction names
20-
specialized = iter(opcode._specialized_opmap.keys())
21-
opname = ["<0>"]
22-
for name in opcode.opname[1:]:
23-
if name.startswith("<"):
24-
try:
25-
name = next(specialized)
26-
except StopIteration:
27-
pass
28-
opname.append(name)
29-
30-
# opcode_name --> opcode
31-
# Sort alphabetically.
32-
opmap = {name: i for i, name in enumerate(opname)}
33-
opmap = dict(sorted(opmap.items()))
34-
3519
TOTAL = "specialization.hit", "specialization.miss", "execution_count"
3620

3721
def format_ratio(num, den):
@@ -200,12 +184,12 @@ def gather_stats(input):
200184
raise ValueError(f"{input:r} is not a file or directory path")
201185

202186
def extract_opcode_stats(stats):
203-
opcode_stats = [ {} for _ in range(256) ]
187+
opcode_stats = collections.defaultdict(dict)
204188
for key, value in stats.items():
205189
if not key.startswith("opcode"):
206190
continue
207-
n, _, rest = key[7:].partition("]")
208-
opcode_stats[int(n)][rest.strip(".")] = value
191+
name, _, rest = key[7:].partition("]")
192+
opcode_stats[name][rest.strip(".")] = value
209193
return opcode_stats
210194

211195
def parse_kinds(spec_src, prefix="SPEC_FAIL"):
@@ -246,11 +230,10 @@ def categorized_counts(opcode_stats):
246230
specialized_instructions = {
247231
op for op in opcode._specialized_opmap.keys()
248232
if "__" not in op}
249-
for i, opcode_stat in enumerate(opcode_stats):
233+
for name, opcode_stat in opcode_stats.items():
250234
if "execution_count" not in opcode_stat:
251235
continue
252236
count = opcode_stat['execution_count']
253-
name = opname[i]
254237
if "specializable" in opcode_stat:
255238
not_specialized += count
256239
elif name in specialized_instructions:
@@ -314,13 +297,13 @@ def emit_table(header, rows):
314297

315298
def calculate_execution_counts(opcode_stats, total):
316299
counts = []
317-
for i, opcode_stat in enumerate(opcode_stats):
300+
for name, opcode_stat in opcode_stats.items():
318301
if "execution_count" in opcode_stat:
319302
count = opcode_stat['execution_count']
320303
miss = 0
321304
if "specializable" not in opcode_stat:
322305
miss = opcode_stat.get("specialization.miss")
323-
counts.append((count, opname[i], miss))
306+
counts.append((count, name, miss))
324307
counts.sort(reverse=True)
325308
cumulative = 0
326309
rows = []
@@ -381,16 +364,17 @@ def get_defines():
381364
def emit_specialization_stats(opcode_stats):
382365
defines = get_defines()
383366
with Section("Specialization stats", summary="specialization stats by family"):
384-
for i, opcode_stat in enumerate(opcode_stats):
385-
name = opname[i]
367+
for name, opcode_stat in opcode_stats.items():
386368
print_specialization_stats(name, opcode_stat, defines)
387369

388370
def emit_comparative_specialization_stats(base_opcode_stats, head_opcode_stats):
389371
defines = get_defines()
390372
with Section("Specialization stats", summary="specialization stats by family"):
391-
for i, (base_opcode_stat, head_opcode_stat) in enumerate(zip(base_opcode_stats, head_opcode_stats)):
392-
name = opname[i]
393-
print_comparative_specialization_stats(name, base_opcode_stat, head_opcode_stat, defines)
373+
opcodes = set(base_opcode_stats.keys()) & set(head_opcode_stats.keys())
374+
for opcode in opcodes:
375+
print_comparative_specialization_stats(
376+
opcode, base_opcode_stats[opcode], head_opcode_stats[opcode], defines
377+
)
394378

395379
def calculate_specialization_effectiveness(opcode_stats, total):
396380
basic, not_specialized, specialized = categorized_counts(opcode_stats)
@@ -407,12 +391,12 @@ def emit_specialization_overview(opcode_stats, total):
407391
for title, field in (("Deferred", "specialization.deferred"), ("Misses", "specialization.miss")):
408392
total = 0
409393
counts = []
410-
for i, opcode_stat in enumerate(opcode_stats):
394+
for name, opcode_stat in opcode_stats.items():
411395
# Avoid double counting misses
412396
if title == "Misses" and "specializable" in opcode_stat:
413397
continue
414398
value = opcode_stat.get(field, 0)
415-
counts.append((value, opname[i]))
399+
counts.append((value, name))
416400
total += value
417401
counts.sort(reverse=True)
418402
if total:
@@ -539,29 +523,27 @@ def emit_comparative_gc_stats(base_stats, head_stats):
539523

540524
def get_total(opcode_stats):
541525
total = 0
542-
for opcode_stat in opcode_stats:
526+
for opcode_stat in opcode_stats.values():
543527
if "execution_count" in opcode_stat:
544528
total += opcode_stat['execution_count']
545529
return total
546530

547531
def emit_pair_counts(opcode_stats, total):
548532
pair_counts = []
549-
for i, opcode_stat in enumerate(opcode_stats):
550-
if i == 0:
551-
continue
533+
for name_i, opcode_stat in opcode_stats.items():
552534
for key, value in opcode_stat.items():
553535
if key.startswith("pair_count"):
554-
x, _, _ = key[11:].partition("]")
536+
name_j, _, _ = key[11:].partition("]")
555537
if value:
556-
pair_counts.append((value, (i, int(x))))
538+
pair_counts.append((value, (name_i, name_j)))
557539
with Section("Pair counts", summary="Pair counts for top 100 pairs"):
558540
pair_counts.sort(reverse=True)
559541
cumulative = 0
560542
rows = []
561543
for (count, pair) in itertools.islice(pair_counts, 100):
562-
i, j = pair
544+
name_i, name_j = pair
563545
cumulative += count
564-
rows.append((opname[i] + " " + opname[j], count, format_ratio(count, total),
546+
rows.append((f"{name_i} {name_j}", count, format_ratio(count, total),
565547
format_ratio(cumulative, total)))
566548
emit_table(("Pair", "Count:", "Self:", "Cumulative:"),
567549
rows
@@ -577,18 +559,18 @@ def emit_pair_counts(opcode_stats, total):
577559
successors[first][second] = count
578560
total_predecessors[second] += count
579561
total_successors[first] += count
580-
for name, i in opmap.items():
581-
total1 = total_predecessors[i]
582-
total2 = total_successors[i]
562+
for name in opcode_stats.keys():
563+
total1 = total_predecessors[name]
564+
total2 = total_successors[name]
583565
if total1 == 0 and total2 == 0:
584566
continue
585567
pred_rows = succ_rows = ()
586568
if total1:
587-
pred_rows = [(opname[pred], count, f"{count/total1:.1%}")
588-
for (pred, count) in predecessors[i].most_common(5)]
569+
pred_rows = [(pred, count, f"{count/total1:.1%}")
570+
for (pred, count) in predecessors[name].most_common(5)]
589571
if total2:
590-
succ_rows = [(opname[succ], count, f"{count/total2:.1%}")
591-
for (succ, count) in successors[i].most_common(5)]
572+
succ_rows = [(succ, count, f"{count/total2:.1%}")
573+
for (succ, count) in successors[name].most_common(5)]
592574
with Section(name, 3, f"Successors and predecessors for {name}"):
593575
emit_table(("Predecessors", "Count:", "Percentage:"),
594576
pred_rows

0 commit comments

Comments
 (0)