Skip to content

Commit 75a0b65

Browse files
authored
Merge pull request #349 from antmicro/refactor-results-page
Refactor results page
2 parents 14b8461 + 9b880fa commit 75a0b65

18 files changed

+207
-98
lines changed

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ install_quicklogic:
7373
tar -xf ${QUICKLOGIC_ARCHIVE} -C env/quicklogic
7474
rm ${QUICKLOGIC_ARCHIVE}
7575

76-
PYTHON_SRCS=$(shell find . -name "*py" -not -path "./third_party/*" -not -path "./env/*" -not -path "./conf/*")
76+
PYTHON_SRCS=$(shell find . -name "*py" -not -path "./third_party/*" -not -path "./env/*" -not -path "./conf/*" -not -path "./results/env/*")
7777

7878
format: ${PYTHON_SRCS}
7979
yapf -i $?
8080

8181
clean::
82-
rm -rf build/
82+
$(IN_CONDA_ENV_BASE) rm -rf build/
8383

8484
.PHONY: all env build-tools format run-all clean

__init__.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (C) 2021 The SymbiFlow Authors.
5+
#
6+
# Use of this source code is governed by a ISC-style
7+
# license that can be found in the LICENSE file or at
8+
# https://opensource.org/licenses/ISC
9+
#
10+
# SPDX-License-Identifier: ISC

conf/common/requirements.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ lxml
55
pandas
66
pytest
77
python-constraint
8+
requests
89
simplejson
910
termcolor
1011
terminaltables
1112
tqdm
12-
yapf
13+
yapf==0.31.0
1314
git+https://github.com/SymbiFlow/edalize.git@symbiflow_update#egg=edalize

infrastructure/__init__.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (C) 2021 The SymbiFlow Authors.
5+
#
6+
# Use of this source code is governed by a ISC-style
7+
# license that can be found in the LICENSE file or at
8+
# https://opensource.org/licenses/ISC
9+
#
10+
# SPDX-License-Identifier: ISC

infrastructure/tasks.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def __init__(self, root_dir):
2323
self.src_dir = os.path.join(root_dir, 'src')
2424
self.tasks = self.iter_options()
2525

26-
def iter_options(self):
26+
def iter_options(self, all_combinations=False):
2727
"""Returns all the possible combination of:
2828
- projects,
2929
- toolchains,
@@ -51,12 +51,18 @@ def iter_options(self):
5151
board for board in project_boards if board in vendor_boards
5252
]
5353

54+
if all_combinations:
55+
boards = vendor_boards
56+
5457
for toolchain, board in list(product(toolchains, boards)):
55-
if toolchain not in skip_toolchains:
58+
if toolchain not in skip_toolchains or all_combinations:
5659
combinations.add((project, toolchain, board))
5760

5861
return combinations
5962

63+
def get_all_combinations(self):
64+
return self.iter_options(all_combinations=True)
65+
6066
def get_tasks(
6167
self,
6268
args,

results/Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ env:
1818

1919
fetch:
2020
mkdir -p meta
21-
$(IN_ENV) python fetch_meta.py nightly 1138 _ meta --pool-size $$(nproc)
21+
$(IN_ENV) python3 fetch_meta.py --builds nightly --from-build 1138 --output-dir meta --pool-size $$(nproc)
2222

2323
build:
2424
mkdir -p build
25-
$(IN_ENV) python gen.py meta -o build
25+
$(IN_ENV) python3 generate_html.py -i meta -o build
2626
touch build/.nojekyll
2727

2828
clean:

results/__init__.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (C) 2021 The SymbiFlow Authors.
5+
#
6+
# Use of this source code is governed by a ISC-style
7+
# license that can be found in the LICENSE file or at
8+
# https://opensource.org/licenses/ISC
9+
#
10+
# SPDX-License-Identifier: ISC

results/fetch_meta.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,17 @@ def download_from_specs(specs):
229229
def main():
230230
parser = ArgumentParser()
231231
parser.add_argument(
232-
'builds', type=str, help='Builds type (e.g. `nightly`)'
232+
'--builds', type=str, help='Builds type (e.g. `nightly`)'
233233
)
234-
parser.add_argument('from_tr', type=int, help='First test run number')
234+
parser.add_argument('--from-build', type=int, help='First test run number')
235235
parser.add_argument(
236-
'to_tr', type=str, help='Last test run number (use `_` for "latest")'
236+
'--to-build',
237+
default="_",
238+
type=str,
239+
help='Last test run number (use `_` for "latest")'
237240
)
238241
parser.add_argument(
239-
'output_dir', type=str, help='Output directory for downloaded data'
242+
'--output-dir', type=str, help='Output directory for downloaded data'
240243
)
241244
parser.add_argument(
242245
'--pool-size', type=int, default=8, help='Size of thread pool'
@@ -250,7 +253,7 @@ def main():
250253
print(f'Using {args.pool_size} parallel threads.')
251254
pool = ThreadPool(args.pool_size)
252255
test_numbers = list(
253-
get_test_run_numbers(args.from_tr, args.to_tr, args.builds)
256+
get_test_run_numbers(args.from_build, args.to_build, args.builds)
254257
)
255258

256259
print('Preparing downloads ...', flush=True)

results/gen.py renamed to results/generate_html.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,23 @@ def main():
2525
parser = ArgumentParser()
2626

2727
parser.add_argument(
28-
'data_dir', type=str, help='Directory containing json data files'
28+
'-i',
29+
'--in-dir',
30+
type=str,
31+
help='Directory containing json data files'
2932
)
3033
parser.add_argument(
3134
'-o',
32-
'--out_dir',
35+
'--out-dir',
3336
nargs=1,
3437
type=str,
3538
help='Save outputs in a given directory'
3639
)
3740

3841
args = parser.parse_args()
3942

40-
if not os.path.isdir(args.data_dir):
41-
print('Path needs to be a path to a directory')
42-
exit(-1)
43+
if not os.path.isdir(args.in_dir):
44+
os.makedirs(args.in_dir)
4345

4446
graph_pages = {}
4547

@@ -48,8 +50,8 @@ def main():
4850

4951
results = []
5052

51-
for project_name in os.listdir(args.data_dir):
52-
project_dir = os.path.join(args.data_dir, project_name)
53+
for project_name in os.listdir(args.in_dir):
54+
project_dir = os.path.join(args.in_dir, project_name)
5355
if not os.path.isdir(project_dir):
5456
print(f'Skipping `{project_dir}` because it' 's not a directory.')
5557
continue

results/generate_index_page.py

+47-13
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,66 @@
99
#
1010
# SPDX-License-Identifier: ISC
1111

12+
import json
13+
import os
1214
from typing import List
1315

1416
import jinja2
1517

1618
from project_results import ProjectResults
19+
from infrastructure.tasks import Tasks
1720

1821

1922
def generate_index_html(
2023
template: jinja2.Template, results: List[ProjectResults]
2124
):
2225
print('Generating index page...')
2326

24-
projects_dict = {}
25-
all_toolchains = set()
27+
cur_dir = os.path.dirname(os.path.abspath(__file__))
28+
root_dir = os.path.join(cur_dir, '..')
29+
tasks = Tasks(root_dir)
30+
combinations = sorted(
31+
tasks.get_all_combinations(), key=lambda tup: (tup[2], tup[0], tup[1])
32+
)
33+
34+
boards = dict()
35+
toolchains_dict = dict()
36+
projects = set()
37+
for project, toolchain, board in combinations:
38+
print(project, toolchain, board)
39+
if board not in boards:
40+
boards[board] = dict()
41+
42+
board_dict = boards[board]
43+
if project not in board_dict:
44+
board_dict[project] = dict()
45+
46+
proj_dict = board_dict[project]
47+
48+
proj_dict[toolchain] = "skip"
49+
50+
if board not in toolchains_dict:
51+
toolchains_dict[board] = set()
52+
53+
toolchains_dict[board].add(toolchain)
54+
55+
projects.add(project)
56+
2657
for project_results in results:
27-
boards = {}
28-
for board, toolchains in project_results.entries.items():
29-
board_toolchains = []
30-
for toolchain in toolchains.keys():
31-
board_toolchains.append(toolchain)
32-
all_toolchains.add(toolchain)
33-
boards[board] = board_toolchains
58+
entries = project_results.entries
59+
project = project_results.project_name
3460

35-
projects_dict[project_results.project_name] = boards
61+
for board, toolchains in entries.items():
62+
for toolchain in toolchains.keys():
63+
status = entries[board][toolchain][0].status
64+
boards[board][project][toolchain] = status
3665

37-
projects_list = sorted(list(projects_dict.items()), key=lambda t: t[0])
38-
toolchain_list = sorted(list(all_toolchains))
66+
for board, tool_list in toolchains_dict.items():
67+
toolchains_dict[board] = sorted(list(tool_list))
3968

40-
return template.render(projects=projects_list, toolchains=toolchain_list)
69+
return template.render(
70+
boards=boards,
71+
boards_list=list(boards.keys()),
72+
toolchains=toolchains_dict,
73+
projects=projects
74+
)

results/html/index.html

+13-16
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,23 @@ <h1>FPGA Tool Perf results</h1>
1616
</div>
1717

1818
<div id="overview" class="w3-container w3-center">
19-
<p>Click on a project to select it, click on its name to jump to the performance graphs.</p>
19+
<p>Click on a board to select it.</p>
2020
</div>
2121

2222
<div class="w3-row">
23-
{% for project_name, boards in projects %}
24-
<div id="{{project_name}}" class="w3-col m4 l3">
23+
{% for board in boards %}
24+
<div id="{{board}}" class="w3-col m4 l3">
2525

26-
<button id="{{project_name}}-button" class="project-button w3-button w3-light-gray w3-block w3-center" onclick="selectTable('{{project_name}}')">
27-
<a href="graphs/{{ project_name }}.html">{{ project_name }}</a>
28-
<!-- {{ project_name }} -->
29-
<!-- <a href="graphs/{{ project_name }}.html"><span class="material-icons">bar_chart</span></a> -->
26+
<button id="{{board}}-button" class="project-button w3-button w3-light-gray w3-block w3-center" onclick="selectTable('{{board}}')">
27+
{{ board }}
3028
</button>
31-
3229
</div>
3330
{% endfor %}
3431
</div>
3532

3633
<div>
37-
{% for project_name, boards in projects %}
38-
<div id="{{project_name}}-table" class="project-table w3-container w3-hide w3-padding-16">
34+
{% for board in boards %}
35+
<div id="{{ board }}-table" class="board-table w3-container w3-hide w3-padding-16">
3936
{% include 'table.html' %}
4037
</div>
4138
{% endfor %}
@@ -61,16 +58,16 @@ <h1>FPGA Tool Perf results</h1>
6158
setVisibility(elem, elem.className.indexOf("w3-show") == -1);
6259
}
6360

64-
function selectTable(project_name) {
65-
var table_id = project_name + "-table";
66-
var button_id = project_name + "-button";
61+
function selectTable(board_name) {
62+
var table_id = board_name + "-table";
63+
var button_id = board_name + "-button";
6764

68-
var tables = document.getElementsByClassName("project-table");
65+
var tables = document.getElementsByClassName("board-table");
6966
for (var i = tables.length - 1; i >= 0; i--) {
7067
setVisibility(tables[i], tables[i].id == table_id);
7168
}
7269

73-
var buttons = document.getElementsByClassName("project-button");
70+
var buttons = document.getElementsByClassName("board-button");
7471
for (var i = buttons.length - 1; i >= 0; i--) {
7572
if (buttons[i].id == button_id) {
7673
buttons[i].className = buttons[i].className.replace(" w3-gray", "");
@@ -85,7 +82,7 @@ <h1>FPGA Tool Perf results</h1>
8582
}
8683

8784
// select first table on start
88-
selectTable("{{ projects[0][0] }}");
85+
selectTable("{{ boards_list[0] }}");
8986

9087
</script>
9188
</html>

results/html/table.html

+17-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
<table class="w3-table-all w3-responsive ">
22
<tr class="w3-gray">
3-
<th class="w3-center w3-border"> Toolchain <br></br> Board</th>
4-
{% for toolchain in toolchains %}
3+
<th class="w3-center w3-border"> Toolchain <br></br> Project</th>
4+
{% for toolchain in toolchains[board] %}
55
<th class="w3-center w3-border"> {{ toolchain }} </th>
66
{% endfor %}
77
</tr>
8-
{% for board in boards %}
8+
{% for project in boards[board] %}
99
<tr>
10-
<th> {{ board }} </th>
11-
{% for toolchain in toolchains %}
12-
<th class="w3-center w3-border">
13-
{% if toolchain in boards[board] %}
14-
X
10+
<th> <a href="graphs/{{ project }}.html">{{ project }}</a></th>
11+
{% for toolchain in boards[board][project] %}
12+
{% if boards[board][project][toolchain] == "succeeded" %}
13+
<th class="w3-center w3-border passed" style="background-color: lightgreen">
14+
Passed
15+
</th>
16+
{% elif boards[board][project][toolchain] == "failed" %}
17+
<th class="w3-center w3-border failed" style="background-color: red">
18+
Failed
19+
</th>
20+
{% elif boards[board][project][toolchain] == "skip" %}
21+
<th class="w3-center w3-border failed" style="background-color: lightblue">
22+
Skipped
23+
</th>
1524
{% endif %}
16-
</th>
1725
{% endfor %}
1826
</tr>
1927
{% endfor %}

results/project_results.py

+1-24
Original file line numberDiff line numberDiff line change
@@ -48,41 +48,18 @@ def __init__(self, project_name: str, data_dir: str):
4848
data = None
4949
try:
5050
data = json.loads(f.read())
51+
datas.append(data)
5152
except Exception as e:
5253
print(f'WARNING: couldn\'t load data from `{p}`: {e}')
53-
if data:
54-
try:
55-
for board, toolchain in get_configs(data):
56-
configs[board].add(toolchain)
57-
except KeyError as e:
58-
print(f'Invalid config `{p}`, missing: {e}')
59-
continue
60-
61-
datas.append(data)
6254

6355
# Create test entries
6456
for data in sorted(datas, key=lambda d: datetime_from_str(d['date'])):
6557
self.test_dates.append(datetime_from_str(data['date']))
6658
configs_to_handle = {}
67-
for board, toolchains in configs.items():
68-
configs_to_handle[board] = toolchains.copy()
6959

7060
for board, toolchain, entry in get_entries(data):
71-
try:
72-
configs_to_handle[board].remove(toolchain)
73-
except KeyError:
74-
print(
75-
f'WARNING: config `{config_name(board, toolchain)}` '
76-
f'repeated in data forproject `{project_name}, '
77-
f'date: {data["date"]}. Data will be ignoreed.'
78-
)
79-
continue
8061
self.entries[board][toolchain].append(entry)
8162

82-
for board, toolchains in configs_to_handle.items():
83-
for toolchain in toolchains:
84-
self.entries[board][toolchain].append(None)
85-
8663
def get_all_configs(self):
8764
for board, toolchains in self.entries.items():
8865
for toolchain in toolchains.keys():

0 commit comments

Comments
 (0)