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
161
162
163
164
165
166
|
#!/usr/bin/env python3
import argparse
import numpy as np
import sys
import logging
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__
)
parser.add_argument(
"--log-level",
metavar="LEVEL",
choices=["debug", "info", "warning", "error"],
default="warning",
help="Set log level",
)
parser.add_argument(
"--output-format",
metavar="FORMAT",
choices=["dfatool", "valgrind-ws"],
default="dfatool",
help="Set output format",
)
parser.add_argument(
"benchmark_file",
type=str,
help="Benchmark file used to run valgrind-ws",
)
parser.add_argument(
"ws_output",
type=str,
help="valgrind-ws output file",
)
args = parser.parse_args()
benchmark_filename = args.benchmark_file.split("/")[-1]
if args.log_level:
numeric_level = getattr(logging, args.log_level.upper(), None)
if not isinstance(numeric_level, int):
print(f"Invalid log level: {args.log_level}", file=sys.stderr)
sys.exit(1)
logging.basicConfig(
level=numeric_level,
format="{asctime} {levelname}:{name}:{message}",
style="{",
)
with open(args.benchmark_file, "r") as f:
start_range = [None, None]
end_range = [None, None]
in_nop = False
for lineno, line in enumerate(f):
line = line.strip()
if line == "#if NOP_SYNC":
in_nop = True
if start_range[0] is None:
start_range[0] = lineno
else:
end_range[0] = lineno
if in_nop and line.startswith("#endif"):
in_nop = False
if start_range[1] is None:
start_range[1] = lineno
else:
end_range[1] = lineno
logging.debug(f"start_range = {start_range}, end_range = {end_range}")
page_size = None
ws_log = list()
sample_info = dict()
with open(args.ws_output, "r") as f:
in_ws_log = False
in_sample_info = False
for line in f:
line = line.strip()
if in_ws_log and line == "":
in_ws_log = False
if in_sample_info and line == "":
in_sample_info = False
if page_size is None and line.startswith("Page size:"):
page_size = int(line.split()[2])
if in_ws_log:
t, wss_i, wss_d, info_ref = line.split()
ws_log.append((int(t), int(wss_i), int(wss_d), info_ref))
elif in_sample_info:
_, info_ref, _, locs = line.split()
info_ref = info_ref.removesuffix("]")
locs = locs.removeprefix("loc=")
sample_info[info_ref] = list()
for loc in filter(lambda x: len(x), locs.split("|")):
filename, lineno = loc.split(":")
sample_info[info_ref].append((filename, int(lineno)))
if line == "t WSS_insn WSS_data info":
in_ws_log = True
if line == "Sample info:":
in_sample_info = True
if page_size is None:
raise RuntimeError("Unable to determine page size fom {args.ws_output}")
logging.debug(f"sample_info = {sample_info}")
next_in_kernel = False
in_kernel = False
insn_working_set_sizes = list()
data_working_set_sizes = list()
kernel_range = [None, None]
for t, wss_i, wss_d, info_ref in ws_log:
if next_in_kernel:
next_in_kernel = False
in_kernel = True
kernel_range[0] = t
if info_ref != "-":
for filename, lineno in sample_info[info_ref]:
if (
filename == benchmark_filename
and start_range[0] <= lineno <= start_range[1]
):
next_in_kernel = True
elif (
filename == benchmark_filename
and end_range[0] <= lineno <= end_range[1]
):
in_kernel = False
if in_kernel:
data_working_set_sizes.append(wss_d * page_size)
insn_working_set_sizes.append(wss_i * page_size)
kernel_range[1] = t
if args.output_format == "dfatool":
print(
f"wss_data_mean_bytes={np.mean(data_working_set_sizes)}"
+ f" wss_data_median_bytes={np.median(data_working_set_sizes)}"
+ f" wss_data_stddev={np.std(data_working_set_sizes)}"
+ f" wss_insn_mean_bytes={np.mean(insn_working_set_sizes)}"
+ f" wss_insn_median_bytes={np.median(insn_working_set_sizes)}"
+ f" wss_insn_stddev={np.std(insn_working_set_sizes)}"
)
elif args.output_format == "valgrind-ws":
with open(args.ws_output, "r") as f:
in_ws_log = False
for line in f:
if in_ws_log and line.strip() == "":
in_ws_log = False
if in_ws_log:
ts = int(line.strip().split()[0])
if kernel_range[0] <= ts <= kernel_range[1]:
print(line, end="")
else:
print(line, end="")
if line.strip() == "t WSS_insn WSS_data info":
in_ws_log = True
if __name__ == "__main__":
main()
|