-
Notifications
You must be signed in to change notification settings - Fork 337
/
csv_formats.py
123 lines (106 loc) · 4 KB
/
csv_formats.py
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
# distinguish the bewildering variety of perf/toplev CSV formats
from __future__ import print_function
import sys
import re
from collections import namedtuple
def is_val(n):
return re.match(r'-?[0-9.]+%?|<.*>', n) is not None
def is_cpu(n):
return re.match(r'(CPU)|(S\d+(-C\d+)?)|C\d+|all', n) is not None
def is_socket(n):
return re.match(r'S\d+', n) is not None
def is_event(n):
return re.match(r'[a-zA-Z.-]+', n) is not None
def is_number(n):
return re.match(r'\s*[0-9]+', n) is not None
def is_ts(n):
return re.match(r'\s*[0-9.]+', n) is not None or n == "SUMMARY"
def is_unit(n):
return re.match(r'(% )?[a-zA-Z]*( <)?', n) is not None
def is_running(n):
return is_number(n)
def is_enabled(n):
return is_number(n)
formats = (
# 0.100997872;CPU0;4612809;;inst_retired_any_0;3491526;2.88 new perf
(is_ts, is_cpu, is_val, is_unit, is_event, is_enabled, is_running),
# 1.354075473,0,cpu-migrations old perf w/o cpu
(is_ts, is_val, is_event),
# 1.354075473,CPU0,0,cpu-migrations old perf w/ cpu
(is_ts, is_cpu, is_val, is_event),
# 0.799553738,137765150,,branches new perf with unit
(is_ts, is_val, is_unit, is_event),
# 0.799553738,CPU1,137765150,,branches new perf with unit and cpu
(is_ts, is_cpu, is_val, is_unit, is_event),
# 0.100879059,402.603109,,task-clock,402596410,100.00 new perf with unit without cpu and stats
(is_ts, is_val, is_unit, is_event, is_running, is_enabled),
# 1.001131873,S0,Backend_Bound.Memory_Bound,13.3,% Slots <,,,0.0,3.0,,
# 0.200584389,0,FrontendBound.Branch Resteers,15.87%,above,"", toplev w/ cpu
(is_ts, is_cpu, is_event, is_val, is_unit),
# 1.001365014,CPU2,1819888,,instructions,93286388,100.00 new perf w/ unit w/ cpu and stats
(is_ts, is_cpu, is_val, is_unit, is_event, is_running, is_enabled),
# 0.609113353,S0,4,405.454531,,task-clock,405454468,100.00 perf --per-socket with cores
(is_ts, is_socket, is_number, is_val, is_unit, is_event, is_running, is_enabled),
# 0.806231582,S0,4,812751,,instructions older perf --per-socket w/ cores w/o stats
(is_ts, is_socket, is_number, is_val, is_unit, is_event),
# 0.936482669,C1-T0,Frontend_Bound.Frontend_Latency.ITLB_Misses,0.39,%below,,itlb_misses.walk_completed,,
# 0.301553743,C1,Retiring,31.81,%,,,,
# 0.200584389,FrontendBound.Branch Resteers,15.87%,above,"", toplev single thread
(is_ts, is_event, is_val),
)
fmtmaps = {
is_ts: 0,
is_cpu: 1,
is_event: 2,
is_val: 3,
is_enabled: 4,
is_running: 5,
is_unit: 6
}
Row = namedtuple('Row', ['ts', 'cpu', 'ev', 'val', 'enabled', 'running', 'unit'])
def check_format(fmt, row):
if all([x(n.strip()) for (x, n) in zip(fmt, row)]):
vals = [None] * 7
for i, j in enumerate(fmt):
if j in fmtmaps:
vals[fmtmaps[j]] = row[i]
r = Row._make(vals)
return r
return False
fmt_cache = formats[0]
def parse_csv_row(row, error_exit=False):
if len(row) == 0:
return None
global fmt_cache
r = check_format(fmt_cache, row)
if r:
return r
for fmt in formats:
r = check_format(fmt, row)
if r:
fmt_cache = fmt
return r
if row[0].startswith("#"): # comment
return None
if ".csv" in row[0]: # fake-perf output
return None
if "Timestamp" in row[0]:
return None
print("PARSE-ERROR", row, file=sys.stderr)
if error_exit:
sys.exit(1)
return None
if __name__ == '__main__':
def check(l, fields):
n = l.split(",")
r = parse_csv_row(n)
assert r is not None
rd = r._asdict()
for a, v in fields.items():
assert rd[a] == n[v]
check('1.001131873,S0,Backend_Bound.Memory_Bound,13.3,% Slots <,,,0.0,3.0,,', {
"ts": 0,
"cpu": 1,
"ev": 2,
"val": 3,
"unit": 4 })