cpython/Tools/scripts/summarize_stats.py

161 lines
5.6 KiB
Python

"""Print a summary of specialization stats for all files in the
default stats folders.
"""
import collections
import os.path
import opcode
if os.name == "nt":
DEFAULT_DIR = "c:\\temp\\py_stats\\"
else:
DEFAULT_DIR = "/tmp/py_stats/"
#Create list of all instruction names
specialized = iter(opcode._specialized_instructions)
opname = ["<0>"]
for name in opcode.opname[1:]:
if name.startswith("<"):
try:
name = next(specialized)
except StopIteration:
pass
opname.append(name)
TOTAL = "specialization.deferred", "specialization.hit", "specialization.miss", "execution_count"
def print_specialization_stats(name, family_stats):
if "specializable" not in family_stats:
return
total = sum(family_stats.get(kind, 0) for kind in TOTAL)
if total == 0:
return
print(name+":")
for key in sorted(family_stats):
if key.startswith("specialization.failure_kinds"):
continue
if key.startswith("specialization."):
label = key[len("specialization."):]
elif key == "execution_count":
label = "unquickened"
if key not in ("specialization.success", "specialization.failure"):
print(f"{label:>12}:{family_stats[key]:>12} {100*family_stats[key]/total:0.1f}%")
for key in ("specialization.success", "specialization.failure"):
label = key[len("specialization."):]
print(f" {label}:{family_stats.get(key, 0):>12}")
total_failures = family_stats.get("specialization.failure", 0)
failure_kinds = [ 0 ] * 30
for key in family_stats:
if not key.startswith("specialization.failure_kind"):
continue
_, index = key[:-1].split("[")
index = int(index)
failure_kinds[index] = family_stats[key]
for index, value in enumerate(failure_kinds):
if not value:
continue
print(f" kind {index:>2}: {value:>8} {100*value/total_failures:0.1f}%")
def gather_stats():
stats = collections.Counter()
for filename in os.listdir(DEFAULT_DIR):
with open(os.path.join(DEFAULT_DIR, filename)) as fd:
for line in fd:
key, value = line.split(":")
key = key.strip()
value = int(value.strip())
stats[key] += value
return stats
def extract_opcode_stats(stats):
opcode_stats = [ {} for _ in range(256) ]
for key, value in stats.items():
if not key.startswith("opcode"):
continue
n, _, rest = key[7:].partition("]")
opcode_stats[int(n)][rest.strip(".")] = value
return opcode_stats
def categorized_counts(opcode_stats):
basic = 0
specialized = 0
not_specialized = 0
specialized_instructions = {
op for op in opcode._specialized_instructions
if "__" not in op and "ADAPTIVE" not in op}
adaptive_instructions = {
op for op in opcode._specialized_instructions
if "ADAPTIVE" in op}
for i, opcode_stat in enumerate(opcode_stats):
if "execution_count" not in opcode_stat:
continue
count = opcode_stat['execution_count']
name = opname[i]
if "specializable" in opcode_stat:
not_specialized += count
elif name in adaptive_instructions:
not_specialized += count
elif name in specialized_instructions:
miss = opcode_stat.get("specialization.miss", 0)
not_specialized += miss
specialized += count - miss
else:
basic += count
return basic, not_specialized, specialized
def main():
stats = gather_stats()
opcode_stats = extract_opcode_stats(stats)
print("Execution counts:")
counts = []
total = 0
for i, opcode_stat in enumerate(opcode_stats):
if "execution_count" in opcode_stat:
count = opcode_stat['execution_count']
miss = 0
if "specializable" not in opcode_stat:
miss = opcode_stat.get("specialization.miss")
counts.append((count, opname[i], miss))
total += count
counts.sort(reverse=True)
cummulative = 0
for (count, name, miss) in counts:
cummulative += count
print(f"{name}: {count} {100*count/total:0.1f}% {100*cummulative/total:0.1f}%")
if miss:
print(f" Misses: {miss} {100*miss/count:0.1f}%")
print("Specialization stats:")
for i, opcode_stat in enumerate(opcode_stats):
name = opname[i]
print_specialization_stats(name, opcode_stat)
basic, not_specialized, specialized = categorized_counts(opcode_stats)
print("Specialization effectiveness:")
print(f" Base instructions {basic} {basic*100/total:0.1f}%")
print(f" Not specialized {not_specialized} {not_specialized*100/total:0.1f}%")
print(f" Specialized {specialized} {specialized*100/total:0.1f}%")
print("Call stats:")
total = 0
for key, value in stats.items():
if "Calls to" in key:
total += value
for key, value in stats.items():
if "Calls to" in key:
print(f" {key}: {value} {100*value/total:0.1f}%")
for key, value in stats.items():
if key.startswith("Frame"):
print(f" {key}: {value} {100*value/total:0.1f}%")
print("Object stats:")
total = stats.get("Object new values")
for key, value in stats.items():
if key.startswith("Object"):
if "materialize" in key:
print(f" {key}: {value} {100*value/total:0.1f}%")
else:
print(f" {key}: {value}")
total = 0
if __name__ == "__main__":
main()