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
siliconcompiler/_common.py
CHANGED
|
@@ -33,6 +33,18 @@ class NodeStatus():
|
|
|
33
33
|
NodeStatus.PENDING,
|
|
34
34
|
)
|
|
35
35
|
|
|
36
|
+
def is_success(status):
|
|
37
|
+
return status in (
|
|
38
|
+
NodeStatus.SUCCESS,
|
|
39
|
+
NodeStatus.SKIPPED
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def is_error(status):
|
|
43
|
+
return status in (
|
|
44
|
+
NodeStatus.ERROR,
|
|
45
|
+
NodeStatus.TIMEOUT
|
|
46
|
+
)
|
|
47
|
+
|
|
36
48
|
|
|
37
49
|
###############################################################################
|
|
38
50
|
# Package Customization classes
|
siliconcompiler/_metadata.py
CHANGED
|
@@ -82,9 +82,13 @@ To include another chip object to compare to:
|
|
|
82
82
|
raise ValueError(f'not a valid file path : {file_path}')
|
|
83
83
|
graph_chip = siliconcompiler.core.Chip(design='')
|
|
84
84
|
graph_chip.read_manifest(file_path)
|
|
85
|
-
graph_chips.append({
|
|
85
|
+
graph_chips.append({
|
|
86
|
+
'chip': graph_chip,
|
|
87
|
+
'name': name,
|
|
88
|
+
'cfg_path': os.path.abspath(file_path)
|
|
89
|
+
})
|
|
86
90
|
|
|
87
|
-
chip.
|
|
91
|
+
chip.dashboard(wait=True, port=switches['port'], graph_chips=graph_chips)
|
|
88
92
|
|
|
89
93
|
return 0
|
|
90
94
|
|
|
@@ -70,17 +70,46 @@ def show_tool(tool, script):
|
|
|
70
70
|
print_header("end")
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
def _get_os_name():
|
|
74
|
+
machine_info = _get_machine_info()
|
|
75
|
+
system = machine_info.get('system', "").lower()
|
|
76
|
+
distro = machine_info.get('distro', "").lower()
|
|
77
|
+
osversion = machine_info.get('osversion', "").lower()
|
|
78
|
+
if system == 'linux':
|
|
79
|
+
if distro == 'ubuntu':
|
|
80
|
+
version, _ = osversion.split('.')
|
|
81
|
+
return f"{distro}{version}"
|
|
82
|
+
elif distro == 'rocky':
|
|
83
|
+
version, _ = osversion.split('.')
|
|
84
|
+
return f"rhel{version}"
|
|
85
|
+
elif distro == 'rhel':
|
|
86
|
+
version, _ = osversion.split('.')
|
|
87
|
+
return f"rhel{version}"
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def print_machine_info():
|
|
92
|
+
machine_info = _get_machine_info()
|
|
93
|
+
mapped_os = _get_os_name()
|
|
94
|
+
|
|
95
|
+
print("System: ", machine_info.get('system', None))
|
|
96
|
+
print("Distro: ", machine_info.get('distro', None))
|
|
97
|
+
print("Version: ", machine_info.get('osversion', None))
|
|
98
|
+
print("Mapped OS:", mapped_os)
|
|
99
|
+
print("Scripts: ", _get_tool_script_dir())
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _get_tool_script_dir():
|
|
103
|
+
return Path(siliconcompiler.__file__).parent / "toolscripts"
|
|
104
|
+
|
|
105
|
+
|
|
73
106
|
def _get_tools_list():
|
|
74
|
-
tools_root =
|
|
107
|
+
tools_root = _get_tool_script_dir()
|
|
75
108
|
|
|
76
|
-
machine_info = _get_machine_info()
|
|
77
109
|
script_dir = None
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
script_dir = f"{machine_info['distro'].lower()}{version}"
|
|
82
|
-
if script_dir:
|
|
83
|
-
script_dir = tools_root / script_dir
|
|
110
|
+
os_dir = _get_os_name()
|
|
111
|
+
if os_dir:
|
|
112
|
+
script_dir = tools_root / os_dir
|
|
84
113
|
if not script_dir.exists():
|
|
85
114
|
script_dir = None
|
|
86
115
|
|
|
@@ -93,14 +122,20 @@ def _get_tools_list():
|
|
|
93
122
|
return tools
|
|
94
123
|
|
|
95
124
|
|
|
96
|
-
def _recommended_tool_groups():
|
|
97
|
-
|
|
125
|
+
def _recommended_tool_groups(tools):
|
|
126
|
+
groups = {
|
|
98
127
|
"asic": {"surelog", "sv2v", "yosys", "openroad", "klayout"},
|
|
99
128
|
"fpga": {"surelog", "sv2v", "yosys", "vpr"},
|
|
100
129
|
"digital-simulation": {"verilator", "icarus"},
|
|
101
130
|
"analog-simulation": {"xyce"}
|
|
102
131
|
}
|
|
103
132
|
|
|
133
|
+
filter_groups = {}
|
|
134
|
+
for group, group_tools in groups.items():
|
|
135
|
+
if all([tool in tools for tool in group_tools]):
|
|
136
|
+
filter_groups[group] = group_tools
|
|
137
|
+
return filter_groups
|
|
138
|
+
|
|
104
139
|
|
|
105
140
|
def main():
|
|
106
141
|
progname = "sc-install"
|
|
@@ -125,6 +160,9 @@ To build tools in a different location:
|
|
|
125
160
|
|
|
126
161
|
To show the install script:
|
|
127
162
|
sc-install -show openroad
|
|
163
|
+
|
|
164
|
+
To system debugging information (this should only be used to debug):
|
|
165
|
+
sc-install -debug_machine
|
|
128
166
|
-----------------------------------------------------------
|
|
129
167
|
"""
|
|
130
168
|
parser = argparse.ArgumentParser(
|
|
@@ -141,11 +179,12 @@ To show the install script:
|
|
|
141
179
|
choices=tool_choices,
|
|
142
180
|
help="tool to install")
|
|
143
181
|
|
|
182
|
+
tool_groups = _recommended_tool_groups(tools)
|
|
144
183
|
parser.add_argument(
|
|
145
184
|
"-group",
|
|
146
185
|
nargs="+",
|
|
147
|
-
choices=
|
|
148
|
-
help="tool group to install")
|
|
186
|
+
choices=tool_groups.keys(),
|
|
187
|
+
help=f"tool group to install{' - not supported' if not tool_groups else ''}")
|
|
149
188
|
|
|
150
189
|
parser.add_argument(
|
|
151
190
|
"-prefix",
|
|
@@ -164,15 +203,24 @@ To show the install script:
|
|
|
164
203
|
action="store_true",
|
|
165
204
|
help="Show the install script and exit")
|
|
166
205
|
|
|
206
|
+
parser.add_argument(
|
|
207
|
+
"-debug_machine",
|
|
208
|
+
action="store_true",
|
|
209
|
+
help="Show information about this machine and exit")
|
|
210
|
+
|
|
167
211
|
args = parser.parse_args()
|
|
168
212
|
|
|
213
|
+
if args.debug_machine:
|
|
214
|
+
print_machine_info()
|
|
215
|
+
return 0
|
|
216
|
+
|
|
169
217
|
if not args.tool:
|
|
170
218
|
args.tool = []
|
|
171
219
|
|
|
172
220
|
args.tool = list(args.tool)
|
|
173
221
|
if args.group:
|
|
174
222
|
for group in args.group:
|
|
175
|
-
args.tool.extend(
|
|
223
|
+
args.tool.extend(tool_groups[group])
|
|
176
224
|
|
|
177
225
|
tools_handled = set()
|
|
178
226
|
for tool in args.tool:
|
|
@@ -185,7 +185,7 @@ To delete a job, use:
|
|
|
185
185
|
# If only a manifest is specified, make a 'check_progress/' request and report results:
|
|
186
186
|
elif chip_cfg:
|
|
187
187
|
try:
|
|
188
|
-
check_progress(chip)
|
|
188
|
+
check_progress(chip, [], {})
|
|
189
189
|
except SiliconCompilerError as e:
|
|
190
190
|
chip.logger.error(f'{e}')
|
|
191
191
|
return 1
|
siliconcompiler/core.py
CHANGED
|
@@ -88,6 +88,9 @@ class Chip:
|
|
|
88
88
|
# Cache of file hashes
|
|
89
89
|
self.__hashes = {}
|
|
90
90
|
|
|
91
|
+
# Dashboard
|
|
92
|
+
self._dash = None
|
|
93
|
+
|
|
91
94
|
# Showtools
|
|
92
95
|
self._showtools = {}
|
|
93
96
|
for plugin in utils.get_plugins('show'):
|
|
@@ -758,7 +761,7 @@ class Chip:
|
|
|
758
761
|
return fullstr
|
|
759
762
|
|
|
760
763
|
###########################################################################
|
|
761
|
-
def valid(self, *keypath, default_valid=False, job=None):
|
|
764
|
+
def valid(self, *keypath, default_valid=False, job=None, check_complete=False):
|
|
762
765
|
"""
|
|
763
766
|
Checks validity of a keypath.
|
|
764
767
|
|
|
@@ -770,6 +773,7 @@ class Chip:
|
|
|
770
773
|
keypaths as a wildcard. Defaults to False.
|
|
771
774
|
job (str): Jobname to use for dictionary access in place of the
|
|
772
775
|
current active jobname.
|
|
776
|
+
check_complete (bool): Require the keypath be a complete path.
|
|
773
777
|
|
|
774
778
|
Returns:
|
|
775
779
|
Boolean indicating validity of keypath.
|
|
@@ -782,7 +786,10 @@ class Chip:
|
|
|
782
786
|
>>> check = chip.valid('metric', 'foo', '0', 'tasktime', default_valid=True)
|
|
783
787
|
Returns True, even if "foo" and "0" aren't in current configuration.
|
|
784
788
|
"""
|
|
785
|
-
return self.schema.valid(*keypath,
|
|
789
|
+
return self.schema.valid(*keypath,
|
|
790
|
+
default_valid=default_valid,
|
|
791
|
+
job=job,
|
|
792
|
+
check_complete=check_complete)
|
|
786
793
|
|
|
787
794
|
###########################################################################
|
|
788
795
|
def get(self, *keypath, field='value', job=None, step=None, index=None):
|
|
@@ -1123,6 +1130,9 @@ class Chip:
|
|
|
1123
1130
|
quiet=quiet)
|
|
1124
1131
|
return
|
|
1125
1132
|
|
|
1133
|
+
if filename is None:
|
|
1134
|
+
raise ValueError(f"{category} cannot process None")
|
|
1135
|
+
|
|
1126
1136
|
# Normalize value to string in case we receive a pathlib.Path
|
|
1127
1137
|
filename = str(filename)
|
|
1128
1138
|
|
|
@@ -1147,8 +1157,9 @@ class Chip:
|
|
|
1147
1157
|
use_filetype = filetype
|
|
1148
1158
|
|
|
1149
1159
|
if not use_fileset or not use_filetype:
|
|
1150
|
-
|
|
1151
|
-
|
|
1160
|
+
raise SiliconCompilerError(
|
|
1161
|
+
f'Unable to infer {category} fileset and/or filetype for '
|
|
1162
|
+
f'{filename} based on file extension.')
|
|
1152
1163
|
elif not quiet:
|
|
1153
1164
|
if not fileset and not filetype:
|
|
1154
1165
|
self.logger.info(f'{filename} inferred as {use_fileset}/{use_filetype}')
|
|
@@ -1352,7 +1363,7 @@ class Chip:
|
|
|
1352
1363
|
basename = str(pathlib.PurePosixPath(*path_paths[0:n]))
|
|
1353
1364
|
endname = str(pathlib.PurePosixPath(*path_paths[n:]))
|
|
1354
1365
|
|
|
1355
|
-
import_name =
|
|
1366
|
+
import_name = utils.get_hashed_filename(basename, package=package)
|
|
1356
1367
|
if import_name not in collected_files:
|
|
1357
1368
|
continue
|
|
1358
1369
|
|
|
@@ -2040,6 +2051,30 @@ class Chip:
|
|
|
2040
2051
|
dot.graph_attr['ranksep'] = '0.75'
|
|
2041
2052
|
dot.attr(bgcolor=background)
|
|
2042
2053
|
|
|
2054
|
+
subgraphs = {
|
|
2055
|
+
"graphs": {
|
|
2056
|
+
"sc-inputs": {
|
|
2057
|
+
"graphs": {},
|
|
2058
|
+
"nodes": []
|
|
2059
|
+
}
|
|
2060
|
+
},
|
|
2061
|
+
"nodes": []
|
|
2062
|
+
}
|
|
2063
|
+
for node, info in nodes.items():
|
|
2064
|
+
if info['is_input']:
|
|
2065
|
+
subgraph_temp = subgraphs["graphs"]["sc-inputs"]
|
|
2066
|
+
else:
|
|
2067
|
+
subgraph_temp = subgraphs
|
|
2068
|
+
|
|
2069
|
+
for key in node.split(".")[0:-1]:
|
|
2070
|
+
if key not in subgraph_temp["graphs"]:
|
|
2071
|
+
subgraph_temp["graphs"][key] = {
|
|
2072
|
+
"graphs": {},
|
|
2073
|
+
"nodes": []
|
|
2074
|
+
}
|
|
2075
|
+
subgraph_temp = subgraph_temp["graphs"][key]
|
|
2076
|
+
subgraph_temp["nodes"].append(node)
|
|
2077
|
+
|
|
2043
2078
|
with dot.subgraph(name='inputs') as input_graph:
|
|
2044
2079
|
input_graph.graph_attr['cluster'] = 'true'
|
|
2045
2080
|
input_graph.graph_attr['color'] = background
|
|
@@ -2051,34 +2086,72 @@ class Chip:
|
|
|
2051
2086
|
fontcolor=fontcolor, fontsize=fontsize, ordering="in",
|
|
2052
2087
|
penwidth=penwidth, fillcolor=fillcolor, shape="box")
|
|
2053
2088
|
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
input_graph_nodes.graph_attr['color'] = background
|
|
2089
|
+
def make_node(graph, node, prefix):
|
|
2090
|
+
info = nodes[node]
|
|
2057
2091
|
|
|
2058
|
-
# add nodes
|
|
2059
2092
|
shape = "oval" if not show_io else "Mrecord"
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2093
|
+
task_label = f"\\n ({info['task']})" if info['task'] is not None else ""
|
|
2094
|
+
if show_io:
|
|
2095
|
+
input_labels = [f"<{ikey}> {ifile}" for ifile, ikey in info['inputs'].items()]
|
|
2096
|
+
output_labels = [f"<{okey}> {ofile}" for ofile, okey in info['outputs'].items()]
|
|
2097
|
+
center_text = f"\\n {node.replace(prefix, '')} {task_label} \\n\\n"
|
|
2098
|
+
labelname = "{"
|
|
2099
|
+
if input_labels:
|
|
2100
|
+
labelname += f"{{ {' | '.join(input_labels)} }} |"
|
|
2101
|
+
labelname += center_text
|
|
2102
|
+
if output_labels:
|
|
2103
|
+
labelname += f"| {{ {' | '.join(output_labels)} }}"
|
|
2104
|
+
labelname += "}"
|
|
2105
|
+
else:
|
|
2106
|
+
labelname = f"{node.replace(prefix, '')}{task_label}"
|
|
2107
|
+
|
|
2108
|
+
graph.node(node, label=labelname, bordercolor=fontcolor, style='filled',
|
|
2109
|
+
fontcolor=fontcolor, fontsize=fontsize, ordering="in",
|
|
2110
|
+
penwidth=penwidth, fillcolor=fillcolor, shape=shape)
|
|
2111
|
+
|
|
2112
|
+
graph_idx = 0
|
|
2113
|
+
|
|
2114
|
+
def get_node_count(graph_info):
|
|
2115
|
+
nodes = len(graph_info["nodes"])
|
|
2116
|
+
|
|
2117
|
+
for subgraph in graph_info["graphs"]:
|
|
2118
|
+
nodes += get_node_count(graph_info["graphs"][subgraph])
|
|
2119
|
+
|
|
2120
|
+
return nodes
|
|
2121
|
+
|
|
2122
|
+
def build_graph(graph_info, parent, prefix):
|
|
2123
|
+
nonlocal graph_idx
|
|
2124
|
+
|
|
2125
|
+
for subgraph in graph_info["graphs"]:
|
|
2126
|
+
if get_node_count(graph_info["graphs"][subgraph]) > 1:
|
|
2127
|
+
graph = graphviz.Digraph(name=f"cluster_{graph_idx}")
|
|
2128
|
+
graph_idx += 1
|
|
2129
|
+
|
|
2130
|
+
graph.graph_attr['rankdir'] = rankdir
|
|
2131
|
+
graph.attr(bgcolor=background)
|
|
2132
|
+
|
|
2133
|
+
if subgraph == "sc-inputs":
|
|
2134
|
+
graph.attr(style='invis')
|
|
2135
|
+
else:
|
|
2136
|
+
graph.attr(color=fontcolor)
|
|
2137
|
+
graph.attr(style='rounded')
|
|
2138
|
+
graph.attr(shape='oval')
|
|
2139
|
+
graph.attr(label=subgraph)
|
|
2140
|
+
graph.attr(labeljust='l')
|
|
2141
|
+
graph.attr(fontcolor=fontcolor)
|
|
2142
|
+
graph.attr(fontsize=str(int(fontsize) + 2))
|
|
2073
2143
|
else:
|
|
2074
|
-
|
|
2144
|
+
graph = parent
|
|
2145
|
+
|
|
2146
|
+
build_graph(graph_info["graphs"][subgraph], graph, f"{prefix}{subgraph}.")
|
|
2147
|
+
|
|
2148
|
+
if graph is not parent:
|
|
2149
|
+
parent.subgraph(graph)
|
|
2075
2150
|
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
fontcolor=fontcolor, fontsize=fontsize, ordering="in",
|
|
2081
|
-
penwidth=penwidth, fillcolor=fillcolor, shape=shape)
|
|
2151
|
+
for subnode in graph_info["nodes"]:
|
|
2152
|
+
make_node(parent, subnode, prefix)
|
|
2153
|
+
|
|
2154
|
+
build_graph(subgraphs, dot, "")
|
|
2082
2155
|
|
|
2083
2156
|
for edge0, edge1, weight in edges:
|
|
2084
2157
|
dot.edge(f'{edge0}{out_label_suffix}', f'{edge1}{in_label_suffix}', weight=str(weight))
|
|
@@ -2383,7 +2456,7 @@ class Chip:
|
|
|
2383
2456
|
|
|
2384
2457
|
abspath = dirs[(package, path)]
|
|
2385
2458
|
if abspath:
|
|
2386
|
-
filename =
|
|
2459
|
+
filename = utils.get_hashed_filename(posix_path, package=package)
|
|
2387
2460
|
dst_path = os.path.join(directory, filename)
|
|
2388
2461
|
if os.path.exists(dst_path):
|
|
2389
2462
|
continue
|
|
@@ -2455,7 +2528,7 @@ class Chip:
|
|
|
2455
2528
|
|
|
2456
2529
|
abspath = files[(package, path)]
|
|
2457
2530
|
if abspath:
|
|
2458
|
-
filename =
|
|
2531
|
+
filename = utils.get_hashed_filename(posix_path, package=package)
|
|
2459
2532
|
dst_path = os.path.join(directory, filename)
|
|
2460
2533
|
if verbose:
|
|
2461
2534
|
self.logger.info(f"Copying {abspath} to '{directory}' directory")
|
|
@@ -2691,12 +2764,12 @@ class Chip:
|
|
|
2691
2764
|
return hashlist
|
|
2692
2765
|
|
|
2693
2766
|
###########################################################################
|
|
2694
|
-
def
|
|
2767
|
+
def dashboard(self, wait=True, port=None, graph_chips=None):
|
|
2695
2768
|
'''
|
|
2696
2769
|
Open a session of the dashboard.
|
|
2697
2770
|
|
|
2698
2771
|
The dashboard can be viewed in any webbrowser and can be accessed via:
|
|
2699
|
-
http://localhost
|
|
2772
|
+
http://localhost:<port>/
|
|
2700
2773
|
|
|
2701
2774
|
Args:
|
|
2702
2775
|
wait (bool): If True, this call will wait in this method
|
|
@@ -2707,21 +2780,28 @@ class Chip:
|
|
|
2707
2780
|
{'chip': chip object, 'name': chip name}
|
|
2708
2781
|
|
|
2709
2782
|
Examples:
|
|
2710
|
-
>>> chip.
|
|
2783
|
+
>>> chip.dashboard()
|
|
2711
2784
|
Opens a sesison of the dashboard.
|
|
2712
2785
|
'''
|
|
2713
|
-
|
|
2714
|
-
|
|
2786
|
+
if self._dash:
|
|
2787
|
+
# Remove previous dashboard
|
|
2788
|
+
self._dash.stop()
|
|
2789
|
+
self._dash = None
|
|
2790
|
+
|
|
2791
|
+
self._dash = Dashboard(self, port=port, graph_chips=graph_chips)
|
|
2792
|
+
self._dash.open_dashboard()
|
|
2793
|
+
|
|
2715
2794
|
if wait:
|
|
2716
2795
|
try:
|
|
2717
|
-
|
|
2796
|
+
self._dash.wait()
|
|
2718
2797
|
except KeyboardInterrupt:
|
|
2719
|
-
|
|
2798
|
+
self._dash._sleep()
|
|
2720
2799
|
finally:
|
|
2721
|
-
|
|
2800
|
+
self._dash.stop()
|
|
2801
|
+
self._dash = None
|
|
2722
2802
|
return None
|
|
2723
2803
|
|
|
2724
|
-
return
|
|
2804
|
+
return self._dash
|
|
2725
2805
|
|
|
2726
2806
|
###########################################################################
|
|
2727
2807
|
def summary(self, show_all_indices=False, generate_image=True, generate_html=True):
|
|
@@ -2761,8 +2841,8 @@ class Chip:
|
|
|
2761
2841
|
work_dir = self.getworkdir()
|
|
2762
2842
|
if os.path.isdir(work_dir):
|
|
2763
2843
|
# Mark file paths where the reports can be found if they were generated.
|
|
2764
|
-
results_html = os.path.join(work_dir, 'report.html')
|
|
2765
2844
|
results_img = os.path.join(work_dir, f'{self.design}.png')
|
|
2845
|
+
results_html = os.path.join(work_dir, 'report.html')
|
|
2766
2846
|
|
|
2767
2847
|
if generate_image:
|
|
2768
2848
|
_generate_summary_image(self, results_img)
|
|
@@ -2770,13 +2850,18 @@ class Chip:
|
|
|
2770
2850
|
if generate_html:
|
|
2771
2851
|
_generate_html_report(self, flow, nodes_to_execute, results_html)
|
|
2772
2852
|
|
|
2853
|
+
# dashboard does not generate any data
|
|
2854
|
+
self.logger.info(f'Dashboard at "sc-dashboard -cfg {work_dir}/{self.design}.pkg.json"')
|
|
2855
|
+
|
|
2773
2856
|
# Try to open the results and layout only if '-nodisplay' is not set.
|
|
2774
|
-
# Priority: PNG
|
|
2775
|
-
if
|
|
2857
|
+
# Priority: PNG > HTML > dashboard.
|
|
2858
|
+
if not self.get('option', 'nodisplay'):
|
|
2776
2859
|
if os.path.isfile(results_img):
|
|
2777
2860
|
_open_summary_image(results_img)
|
|
2778
2861
|
elif os.path.isfile(results_html):
|
|
2779
2862
|
_open_html_report(self, results_html)
|
|
2863
|
+
else:
|
|
2864
|
+
self._dashboard(wait=False)
|
|
2780
2865
|
|
|
2781
2866
|
###########################################################################
|
|
2782
2867
|
def clock(self, pin, period, jitter=0, mode='global'):
|
|
@@ -3120,6 +3205,7 @@ class Chip:
|
|
|
3120
3205
|
self.set('option', 'nodisplay', False, clobber=True)
|
|
3121
3206
|
self.set('option', 'continue', True, clobber=True)
|
|
3122
3207
|
self.set('option', 'quiet', False, clobber=True)
|
|
3208
|
+
self.set('option', 'clean', True, clobber=True)
|
|
3123
3209
|
self.set('arg', 'step', None, clobber=True)
|
|
3124
3210
|
self.set('arg', 'index', None, clobber=True)
|
|
3125
3211
|
self.unset('option', 'to')
|
|
@@ -3214,31 +3300,6 @@ class Chip:
|
|
|
3214
3300
|
|
|
3215
3301
|
return os.path.join(*dirlist)
|
|
3216
3302
|
|
|
3217
|
-
#######################################
|
|
3218
|
-
def __get_imported_filename(self, pathstr, package=None):
|
|
3219
|
-
''' Utility to map collected file to an unambiguous name based on its path.
|
|
3220
|
-
|
|
3221
|
-
The mapping looks like:
|
|
3222
|
-
path/to/file.ext => file_<md5('path/to/file.ext')>.ext
|
|
3223
|
-
'''
|
|
3224
|
-
path = pathlib.PurePosixPath(pathstr)
|
|
3225
|
-
ext = ''.join(path.suffixes)
|
|
3226
|
-
|
|
3227
|
-
# strip off all file suffixes to get just the bare name
|
|
3228
|
-
barepath = path
|
|
3229
|
-
while barepath.suffix:
|
|
3230
|
-
barepath = pathlib.PurePosixPath(barepath.stem)
|
|
3231
|
-
filename = str(barepath.parts[-1])
|
|
3232
|
-
|
|
3233
|
-
if not package:
|
|
3234
|
-
package = ''
|
|
3235
|
-
else:
|
|
3236
|
-
package = f'{package}:'
|
|
3237
|
-
path_to_hash = f'{package}{str(path)}'
|
|
3238
|
-
pathhash = hashlib.sha1(path_to_hash.encode('utf-8')).hexdigest()
|
|
3239
|
-
|
|
3240
|
-
return f'{filename}_{pathhash}{ext}'
|
|
3241
|
-
|
|
3242
3303
|
def error(self, msg):
|
|
3243
3304
|
'''
|
|
3244
3305
|
Raises error.
|
|
@@ -3273,6 +3334,9 @@ class Chip:
|
|
|
3273
3334
|
# Modules are not serializable, so save without cache
|
|
3274
3335
|
attributes['_showtools'] = {}
|
|
3275
3336
|
|
|
3337
|
+
# Dashboard is not serializable
|
|
3338
|
+
attributes['_dash'] = None
|
|
3339
|
+
|
|
3276
3340
|
# We have to remove the chip's logger before serializing the object
|
|
3277
3341
|
# since the logger object is not serializable.
|
|
3278
3342
|
del attributes['logger']
|
|
@@ -43,6 +43,14 @@ def setup():
|
|
|
43
43
|
|
|
44
44
|
fpga.set('fpga', part_name, 'vendor', vendor)
|
|
45
45
|
|
|
46
|
+
# Part name is specified per architecture file. Device code specifies
|
|
47
|
+
# which <fixed_layout> name to use when running VPR. These examples
|
|
48
|
+
# use the following names:
|
|
49
|
+
if (part_name == 'example_arch_X005Y005'):
|
|
50
|
+
fpga.set('fpga', part_name, 'var', 'vpr_device_code', 'fpga_beta')
|
|
51
|
+
else:
|
|
52
|
+
fpga.set('fpga', part_name, 'var', 'vpr_device_code', part_name)
|
|
53
|
+
|
|
46
54
|
fpga.set('fpga', part_name, 'lutsize', lut_size)
|
|
47
55
|
|
|
48
56
|
arch_root = os.path.join(flow_root, 'arch', part_name)
|
siliconcompiler/package.py
CHANGED
|
@@ -88,7 +88,8 @@ def _path(chip, package, download_handler):
|
|
|
88
88
|
chip._packages[package] = data_path
|
|
89
89
|
return data_path
|
|
90
90
|
|
|
91
|
-
raise SiliconCompilerError(f'Extracting {package} data to {data_path} failed'
|
|
91
|
+
raise SiliconCompilerError(f'Extracting {package} data to {data_path} failed',
|
|
92
|
+
chip=chip)
|
|
92
93
|
|
|
93
94
|
|
|
94
95
|
def path(chip, package):
|
|
@@ -188,7 +189,7 @@ def clone_synchronized(chip, package, data, data_path):
|
|
|
188
189
|
elif url.scheme in ['git', 'git+https']:
|
|
189
190
|
chip.logger.error('Failed to authenticate. Please use a token or ssh.')
|
|
190
191
|
else:
|
|
191
|
-
|
|
192
|
+
chip.logger.error(str(e))
|
|
192
193
|
|
|
193
194
|
|
|
194
195
|
def clone_from_git(chip, package, data, repo_path):
|
siliconcompiler/remote/client.py
CHANGED
|
@@ -178,7 +178,7 @@ def _log_truncated_stats(chip, status, nodes_with_status, nodes_to_print):
|
|
|
178
178
|
|
|
179
179
|
|
|
180
180
|
###################################
|
|
181
|
-
def _process_progress_info(chip, progress_info, nodes_to_print=3):
|
|
181
|
+
def _process_progress_info(chip, progress_info, recorded_nodes, all_nodes, nodes_to_print=3):
|
|
182
182
|
'''
|
|
183
183
|
Helper method to log information about a remote run's progress,
|
|
184
184
|
based on information returned from a 'check_progress/' call.
|
|
@@ -201,6 +201,11 @@ def _process_progress_info(chip, progress_info, nodes_to_print=3):
|
|
|
201
201
|
# collect completed
|
|
202
202
|
completed.append(node)
|
|
203
203
|
|
|
204
|
+
if node in all_nodes:
|
|
205
|
+
step, index = all_nodes[node]
|
|
206
|
+
if (step, index) not in recorded_nodes:
|
|
207
|
+
chip.set('record', 'status', status, step=step, index=index)
|
|
208
|
+
|
|
204
209
|
nodes_to_log = {key: nodes_to_log[key] for key in sorted(nodes_to_log.keys())}
|
|
205
210
|
|
|
206
211
|
# Log information about the job's progress.
|
|
@@ -360,11 +365,32 @@ def __remote_run_loop(chip, check_interval):
|
|
|
360
365
|
completed = []
|
|
361
366
|
result_procs = []
|
|
362
367
|
|
|
368
|
+
recorded = []
|
|
369
|
+
|
|
363
370
|
for step, index in nodes_to_execute(chip):
|
|
364
371
|
if SCNodeStatus.is_done(chip.get('record', 'status', step=step, index=index)):
|
|
365
372
|
continue
|
|
366
373
|
all_nodes[f'{step}{index}'] = (step, index)
|
|
367
374
|
|
|
375
|
+
def import_manifests():
|
|
376
|
+
changed = False
|
|
377
|
+
for step, index in all_nodes.values():
|
|
378
|
+
if (step, index) in recorded:
|
|
379
|
+
continue
|
|
380
|
+
|
|
381
|
+
manifest = os.path.join(chip.getworkdir(step=step, index=index),
|
|
382
|
+
'outputs',
|
|
383
|
+
f'{chip.design}.pkg.json')
|
|
384
|
+
if os.path.exists(manifest):
|
|
385
|
+
try:
|
|
386
|
+
chip.schema.read_journal(manifest)
|
|
387
|
+
recorded.append((step, index))
|
|
388
|
+
changed = True
|
|
389
|
+
except: # noqa E722
|
|
390
|
+
# Import may fail if file is still getting written
|
|
391
|
+
pass
|
|
392
|
+
return changed
|
|
393
|
+
|
|
368
394
|
def schedule_download(node):
|
|
369
395
|
node_proc = multiprocessor.Process(target=fetch_results,
|
|
370
396
|
args=(chip, node))
|
|
@@ -376,7 +402,12 @@ def __remote_run_loop(chip, check_interval):
|
|
|
376
402
|
|
|
377
403
|
while is_busy:
|
|
378
404
|
time.sleep(check_interval)
|
|
379
|
-
|
|
405
|
+
import_manifests()
|
|
406
|
+
new_completed, is_busy = check_progress(chip, recorded, all_nodes)
|
|
407
|
+
|
|
408
|
+
if chip._dash:
|
|
409
|
+
chip._dash.update_manifest()
|
|
410
|
+
|
|
380
411
|
nodes_to_fetch = []
|
|
381
412
|
for node in new_completed:
|
|
382
413
|
if node not in completed:
|
|
@@ -400,26 +431,26 @@ def __remote_run_loop(chip, check_interval):
|
|
|
400
431
|
proc.join()
|
|
401
432
|
|
|
402
433
|
# Read in node manifests
|
|
403
|
-
|
|
404
|
-
manifest = os.path.join(chip.getworkdir(step=step, index=index),
|
|
405
|
-
'outputs',
|
|
406
|
-
f'{chip.design}.pkg.json')
|
|
407
|
-
if os.path.exists(manifest):
|
|
408
|
-
chip.schema.read_journal(manifest)
|
|
434
|
+
import_manifests()
|
|
409
435
|
|
|
410
436
|
# Un-set the 'remote' option to avoid from/to-based summary/show errors
|
|
411
437
|
chip.unset('option', 'remote')
|
|
412
438
|
|
|
439
|
+
if chip._dash:
|
|
440
|
+
chip._dash.update_manifest()
|
|
441
|
+
|
|
413
442
|
|
|
414
443
|
###################################
|
|
415
|
-
def check_progress(chip):
|
|
444
|
+
def check_progress(chip, recorded_nodes, all_nodes):
|
|
416
445
|
try:
|
|
417
446
|
is_busy_info = is_job_busy(chip)
|
|
418
447
|
is_busy = is_busy_info['busy']
|
|
419
448
|
completed = []
|
|
420
449
|
if is_busy:
|
|
421
450
|
completed = _process_progress_info(chip,
|
|
422
|
-
is_busy_info
|
|
451
|
+
is_busy_info,
|
|
452
|
+
recorded_nodes,
|
|
453
|
+
all_nodes)
|
|
423
454
|
return completed, is_busy
|
|
424
455
|
except Exception as e:
|
|
425
456
|
# Sometimes an exception is raised if the request library cannot
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from .summary_image import _generate_summary_image, _open_summary_image
|
|
2
2
|
from .html_report import _generate_html_report, _open_html_report
|
|
3
3
|
from .summary_table import _show_summary_table
|
|
4
|
-
from .
|
|
4
|
+
from .dashboard import Dashboard
|
|
5
5
|
|
|
6
6
|
__all__ = [
|
|
7
7
|
"_generate_summary_image",
|