summaryrefslogtreecommitdiffstats
path: root/Tools/scripts/summarize_stats.py
blob: 1271c194e96a1064e8a8fc82603cf1ea47e31f1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
"""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()