1
|
|
-"""This script generates a HTML file from the results of ftbench"""
|
2
|
|
-# Ahmet Goksu ahmet@goksu.in ahmet.goksu.in
|
3
|
|
-
|
4
|
|
-import os
|
5
|
|
-import re
|
6
|
|
-import sys
|
7
|
|
-
|
8
|
|
-PROJECT_ROOT = sys.argv[1]
|
9
|
|
-BENCHMARK_HTML = os.path.join(PROJECT_ROOT, "benchmark.html")
|
10
|
|
-GITLAB_URL = "https://gitlab.freedesktop.org/freetype/freetype/-/commit/"
|
11
|
|
-CSS_STYLE = """
|
12
|
|
- <style>
|
13
|
|
- table {
|
14
|
|
-
|
15
|
|
- }
|
16
|
|
- th, td {
|
17
|
|
- padding: 3px;
|
18
|
|
- text-align: center;
|
19
|
|
- }
|
20
|
|
- th {
|
21
|
|
- background-color: #ccc;
|
22
|
|
- color: black;
|
23
|
|
- }
|
24
|
|
- .warning{
|
25
|
|
- color: red;
|
26
|
|
- }
|
27
|
|
- .col1 {
|
28
|
|
- background-color: #eee;
|
29
|
|
- }
|
30
|
|
-
|
31
|
|
- .highlight {
|
32
|
|
- background-color: #0a0;
|
33
|
|
- }
|
34
|
|
- </style>
|
35
|
|
-"""
|
36
|
|
-BASELINE_DIR = os.path.join(PROJECT_ROOT, "baseline")
|
37
|
|
-BENCHMARK_DIR = os.path.join(PROJECT_ROOT, "benchmark")
|
38
|
|
-
|
39
|
|
-def main():
|
40
|
|
- """Entry point for the script"""
|
41
|
|
- with open(BENCHMARK_HTML, "w") as html_file:
|
42
|
|
- write_to_html(html_file, "<html>\n<head>\n")
|
43
|
|
- write_to_html(html_file, CSS_STYLE)
|
44
|
|
- write_to_html(html_file, "</head>\n<body>\n")
|
45
|
|
- write_to_html(html_file, "<h1>Freetype Benchmark Results</h1>\n")
|
46
|
|
-
|
47
|
|
- baseline_info = parse_info_file(os.path.join(BASELINE_DIR, "info.txt"))
|
48
|
|
- benchmark_info = parse_info_file(os.path.join(BENCHMARK_DIR, "info.txt"))
|
49
|
|
-
|
50
|
|
- if baseline_info[1].strip() == benchmark_info[1].strip():
|
51
|
|
- write_to_html(
|
52
|
|
- html_file,
|
53
|
|
- '<h2 class="warning">Warning: Baseline and Benchmark have the same commit ID!</h2>\n',
|
54
|
|
- )
|
55
|
|
-
|
56
|
|
- generate_info_table(html_file, baseline_info, benchmark_info)
|
57
|
|
-
|
58
|
|
- # Generate total results table
|
59
|
|
- generate_total_results_table(html_file, BASELINE_DIR, BENCHMARK_DIR)
|
60
|
|
-
|
61
|
|
- # Generate results tables
|
62
|
|
- for filename in os.listdir(BASELINE_DIR):
|
63
|
|
- if filename.endswith(".txt") and not filename == "info.txt":
|
64
|
|
- baseline_results = read_file(os.path.join(BASELINE_DIR, filename))
|
65
|
|
- benchmark_results = read_file(os.path.join(BENCHMARK_DIR, filename))
|
66
|
|
-
|
67
|
|
- generate_results_table(
|
68
|
|
- html_file, baseline_results, benchmark_results, filename
|
69
|
|
- )
|
70
|
|
-
|
71
|
|
-
|
72
|
|
- write_to_html(html_file, "<center>Freetype Benchmark</center>\n")
|
73
|
|
- write_to_html(html_file, "</body>\n</html>\n")
|
74
|
|
-
|
75
|
|
-def write_to_html(html_file, content):
|
76
|
|
- """Write content to html file"""
|
77
|
|
- html_file.write(content)
|
78
|
|
-
|
79
|
|
-
|
80
|
|
-def read_file(file_path):
|
81
|
|
- """Read file and return list of lines"""
|
82
|
|
- with open(file_path, "r") as f:
|
83
|
|
- return f.readlines()
|
84
|
|
-
|
85
|
|
-
|
86
|
|
-def parse_info_file(info_file):
|
87
|
|
- """Get info from info.txt file and return as list"""
|
88
|
|
- info = read_file(info_file)
|
89
|
|
- info[1] = '<a href="">"{}{}">{}</a>\n'.format(GITLAB_URL, info[1].strip(), info[1][:8])
|
90
|
|
- return info
|
91
|
|
-
|
92
|
|
-
|
93
|
|
-def generate_info_table(html_file, baseline_info, benchmark_info):
|
94
|
|
- """Prepare info table for html"""
|
95
|
|
- write_to_html(html_file, "<h2>Info</h2>\n")
|
96
|
|
- write_to_html(html_file, '<table border="1">\n')
|
97
|
|
- write_to_html(
|
98
|
|
- html_file, "<tr><th>Info</th><th>Baseline</th><th>Benchmark</th></tr>\n"
|
99
|
|
- )
|
100
|
|
- info_list = ["Parameters", "Commit ID", "Commit Date", "Branch"]
|
101
|
|
- for info, baseline_line, benchmark_line in zip(
|
102
|
|
- info_list, baseline_info, benchmark_info
|
103
|
|
- ):
|
104
|
|
- write_to_html(
|
105
|
|
- html_file,
|
106
|
|
- '<tr><td class="col1">{}</td><td>{}</td><td>{}</td></tr>\n'.format(
|
107
|
|
- info, baseline_line.strip(), benchmark_line.strip()
|
108
|
|
- ),
|
109
|
|
- )
|
110
|
|
- write_to_html(html_file, "</table><br/>")
|
111
|
|
- write_to_html(html_file, "<p>* Average time for single iteration. Smaller values are better.</p>")
|
112
|
|
- write_to_html(html_file, "<p>** N count in (x | y) format is for showing baseline and benchmark N counts seperately when they differs.</p>")
|
113
|
|
-
|
114
|
|
-
|
115
|
|
-def generate_total_results_table(html_file, baseline_dir, benchmark_dir):
|
116
|
|
- """Prepare total results table for html"""
|
117
|
|
-
|
118
|
|
- # This dictionary will store aggregated results.
|
119
|
|
- test_results = {test: {"baseline": 0, "benchmark": 0, "n_baseline": 0, "n_benchmark": 0} for test in [
|
120
|
|
- "Load", "Load_Advances (Normal)", "Load_Advances (Fast)", "Load_Advances (Unscaled)", "Render",
|
121
|
|
- "Get_Glyph", "Get_Char_Index", "Iterate CMap", "New_Face", "Embolden", "Stroke", "Get_BBox",
|
122
|
|
- "Get_CBox", "New_Face & load glyph(s)"
|
123
|
|
- ]}
|
124
|
|
-
|
125
|
|
- for filename in os.listdir(baseline_dir):
|
126
|
|
- if filename.endswith(".txt") and not filename == "info.txt":
|
127
|
|
-
|
128
|
|
- baseline_results = read_file(os.path.join(baseline_dir, filename))
|
129
|
|
- benchmark_results = read_file(os.path.join(benchmark_dir, filename))
|
130
|
|
-
|
131
|
|
- for baseline_line, benchmark_line in zip(baseline_results, benchmark_results):
|
132
|
|
- if baseline_line.startswith(" "):
|
133
|
|
- baseline_match = re.match(r"\s+(.*?)\s+(\d+\.\d+)\s+microseconds\s+(\d+)\s", baseline_line)
|
134
|
|
- benchmark_match = re.match(r"\s+(.*?)\s+(\d+\.\d+)\s+microseconds\s+(\d+)\s", benchmark_line)
|
135
|
|
-
|
136
|
|
- if baseline_match and benchmark_match:
|
137
|
|
- test = baseline_match.group(1).strip()
|
138
|
|
- baseline_value = float(baseline_match.group(2))
|
139
|
|
- benchmark_value = float(benchmark_match.group(2))
|
140
|
|
- baseline_n = int(baseline_match.group(3))
|
141
|
|
- benchmark_n = int(benchmark_match.group(3))
|
142
|
|
-
|
143
|
|
- # Aggregate the results
|
144
|
|
- if test in test_results:
|
145
|
|
- test_results[test]["baseline"] += baseline_value
|
146
|
|
- test_results[test]["benchmark"] += benchmark_value
|
147
|
|
- test_results[test]["n_baseline"] += baseline_n
|
148
|
|
- test_results[test]["n_benchmark"] += benchmark_n
|
149
|
|
-
|
150
|
|
- # Writing to HTML
|
151
|
|
- write_to_html(html_file, "<h2>Total Results</h2>\n")
|
152
|
|
- write_to_html(html_file, '<table border="1">\n')
|
153
|
|
- write_to_html(
|
154
|
|
- html_file,
|
155
|
|
- '<tr><th>Test</th><th>N</th><th>Baseline (µs)</th>\
|
156
|
|
- <th>Benchmark (µs)</th><th>Difference (%)</th></tr>\n'
|
157
|
|
- )
|
158
|
|
-
|
159
|
|
- total_baseline = total_benchmark = total_diff = total_n_baseline = total_n_benchmark = 0
|
160
|
|
-
|
161
|
|
- for test, values in test_results.items():
|
162
|
|
- baseline = values["baseline"]
|
163
|
|
- benchmark = values["benchmark"]
|
164
|
|
- n_baseline = values["n_baseline"]
|
165
|
|
- n_benchmark = values["n_benchmark"]
|
166
|
|
-
|
167
|
|
- n_display = f"{n_baseline} | {n_benchmark}" if n_baseline != n_benchmark else str(n_baseline)
|
168
|
|
-
|
169
|
|
- diff = ((baseline - benchmark) / baseline) * 100
|
170
|
|
-
|
171
|
|
- # Calculate for total row
|
172
|
|
- total_baseline += baseline
|
173
|
|
- total_benchmark += benchmark
|
174
|
|
- total_n_baseline += n_baseline
|
175
|
|
- total_n_benchmark += n_benchmark
|
176
|
|
-
|
177
|
|
- # Check which value is smaller for color highlighting
|
178
|
|
- baseline_color = "highlight" if baseline <= benchmark else ""
|
179
|
|
- benchmark_color = "highlight" if benchmark <= baseline else ""
|
180
|
|
-
|
181
|
|
- write_to_html(
|
182
|
|
- html_file,
|
183
|
|
- f'<tr><td class="col1">{test}</td><td>{n_display}</td>\
|
184
|
|
- <td class="{baseline_color}">{baseline:.1f}</td>\
|
185
|
|
- <td class="{benchmark_color}">{benchmark:.1f}</td><td>{diff:.1f}</td></tr>\n'
|
186
|
|
- )
|
187
|
|
-
|
188
|
|
- total_diff = ((total_baseline - total_benchmark) / total_baseline) * 100
|
189
|
|
- total_n_display = f"{total_n_baseline} | {total_n_benchmark}" if total_n_baseline != total_n_benchmark else str(total_n_baseline)
|
190
|
|
-
|
191
|
|
- write_to_html(
|
192
|
|
- html_file,
|
193
|
|
- f'<tr><td class="col1">TOTAL</td><td class="col1">{total_n_display}</td>\
|
194
|
|
- <td class="col1">{total_baseline:.1f}</td><td class="col1">{total_benchmark:.1f}</td>\
|
195
|
|
- <td class="col1">{total_diff:.1f}</td></tr>\n'
|
196
|
|
- )
|
197
|
|
-
|
198
|
|
- write_to_html(html_file, "</table><br/>\n")
|
199
|
|
-
|
200
|
|
-
|
201
|
|
-
|
202
|
|
-def generate_results_table(html_file, baseline_results, benchmark_results, filename):
|
203
|
|
- """Prepare results table for html"""
|
204
|
|
- fontname = [
|
205
|
|
- line.split("/")[-1].strip("'")[:-2]
|
206
|
|
- for line in baseline_results
|
207
|
|
- if line.startswith("ftbench results for font")
|
208
|
|
- ][0]
|
209
|
|
-
|
210
|
|
- write_to_html(html_file, "<h3>Results for {}</h2>\n".format(fontname))
|
211
|
|
- write_to_html(html_file, '<table border="1">\n')
|
212
|
|
- write_to_html(
|
213
|
|
- html_file,
|
214
|
|
- '<tr><th>Test</th><th>N</th>\
|
215
|
|
- <th>* <a href="">"{}.txt">Baseline</a> (µs)</th>\
|
216
|
|
- <th>* <a href="">"{}.txt">Benchmark</a> (µs)</th>\
|
217
|
|
- <th>Difference (%)</th></tr>\n'.format(
|
218
|
|
- os.path.join(BASELINE_DIR, filename[:-4]),
|
219
|
|
- os.path.join(BENCHMARK_DIR, filename[:-4]),
|
220
|
|
- ),
|
221
|
|
- )
|
222
|
|
-
|
223
|
|
- total_n = total_time_baseline = total_time_benchmark = total_difference = 0
|
224
|
|
-
|
225
|
|
- for baseline_line, benchmark_line in zip(baseline_results, benchmark_results):
|
226
|
|
- if baseline_line.startswith(" "):
|
227
|
|
- baseline_match = re.match(
|
228
|
|
- r"\s+(.*?)\s+(\d+\.\d+)\s+microseconds\s+(\d+)\s", baseline_line
|
229
|
|
- )
|
230
|
|
- benchmark_match = re.match(
|
231
|
|
- r"\s+(.*?)\s+(\d+\.\d+)\s+microseconds\s+(\d+)\s", benchmark_line
|
232
|
|
- )
|
233
|
|
-
|
234
|
|
- if baseline_match and benchmark_match:
|
235
|
|
- baseline_value = float(baseline_match.group(2))
|
236
|
|
- benchmark_value = float(benchmark_match.group(2))
|
237
|
|
-
|
238
|
|
- percentage_diff = (
|
239
|
|
- (baseline_value - benchmark_value) / baseline_value
|
240
|
|
- ) * 100
|
241
|
|
-
|
242
|
|
- baseline_n = baseline_match.group(3)
|
243
|
|
- benchmark_n = benchmark_match.group(3)
|
244
|
|
-
|
245
|
|
- n = (
|
246
|
|
- baseline_n
|
247
|
|
- if baseline_n == benchmark_n
|
248
|
|
- else baseline_n + " | " + benchmark_n
|
249
|
|
- )
|
250
|
|
-
|
251
|
|
- total_n += int(baseline_n)
|
252
|
|
- total_n += int(benchmark_n)
|
253
|
|
- total_time_baseline += baseline_value
|
254
|
|
- total_time_benchmark += benchmark_value
|
255
|
|
-
|
256
|
|
-
|
257
|
|
- if baseline_value > benchmark_value:
|
258
|
|
- write_to_html(
|
259
|
|
- html_file,
|
260
|
|
- '<tr><td class="col1">{}</td><td>{}</td>\
|
261
|
|
- <td class="lowlight">{:.1f}</td><td class="highlight">{:.1f}</td><td>{:.1f}</td></tr>\n'.format(
|
262
|
|
- baseline_match.group(1),
|
263
|
|
- n,
|
264
|
|
- baseline_value,
|
265
|
|
- benchmark_value,
|
266
|
|
- percentage_diff,
|
267
|
|
- ),
|
268
|
|
- )
|
269
|
|
- else:
|
270
|
|
- write_to_html(
|
271
|
|
- html_file,
|
272
|
|
- '<tr><td class="col1">{}</td><td>{}</td>\
|
273
|
|
- <td class="highlight">{:.1f}</td><td class="lowlight">{:.1f}</td><td>{:.1f}</td></tr>\n'.format(
|
274
|
|
- baseline_match.group(1),
|
275
|
|
- n,
|
276
|
|
- baseline_value,
|
277
|
|
- benchmark_value,
|
278
|
|
- percentage_diff,
|
279
|
|
- ),
|
280
|
|
- )
|
281
|
|
-
|
282
|
|
- write_to_html(
|
283
|
|
- html_file,
|
284
|
|
- '<tr><td class="col1">TOTAL</td><td class="col1">{}</td>\
|
285
|
|
- <td class="col1">{:.1f}</td><td class="col1">{:.1f}</td><td class="col1">{:.1f}</td></tr>\n'.format(
|
286
|
|
- total_n, total_time_baseline, total_time_benchmark, (total_time_baseline - total_time_benchmark) / total_time_baseline * -100
|
287
|
|
- ),
|
288
|
|
- )
|
289
|
|
- write_to_html(html_file, "</table><br/>\n")
|
290
|
|
-
|
291
|
|
-if __name__ == "__main__":
|
292
|
|
- main() |