siliconcompiler 0.28.2__py3-none-any.whl → 0.28.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- siliconcompiler/_common.py +12 -0
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc_dashboard.py +6 -2
- siliconcompiler/apps/sc_install.py +61 -13
- siliconcompiler/apps/sc_remote.py +1 -1
- siliconcompiler/core.py +132 -68
- siliconcompiler/fpgas/vpr_example.py +8 -0
- siliconcompiler/package.py +3 -2
- siliconcompiler/remote/client.py +41 -10
- siliconcompiler/report/__init__.py +1 -1
- siliconcompiler/report/{streamlit_report.py → dashboard/__init__.py} +56 -10
- siliconcompiler/report/dashboard/components/__init__.py +546 -0
- siliconcompiler/report/dashboard/components/flowgraph.py +114 -0
- siliconcompiler/report/dashboard/components/graph.py +208 -0
- siliconcompiler/report/dashboard/layouts/__init__.py +20 -0
- siliconcompiler/report/dashboard/layouts/_common.py +43 -0
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph.py +96 -0
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph_node_tab.py +117 -0
- siliconcompiler/report/dashboard/layouts/vertical_flowgraph_sac_tabs.py +110 -0
- siliconcompiler/report/dashboard/state.py +217 -0
- siliconcompiler/report/dashboard/utils/__init__.py +73 -0
- siliconcompiler/report/dashboard/utils/file_utils.py +120 -0
- siliconcompiler/report/dashboard/viewer.py +36 -0
- siliconcompiler/report/report.py +22 -4
- siliconcompiler/report/summary_table.py +1 -2
- siliconcompiler/report/utils.py +1 -2
- siliconcompiler/scheduler/__init__.py +45 -6
- siliconcompiler/schema/schema_obj.py +4 -2
- siliconcompiler/sphinx_ext/dynamicgen.py +6 -0
- siliconcompiler/tools/_common/__init__.py +44 -6
- siliconcompiler/tools/_common/asic.py +79 -23
- siliconcompiler/tools/genfasm/genfasm.py +7 -0
- siliconcompiler/tools/ghdl/convert.py +7 -0
- siliconcompiler/tools/klayout/convert_drc_db.py +60 -0
- siliconcompiler/tools/klayout/drc.py +156 -0
- siliconcompiler/tools/klayout/export.py +2 -0
- siliconcompiler/tools/klayout/klayout.py +0 -1
- siliconcompiler/tools/klayout/klayout_convert_drc_db.py +182 -0
- siliconcompiler/tools/klayout/operations.py +2 -0
- siliconcompiler/tools/klayout/screenshot.py +2 -0
- siliconcompiler/tools/klayout/show.py +4 -4
- siliconcompiler/tools/magic/drc.py +21 -0
- siliconcompiler/tools/magic/extspice.py +21 -0
- siliconcompiler/tools/magic/magic.py +29 -0
- siliconcompiler/tools/magic/sc_drc.tcl +2 -12
- siliconcompiler/tools/magic/sc_extspice.tcl +3 -15
- siliconcompiler/tools/openroad/floorplan.py +5 -0
- siliconcompiler/tools/openroad/openroad.py +56 -5
- siliconcompiler/tools/openroad/scripts/sc_apr.tcl +15 -0
- siliconcompiler/tools/openroad/scripts/sc_cts.tcl +18 -13
- siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +61 -10
- siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +10 -0
- siliconcompiler/tools/openroad/scripts/sc_procs.tcl +31 -1
- siliconcompiler/tools/openroad/scripts/sc_route.tcl +8 -2
- siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +0 -5
- siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +36 -6
- siliconcompiler/tools/surelog/__init__.py +12 -0
- siliconcompiler/tools/verilator/compile.py +27 -0
- siliconcompiler/tools/verilator/verilator.py +9 -0
- siliconcompiler/tools/vpr/vpr.py +18 -0
- siliconcompiler/tools/yosys/{syn_asic_fpga_shared.tcl → procs.tcl} +23 -0
- siliconcompiler/tools/yosys/sc_screenshot.tcl +104 -0
- siliconcompiler/tools/yosys/sc_syn.tcl +7 -9
- siliconcompiler/tools/yosys/screenshot.py +153 -0
- siliconcompiler/tools/yosys/syn_asic.py +3 -0
- siliconcompiler/tools/yosys/syn_asic.tcl +1 -3
- siliconcompiler/tools/yosys/syn_fpga.tcl +3 -2
- siliconcompiler/toolscripts/_tools.json +10 -5
- siliconcompiler/toolscripts/rhel8/install-chisel.sh +26 -0
- siliconcompiler/toolscripts/rhel8/install-ghdl.sh +25 -0
- siliconcompiler/toolscripts/rhel8/install-icarus.sh +40 -0
- siliconcompiler/toolscripts/rhel8/install-klayout.sh +17 -0
- siliconcompiler/toolscripts/rhel8/install-magic.sh +26 -0
- siliconcompiler/toolscripts/rhel8/install-montage.sh +5 -0
- siliconcompiler/toolscripts/rhel8/install-netgen.sh +25 -0
- siliconcompiler/toolscripts/rhel8/install-openroad.sh +31 -0
- siliconcompiler/toolscripts/rhel8/install-slang.sh +31 -0
- siliconcompiler/toolscripts/rhel8/install-surelog.sh +32 -0
- siliconcompiler/toolscripts/rhel8/install-sv2v.sh +27 -0
- siliconcompiler/toolscripts/rhel8/install-verible.sh +24 -0
- siliconcompiler/toolscripts/rhel8/install-verilator.sh +40 -0
- siliconcompiler/toolscripts/rhel8/install-xyce.sh +64 -0
- siliconcompiler/toolscripts/rhel8/install-yosys.sh +23 -0
- siliconcompiler/toolscripts/rhel9/install-chisel.sh +26 -0
- siliconcompiler/toolscripts/rhel9/install-ghdl.sh +25 -0
- siliconcompiler/toolscripts/rhel9/install-icarus.sh +40 -0
- siliconcompiler/toolscripts/rhel9/install-klayout.sh +17 -0
- siliconcompiler/toolscripts/rhel9/install-magic.sh +26 -0
- siliconcompiler/toolscripts/rhel9/install-montage.sh +5 -0
- siliconcompiler/toolscripts/rhel9/install-netgen.sh +25 -0
- siliconcompiler/toolscripts/rhel9/install-slang.sh +31 -0
- siliconcompiler/toolscripts/rhel9/install-surelog.sh +32 -0
- siliconcompiler/toolscripts/rhel9/install-sv2v.sh +27 -0
- siliconcompiler/toolscripts/rhel9/install-verible.sh +24 -0
- siliconcompiler/toolscripts/rhel9/install-verilator.sh +40 -0
- siliconcompiler/toolscripts/rhel9/install-xdm.sh +43 -0
- siliconcompiler/toolscripts/rhel9/install-xyce.sh +64 -0
- siliconcompiler/toolscripts/rhel9/install-yosys.sh +23 -0
- siliconcompiler/toolscripts/ubuntu20/install-icepack.sh +1 -1
- siliconcompiler/toolscripts/ubuntu20/install-xdm.sh +40 -0
- siliconcompiler/toolscripts/ubuntu20/install-yosys.sh +2 -2
- siliconcompiler/toolscripts/ubuntu22/install-icepack.sh +1 -1
- siliconcompiler/toolscripts/ubuntu22/install-xdm.sh +40 -0
- siliconcompiler/toolscripts/ubuntu22/install-yosys.sh +2 -2
- siliconcompiler/toolscripts/ubuntu24/install-icepack.sh +1 -1
- siliconcompiler/toolscripts/ubuntu24/install-klayout.sh +2 -0
- siliconcompiler/toolscripts/ubuntu24/install-xdm.sh +40 -0
- siliconcompiler/toolscripts/ubuntu24/install-yosys.sh +2 -2
- siliconcompiler/utils/__init__.py +30 -1
- siliconcompiler/utils/showtools.py +4 -0
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/METADATA +22 -8
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/RECORD +116 -67
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/WHEEL +1 -1
- siliconcompiler/report/streamlit_viewer.py +0 -944
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/LICENSE +0 -0
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.28.2.dist-info → siliconcompiler-0.28.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import streamlit
|
|
3
|
+
|
|
4
|
+
from siliconcompiler.report.dashboard import components
|
|
5
|
+
from siliconcompiler.report.dashboard.components import graph
|
|
6
|
+
from siliconcompiler.report.dashboard import state
|
|
7
|
+
from siliconcompiler.report.dashboard import utils
|
|
8
|
+
from siliconcompiler.report.dashboard.utils import file_utils
|
|
9
|
+
from siliconcompiler.report.dashboard.layouts import _common
|
|
10
|
+
import streamlit_antd_components as sac
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def layout():
|
|
14
|
+
chip = state.get_chip()
|
|
15
|
+
metric_dataframe, node_to_step_index_map, metric_to_metric_unit_map = \
|
|
16
|
+
utils.generate_metric_dataframe(chip)
|
|
17
|
+
|
|
18
|
+
components.page_header()
|
|
19
|
+
|
|
20
|
+
tab_headings = [
|
|
21
|
+
sac.TabsItem(
|
|
22
|
+
"Metrics",
|
|
23
|
+
icon='stack'),
|
|
24
|
+
sac.TabsItem(
|
|
25
|
+
"Manifest",
|
|
26
|
+
icon=file_utils.get_file_icon('manifest.pkg.json')),
|
|
27
|
+
sac.TabsItem(
|
|
28
|
+
"File Viewer",
|
|
29
|
+
icon=file_utils.get_file_icon(state.get_key(state.SELECTED_FILE))),
|
|
30
|
+
sac.TabsItem(
|
|
31
|
+
"Design Preview",
|
|
32
|
+
icon=file_utils.get_file_icon('design.png'),
|
|
33
|
+
disabled=not os.path.isfile(f'{chip.getworkdir()}/{chip.design}.png')),
|
|
34
|
+
sac.TabsItem(
|
|
35
|
+
"Graphs",
|
|
36
|
+
icon='graph-up',
|
|
37
|
+
disabled=len(state.get_key(state.LOADED_CHIPS)) == 1)
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
tab_selected = _common.sac_tabs(tab_headings)
|
|
41
|
+
|
|
42
|
+
if tab_selected == "Metrics":
|
|
43
|
+
# Add flowgraph
|
|
44
|
+
if state.get_key(state.DISPLAY_FLOWGRAPH):
|
|
45
|
+
default_flowgraph_width_in_percent = 0.4
|
|
46
|
+
flowgraph_col_width_in_pixels = 520
|
|
47
|
+
flowgraph_col_width_in_percent = \
|
|
48
|
+
state.compute_component_size(
|
|
49
|
+
default_flowgraph_width_in_percent,
|
|
50
|
+
flowgraph_col_width_in_pixels)
|
|
51
|
+
|
|
52
|
+
flowgraph_col, metrics_container = \
|
|
53
|
+
streamlit.columns(
|
|
54
|
+
[flowgraph_col_width_in_percent, 1 - flowgraph_col_width_in_percent],
|
|
55
|
+
gap="large")
|
|
56
|
+
|
|
57
|
+
with flowgraph_col:
|
|
58
|
+
header_col, flowgraph_toggle_container = streamlit.columns(2, gap="large")
|
|
59
|
+
with header_col:
|
|
60
|
+
streamlit.header('Flowgraph')
|
|
61
|
+
components.flowgraph_viewer(chip)
|
|
62
|
+
else:
|
|
63
|
+
flowgraph_toggle_container = streamlit.container()
|
|
64
|
+
metrics_container = streamlit.container()
|
|
65
|
+
|
|
66
|
+
with flowgraph_toggle_container:
|
|
67
|
+
streamlit.markdown("")
|
|
68
|
+
streamlit.markdown("")
|
|
69
|
+
|
|
70
|
+
if state.set_key(state.DISPLAY_FLOWGRAPH, not streamlit.checkbox(
|
|
71
|
+
'Hide flowgraph',
|
|
72
|
+
help='Click here to hide the flowgraph')):
|
|
73
|
+
state.set_key(state.APP_RERUN, "Flowgraph")
|
|
74
|
+
|
|
75
|
+
with metrics_container:
|
|
76
|
+
components.metrics_viewer(metric_dataframe, metric_to_metric_unit_map)
|
|
77
|
+
|
|
78
|
+
header_col, settings_col = \
|
|
79
|
+
streamlit.columns(
|
|
80
|
+
[0.7, 0.3],
|
|
81
|
+
gap='small')
|
|
82
|
+
with header_col:
|
|
83
|
+
streamlit.header('Node Information')
|
|
84
|
+
with settings_col:
|
|
85
|
+
components.node_selector(list(node_to_step_index_map.keys()))
|
|
86
|
+
|
|
87
|
+
if state.get_selected_node():
|
|
88
|
+
step, index = node_to_step_index_map[state.get_selected_node()]
|
|
89
|
+
current_file = state.get_key(state.SELECTED_FILE)
|
|
90
|
+
components.node_viewer(chip, step, index, metric_dataframe)
|
|
91
|
+
if state.get_key(state.SELECTED_FILE) and \
|
|
92
|
+
current_file != state.get_key(state.SELECTED_FILE):
|
|
93
|
+
state.set_key(state.APP_RERUN, "File")
|
|
94
|
+
|
|
95
|
+
if tab_selected == "Manifest":
|
|
96
|
+
components.manifest_viewer(chip)
|
|
97
|
+
|
|
98
|
+
if tab_selected == "File Viewer":
|
|
99
|
+
components.file_viewer(
|
|
100
|
+
chip,
|
|
101
|
+
state.get_key(state.SELECTED_FILE),
|
|
102
|
+
page_key=state.SELECTED_FILE_PAGE)
|
|
103
|
+
|
|
104
|
+
if tab_selected == "Design Preview":
|
|
105
|
+
components.file_viewer(chip, f'{chip.getworkdir()}/{chip.design}.png')
|
|
106
|
+
|
|
107
|
+
if tab_selected == "Graphs":
|
|
108
|
+
graph.viewer(metric_dataframe, node_to_step_index_map, metric_to_metric_unit_map)
|
|
109
|
+
|
|
110
|
+
_common.check_rerun()
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import streamlit
|
|
5
|
+
import streamlit_javascript
|
|
6
|
+
import fasteners
|
|
7
|
+
|
|
8
|
+
from siliconcompiler import Chip
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
DISPLAY_FLOWGRAPH = "show_flowgraph"
|
|
12
|
+
SELECTED_JOB = "selected_job"
|
|
13
|
+
SELECTED_NODE = "selected_node"
|
|
14
|
+
# This is needed until the graph supports setting a selected node
|
|
15
|
+
SELECTED_FLOWGRAPH_NODE = "selected_flowgraph_node"
|
|
16
|
+
SELECTED_SELECTOR_NODE = "selected_selector_node"
|
|
17
|
+
NODE_SOURCE = "node_source"
|
|
18
|
+
SELECTED_FILE = "selected_file"
|
|
19
|
+
SELECTED_FILE_PAGE = "selected_file_page"
|
|
20
|
+
LOADED_CHIPS = "loaded_chips"
|
|
21
|
+
UI_WIDTH = "ui_width"
|
|
22
|
+
MANIFEST_FILE = "manifest_file"
|
|
23
|
+
MANIFEST_LOCK = "manifest_lock"
|
|
24
|
+
MANIFEST_TIME = "manifest_time"
|
|
25
|
+
IS_RUNNING = "is_flow_running"
|
|
26
|
+
GRAPH_JOBS = "graph_jobs"
|
|
27
|
+
APP_LAYOUT = "app_layout"
|
|
28
|
+
APP_RERUN = "app_rerun"
|
|
29
|
+
APP_RUNNING_REFRESH = "app_running_refresh"
|
|
30
|
+
APP_STOPPED_REFRESH = "app_stopped_refresh"
|
|
31
|
+
MAX_DICT_ITEMS_TO_SHOW = "max_dict_items"
|
|
32
|
+
MAX_FILE_LINES_TO_SHOW = "max_file_lines"
|
|
33
|
+
SELECT_TAB = "select_tab"
|
|
34
|
+
TAB_INDEX = "tab-index"
|
|
35
|
+
TAB_STATE = "tab-state"
|
|
36
|
+
|
|
37
|
+
_DEBUG = False
|
|
38
|
+
DEVELOPER = False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _add_default(key, value):
|
|
42
|
+
if key not in streamlit.session_state:
|
|
43
|
+
streamlit.session_state[key] = value
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def update_manifest():
|
|
47
|
+
file_time = os.stat(get_key(MANIFEST_FILE)).st_mtime
|
|
48
|
+
|
|
49
|
+
if get_key(MANIFEST_TIME) != file_time:
|
|
50
|
+
chip = Chip(design='')
|
|
51
|
+
|
|
52
|
+
with get_key(MANIFEST_LOCK):
|
|
53
|
+
chip.read_manifest(get_key(MANIFEST_FILE))
|
|
54
|
+
set_key(MANIFEST_TIME, file_time)
|
|
55
|
+
debug_print("Read manifest", get_key(MANIFEST_FILE))
|
|
56
|
+
|
|
57
|
+
add_chip("default", chip)
|
|
58
|
+
|
|
59
|
+
for history in chip.getkeys('history'):
|
|
60
|
+
history_chip = Chip(design='')
|
|
61
|
+
history_chip.schema.cfg = chip.getdict('history', history)
|
|
62
|
+
history_chip.set('design', chip.design)
|
|
63
|
+
add_chip(history, history_chip)
|
|
64
|
+
|
|
65
|
+
return True
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def init():
|
|
70
|
+
_add_default(DISPLAY_FLOWGRAPH, True)
|
|
71
|
+
_add_default(SELECTED_JOB, None)
|
|
72
|
+
_add_default(SELECTED_NODE, None)
|
|
73
|
+
_add_default(SELECTED_FLOWGRAPH_NODE, None)
|
|
74
|
+
_add_default(SELECTED_SELECTOR_NODE, None)
|
|
75
|
+
_add_default(NODE_SOURCE, None)
|
|
76
|
+
_add_default(SELECTED_FILE, None)
|
|
77
|
+
_add_default(SELECTED_FILE_PAGE, None)
|
|
78
|
+
_add_default(LOADED_CHIPS, {})
|
|
79
|
+
_add_default(MANIFEST_FILE, None)
|
|
80
|
+
_add_default(MANIFEST_LOCK, None)
|
|
81
|
+
_add_default(MANIFEST_TIME, None)
|
|
82
|
+
_add_default(IS_RUNNING, False)
|
|
83
|
+
_add_default(GRAPH_JOBS, None)
|
|
84
|
+
_add_default(UI_WIDTH, None)
|
|
85
|
+
_add_default(APP_LAYOUT, "vertical_flowgraph_sac_tabs")
|
|
86
|
+
_add_default(APP_RERUN, None)
|
|
87
|
+
_add_default(APP_RUNNING_REFRESH, 2 * 1000)
|
|
88
|
+
_add_default(APP_STOPPED_REFRESH, 30 * 1000)
|
|
89
|
+
_add_default(MAX_DICT_ITEMS_TO_SHOW, 100)
|
|
90
|
+
_add_default(MAX_FILE_LINES_TO_SHOW, 100)
|
|
91
|
+
_add_default(SELECT_TAB, None)
|
|
92
|
+
_add_default(TAB_INDEX, 0)
|
|
93
|
+
|
|
94
|
+
parser = argparse.ArgumentParser('dashboard')
|
|
95
|
+
parser.add_argument('cfg', nargs='?')
|
|
96
|
+
args = parser.parse_args()
|
|
97
|
+
|
|
98
|
+
if not args.cfg:
|
|
99
|
+
raise ValueError('configuration not provided')
|
|
100
|
+
|
|
101
|
+
if not get_key(LOADED_CHIPS):
|
|
102
|
+
# First time through
|
|
103
|
+
|
|
104
|
+
with open(args.cfg, 'r') as f:
|
|
105
|
+
config = json.load(f)
|
|
106
|
+
|
|
107
|
+
set_key(MANIFEST_FILE, config["manifest"])
|
|
108
|
+
set_key(MANIFEST_LOCK, fasteners.InterProcessLock(config["lock"]))
|
|
109
|
+
|
|
110
|
+
update_manifest()
|
|
111
|
+
chip = get_chip("default")
|
|
112
|
+
for graph_info in config['graph_chips']:
|
|
113
|
+
file_path = graph_info['path']
|
|
114
|
+
graph_chip = Chip(design='')
|
|
115
|
+
graph_chip.read_manifest(file_path)
|
|
116
|
+
graph_chip.unset('arg', 'step')
|
|
117
|
+
graph_chip.unset('arg', 'index')
|
|
118
|
+
|
|
119
|
+
if graph_info['cwd']:
|
|
120
|
+
graph_chip.cwd = graph_info['cwd']
|
|
121
|
+
|
|
122
|
+
add_chip(os.path.basename(file_path), graph_chip)
|
|
123
|
+
|
|
124
|
+
chip_step = chip.get('arg', 'step')
|
|
125
|
+
chip_index = chip.get('arg', 'index')
|
|
126
|
+
|
|
127
|
+
if chip_step and chip_index:
|
|
128
|
+
set_key(SELECTED_NODE, f'{chip_step}{chip_index}')
|
|
129
|
+
|
|
130
|
+
chip = get_chip("default")
|
|
131
|
+
chip.unset('arg', 'step')
|
|
132
|
+
chip.unset('arg', 'index')
|
|
133
|
+
|
|
134
|
+
if not get_key(SELECTED_JOB):
|
|
135
|
+
set_key(SELECTED_JOB, "default")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def setup():
|
|
139
|
+
with streamlit.empty():
|
|
140
|
+
# get width
|
|
141
|
+
set_key(UI_WIDTH, streamlit_javascript.st_javascript("window.innerWidth"))
|
|
142
|
+
# replace with a empty container to avoid adding a gap at the top
|
|
143
|
+
streamlit.empty()
|
|
144
|
+
|
|
145
|
+
set_key(NODE_SOURCE, None)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def get_chip(job=None):
|
|
149
|
+
if not job:
|
|
150
|
+
job = get_key(SELECTED_JOB)
|
|
151
|
+
return get_key(LOADED_CHIPS)[job]
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def add_chip(name, chip):
|
|
155
|
+
streamlit.session_state[LOADED_CHIPS][name] = chip
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def get_chips():
|
|
159
|
+
chips = list(get_key(LOADED_CHIPS).keys())
|
|
160
|
+
chips.remove('default')
|
|
161
|
+
chips.insert(0, 'default')
|
|
162
|
+
return chips
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def get_selected_node():
|
|
166
|
+
if get_key(NODE_SOURCE) == "flowgraph":
|
|
167
|
+
return get_key(SELECTED_FLOWGRAPH_NODE)
|
|
168
|
+
|
|
169
|
+
if get_key(NODE_SOURCE) == "selector":
|
|
170
|
+
return get_key(SELECTED_SELECTOR_NODE)
|
|
171
|
+
|
|
172
|
+
return get_key(SELECTED_NODE)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def get_key(key):
|
|
176
|
+
return streamlit.session_state[key]
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def set_key(key, value):
|
|
180
|
+
changed = value != streamlit.session_state[key]
|
|
181
|
+
if changed:
|
|
182
|
+
debug_print("set_key()", key, "changed", streamlit.session_state[key], "->", value)
|
|
183
|
+
streamlit.session_state[key] = value
|
|
184
|
+
return True
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def del_key(key):
|
|
189
|
+
debug_print("del_key()", key)
|
|
190
|
+
if key in streamlit.session_state:
|
|
191
|
+
del streamlit.session_state[key]
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def compute_component_size(minimum, requested_px):
|
|
195
|
+
ui_width = get_key(UI_WIDTH)
|
|
196
|
+
|
|
197
|
+
if ui_width > 0:
|
|
198
|
+
return min(requested_px / ui_width, minimum)
|
|
199
|
+
|
|
200
|
+
return minimum
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def debug_print(*args):
|
|
204
|
+
if not _DEBUG:
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
print(*args)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def debug_print_state():
|
|
211
|
+
if not _DEBUG:
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
for n, key in enumerate(sorted(streamlit.session_state.keys())):
|
|
215
|
+
value = streamlit.session_state[key]
|
|
216
|
+
print("state", n, key, type(value), value)
|
|
217
|
+
print()
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from siliconcompiler import NodeStatus
|
|
2
|
+
from siliconcompiler.flowgraph import _get_flowgraph_nodes
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_chip_cwd(chip, manifest):
|
|
8
|
+
build_dir = Path(chip.get('option', 'builddir'))
|
|
9
|
+
|
|
10
|
+
manifest_path = Path(manifest)
|
|
11
|
+
for path in manifest_path.parents:
|
|
12
|
+
if build_dir.name == path.name:
|
|
13
|
+
return str(path.parent)
|
|
14
|
+
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def make_node_to_step_index_map(chip, metric_dataframe):
|
|
19
|
+
'''
|
|
20
|
+
Returns a map from the name of a node to the associated step, index pair.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
metric_dataframe (pandas.DataFrame) : A dataframe full of all metrics and all
|
|
24
|
+
nodes of the selected chip
|
|
25
|
+
'''
|
|
26
|
+
node_to_step_index_map = {}
|
|
27
|
+
for step, index in _get_flowgraph_nodes(chip, chip.get('option', 'flow')):
|
|
28
|
+
node_to_step_index_map[f'{step}{index}'] = (step, index)
|
|
29
|
+
|
|
30
|
+
# concatenate step and index
|
|
31
|
+
metric_dataframe.columns = metric_dataframe.columns.map(lambda x: f'{x[0]}{x[1]}')
|
|
32
|
+
return node_to_step_index_map, metric_dataframe
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def make_metric_to_metric_unit_map(metric_dataframe):
|
|
36
|
+
'''
|
|
37
|
+
Returns a map from the name of a metric to the associated metric and unit in
|
|
38
|
+
the form f'{x[0]} ({x[1]})'
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
metric_dataframe (pandas.DataFrame) : A dataframe full of all metrics and all
|
|
42
|
+
nodes of the selected chip.
|
|
43
|
+
'''
|
|
44
|
+
metric_to_metric_unit_map = {}
|
|
45
|
+
for metric, unit in metric_dataframe.index.tolist():
|
|
46
|
+
if unit != '':
|
|
47
|
+
metric_to_metric_unit_map[f'{metric} ({unit})'] = metric
|
|
48
|
+
else:
|
|
49
|
+
metric_to_metric_unit_map[metric] = metric
|
|
50
|
+
# concatenate metric and unit
|
|
51
|
+
metric_dataframe.index = metric_dataframe.index.map(lambda x: f'{x[0]} ({x[1]})'
|
|
52
|
+
if x[1] else x[0])
|
|
53
|
+
return metric_to_metric_unit_map, metric_dataframe
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def is_running(chip):
|
|
57
|
+
for step, index in _get_flowgraph_nodes(chip, chip.get('option', 'flow')):
|
|
58
|
+
state = chip.get('record', 'status', step=step, index=index)
|
|
59
|
+
if not NodeStatus.is_done(state):
|
|
60
|
+
return True
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def generate_metric_dataframe(chip):
|
|
65
|
+
from siliconcompiler.report import report
|
|
66
|
+
|
|
67
|
+
metric_dataframe = report.make_metric_dataframe(chip)
|
|
68
|
+
node_to_step_index_map, metric_dataframe = \
|
|
69
|
+
make_node_to_step_index_map(chip, metric_dataframe)
|
|
70
|
+
metric_to_metric_unit_map, metric_dataframe = \
|
|
71
|
+
make_metric_to_metric_unit_map(metric_dataframe)
|
|
72
|
+
|
|
73
|
+
return metric_dataframe, node_to_step_index_map, metric_to_metric_unit_map
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import gzip
|
|
2
|
+
import os
|
|
3
|
+
from siliconcompiler import utils, sc_open
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def is_file_is_binary(path, compressed):
|
|
7
|
+
# Read first chunk and check for non characters
|
|
8
|
+
try:
|
|
9
|
+
if compressed:
|
|
10
|
+
with gzip.open(path, 'rt') as f:
|
|
11
|
+
f.read(8196)
|
|
12
|
+
else:
|
|
13
|
+
with open(path, "r") as f:
|
|
14
|
+
f.read(8196)
|
|
15
|
+
except UnicodeDecodeError:
|
|
16
|
+
return True
|
|
17
|
+
return False
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def read_file(path, max_lines):
|
|
21
|
+
_, compressed_file_extension = os.path.splitext(path.lower())
|
|
22
|
+
file_info = []
|
|
23
|
+
honor_max_file = max_lines is not None
|
|
24
|
+
|
|
25
|
+
def read_file(fid):
|
|
26
|
+
for line in fid:
|
|
27
|
+
file_info.append(line.rstrip())
|
|
28
|
+
if honor_max_file and len(file_info) >= max_lines:
|
|
29
|
+
file_info.append('... truncated ...')
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
is_compressed = compressed_file_extension == '.gz'
|
|
33
|
+
if is_file_is_binary(path, is_compressed):
|
|
34
|
+
return "Binary file"
|
|
35
|
+
|
|
36
|
+
if is_compressed:
|
|
37
|
+
with gzip.open(path, 'rt') as fid:
|
|
38
|
+
read_file(fid)
|
|
39
|
+
else:
|
|
40
|
+
with sc_open(path) as fid:
|
|
41
|
+
read_file(fid)
|
|
42
|
+
return "\n".join(file_info)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_file_type(ext):
|
|
46
|
+
if ext in ("v", "vh", "sv", "svh", "vg"):
|
|
47
|
+
return "verilog"
|
|
48
|
+
if ext in ("vhdl", "vhd"):
|
|
49
|
+
return "vhdl"
|
|
50
|
+
if ext in ("tcl", "sdc", "xdc"):
|
|
51
|
+
return "tcl"
|
|
52
|
+
if ext in ("c", "cpp", "cc", "h"):
|
|
53
|
+
return "cpp"
|
|
54
|
+
if ext in ("csv",):
|
|
55
|
+
return "csv"
|
|
56
|
+
if ext in ("md",):
|
|
57
|
+
return "markdown"
|
|
58
|
+
if ext in ("sh",):
|
|
59
|
+
return "bash"
|
|
60
|
+
return "log"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_file_icon(file):
|
|
64
|
+
if not file:
|
|
65
|
+
return 'file'
|
|
66
|
+
ext = utils.get_file_ext(file)
|
|
67
|
+
file_type = get_file_type(ext)
|
|
68
|
+
if file.endswith('.pkg.json'):
|
|
69
|
+
return 'boxes'
|
|
70
|
+
elif ext in ('png', 'jpg', 'jpeg'):
|
|
71
|
+
return 'file-image'
|
|
72
|
+
elif ext == 'json':
|
|
73
|
+
return 'file-json'
|
|
74
|
+
elif file_type in ('verilog', 'tcl', 'vhdl', 'cpp', 'bash'):
|
|
75
|
+
return 'file-code'
|
|
76
|
+
elif ext in ('log', 'rpt', 'drc', 'warnings', 'errors'):
|
|
77
|
+
return 'file-text'
|
|
78
|
+
return 'file'
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def convert_filepaths_to_select_tree(logs_and_reports):
|
|
82
|
+
"""
|
|
83
|
+
Converts the logs_and_reports found to the structure
|
|
84
|
+
required by streamlit_tree_select. Success is predicated on the order of
|
|
85
|
+
logs_and_reports outlined in report.get_files.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
logs_and_reports (list) : A list of 3-tuples with order of a path name,
|
|
89
|
+
folder in the..., and files in the....
|
|
90
|
+
"""
|
|
91
|
+
if not logs_and_reports:
|
|
92
|
+
return []
|
|
93
|
+
|
|
94
|
+
all_files = {}
|
|
95
|
+
for path_name, folders, files in logs_and_reports:
|
|
96
|
+
all_files[path_name] = {
|
|
97
|
+
'files': list(files),
|
|
98
|
+
'folders': list(folders)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
def organize_node(base_folder):
|
|
102
|
+
nodes = []
|
|
103
|
+
|
|
104
|
+
for folder in all_files[base_folder]['folders']:
|
|
105
|
+
path = os.path.join(base_folder, folder)
|
|
106
|
+
nodes.append({
|
|
107
|
+
'value': path,
|
|
108
|
+
'label': folder,
|
|
109
|
+
'children': organize_node(path)
|
|
110
|
+
})
|
|
111
|
+
for file in all_files[base_folder]['files']:
|
|
112
|
+
nodes.append({
|
|
113
|
+
'value': os.path.join(base_folder, file),
|
|
114
|
+
'label': file
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return nodes
|
|
118
|
+
|
|
119
|
+
starting_path_name = logs_and_reports[0][0]
|
|
120
|
+
return organize_node(starting_path_name)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import streamlit
|
|
2
|
+
|
|
3
|
+
from siliconcompiler.report.dashboard import components
|
|
4
|
+
from siliconcompiler.report.dashboard import layouts
|
|
5
|
+
from siliconcompiler.report.dashboard import state
|
|
6
|
+
from siliconcompiler.report.dashboard import utils
|
|
7
|
+
|
|
8
|
+
import streamlit_autorefresh
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
# opened by running command in siliconcompiler/apps/sc_dashboard.py
|
|
13
|
+
state.init()
|
|
14
|
+
|
|
15
|
+
components.setup_page()
|
|
16
|
+
state.setup()
|
|
17
|
+
|
|
18
|
+
layout = layouts.get_layout(state.get_key(state.APP_LAYOUT))
|
|
19
|
+
layout()
|
|
20
|
+
|
|
21
|
+
reload = False
|
|
22
|
+
if state.get_key(state.SELECTED_JOB) == 'default':
|
|
23
|
+
reload = state.set_key(state.IS_RUNNING, utils.is_running(state.get_chip()))
|
|
24
|
+
|
|
25
|
+
if state.get_key(state.IS_RUNNING):
|
|
26
|
+
update_interval = state.get_key(state.APP_RUNNING_REFRESH)
|
|
27
|
+
else:
|
|
28
|
+
update_interval = state.get_key(state.APP_STOPPED_REFRESH)
|
|
29
|
+
|
|
30
|
+
streamlit_autorefresh.st_autorefresh(interval=update_interval)
|
|
31
|
+
|
|
32
|
+
state.debug_print_state()
|
|
33
|
+
|
|
34
|
+
if reload or state.update_manifest() or state.get_key(state.APP_RERUN):
|
|
35
|
+
state.set_key(state.APP_RERUN, None)
|
|
36
|
+
streamlit.rerun()
|
siliconcompiler/report/report.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fnmatch
|
|
1
2
|
import pandas
|
|
2
3
|
import os
|
|
3
4
|
from siliconcompiler import Schema
|
|
@@ -104,7 +105,8 @@ def make_manifest_helper(manifest_subsect, modified_manifest_subsect):
|
|
|
104
105
|
|
|
105
106
|
def build_leaf(manifest_subsect):
|
|
106
107
|
if manifest_subsect['pernode'] == 'never':
|
|
107
|
-
if Schema.GLOBAL_KEY in manifest_subsect['node']
|
|
108
|
+
if Schema.GLOBAL_KEY in manifest_subsect['node'] and \
|
|
109
|
+
Schema.GLOBAL_KEY in manifest_subsect['node'][Schema.GLOBAL_KEY]:
|
|
108
110
|
value = manifest_subsect['node'][Schema.GLOBAL_KEY][Schema.GLOBAL_KEY]['value']
|
|
109
111
|
else:
|
|
110
112
|
value = manifest_subsect['node']['default']['default']['value']
|
|
@@ -201,7 +203,7 @@ def search_manifest_keys(manifest, key):
|
|
|
201
203
|
'''
|
|
202
204
|
filtered_manifest = {}
|
|
203
205
|
for dict_key in manifest:
|
|
204
|
-
if key
|
|
206
|
+
if fnmatch.fnmatch(dict_key, key):
|
|
205
207
|
filtered_manifest[dict_key] = manifest[dict_key]
|
|
206
208
|
elif isinstance(manifest[dict_key], dict):
|
|
207
209
|
result = search_manifest_keys(manifest[dict_key], key)
|
|
@@ -225,8 +227,16 @@ def search_manifest_values(manifest, value):
|
|
|
225
227
|
result = search_manifest_values(manifest[key], value)
|
|
226
228
|
if result: # result is non-empty
|
|
227
229
|
filtered_manifest[key] = result
|
|
228
|
-
|
|
229
|
-
|
|
230
|
+
else:
|
|
231
|
+
if manifest[key] is None:
|
|
232
|
+
continue
|
|
233
|
+
|
|
234
|
+
if isinstance(manifest[key], (list, tuple)):
|
|
235
|
+
if fnmatch.filter([str(v) for v in manifest[key]], value):
|
|
236
|
+
filtered_manifest[key] = manifest[key]
|
|
237
|
+
else:
|
|
238
|
+
if fnmatch.fnmatch(str(manifest[key]), value):
|
|
239
|
+
filtered_manifest[key] = manifest[key]
|
|
230
240
|
return filtered_manifest
|
|
231
241
|
|
|
232
242
|
|
|
@@ -251,8 +261,12 @@ def search_manifest(manifest, key_search=None, value_search=None):
|
|
|
251
261
|
'''
|
|
252
262
|
return_manifest = manifest
|
|
253
263
|
if key_search:
|
|
264
|
+
if '*' not in key_search or '?' not in key_search:
|
|
265
|
+
key_search = f'*{key_search}*'
|
|
254
266
|
return_manifest = search_manifest_keys(return_manifest, key_search)
|
|
255
267
|
if value_search:
|
|
268
|
+
if '*' not in value_search or '?' not in value_search:
|
|
269
|
+
value_search = f'*{value_search}*'
|
|
256
270
|
return_manifest = search_manifest_values(return_manifest, value_search)
|
|
257
271
|
return return_manifest
|
|
258
272
|
|
|
@@ -286,7 +300,11 @@ def get_metrics_source(chip, step, index):
|
|
|
286
300
|
'''
|
|
287
301
|
file_to_metric = {}
|
|
288
302
|
tool, task = get_tool_task(chip, step, index)
|
|
303
|
+
if not chip.valid('tool', tool, 'task', task, 'report'):
|
|
304
|
+
return file_to_metric
|
|
305
|
+
|
|
289
306
|
metrics = chip.getkeys('tool', tool, 'task', task, 'report')
|
|
307
|
+
|
|
290
308
|
for metric in metrics:
|
|
291
309
|
sources = chip.get('tool', tool, 'task', task, 'report', metric, step=step, index=index)
|
|
292
310
|
for source in sources:
|
|
@@ -12,10 +12,9 @@ def _show_summary_table(chip, flow, flowgraph_nodes, show_all_indices):
|
|
|
12
12
|
'''
|
|
13
13
|
|
|
14
14
|
# Display data
|
|
15
|
-
max_line_width = 135
|
|
16
15
|
column_width = 15
|
|
17
16
|
|
|
18
|
-
max_line_width = max(
|
|
17
|
+
max_line_width = max(2 * column_width, int(0.95*shutil.get_terminal_size().columns))
|
|
19
18
|
|
|
20
19
|
nodes, _, metrics, metrics_unit, metrics_to_show, _ = \
|
|
21
20
|
_collect_data(chip, flow, flowgraph_nodes)
|
siliconcompiler/report/utils.py
CHANGED
|
@@ -143,8 +143,7 @@ def _get_flowgraph_path(chip, flow, nodes_to_execute, only_include_successful=Fa
|
|
|
143
143
|
end_nodes = _get_flowgraph_exit_nodes(chip, flow, steps=flowgraph_steps)
|
|
144
144
|
for node in end_nodes:
|
|
145
145
|
if only_include_successful:
|
|
146
|
-
if chip.get('record', 'status', step=node[0], index=node[1])
|
|
147
|
-
NodeStatus.SUCCESS:
|
|
146
|
+
if NodeStatus.is_success(chip.get('record', 'status', step=node[0], index=node[1])):
|
|
148
147
|
selected_nodes.add(node)
|
|
149
148
|
to_search.append(node)
|
|
150
149
|
else:
|