siliconcompiler 0.33.2__py3-none-any.whl → 0.34.1__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/__init__.py +2 -0
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/_common.py +1 -1
- siliconcompiler/apps/sc.py +1 -1
- siliconcompiler/apps/sc_issue.py +6 -4
- siliconcompiler/apps/sc_remote.py +3 -20
- siliconcompiler/apps/sc_show.py +2 -2
- siliconcompiler/apps/utils/replay.py +4 -4
- siliconcompiler/checklist.py +202 -1
- siliconcompiler/core.py +62 -293
- siliconcompiler/data/templates/email/general.j2 +3 -3
- siliconcompiler/data/templates/email/summary.j2 +1 -1
- siliconcompiler/data/templates/issue/README.txt +1 -1
- siliconcompiler/data/templates/report/sc_report.j2 +7 -7
- siliconcompiler/dependencyschema.py +392 -0
- siliconcompiler/design.py +758 -0
- siliconcompiler/flowgraph.py +79 -13
- siliconcompiler/optimizer/vizier.py +2 -2
- siliconcompiler/package/__init__.py +383 -223
- siliconcompiler/package/git.py +75 -77
- siliconcompiler/package/github.py +70 -97
- siliconcompiler/package/https.py +77 -93
- siliconcompiler/packageschema.py +260 -0
- siliconcompiler/pdk.py +5 -5
- siliconcompiler/remote/client.py +33 -15
- siliconcompiler/remote/server.py +2 -2
- siliconcompiler/report/dashboard/cli/__init__.py +6 -6
- siliconcompiler/report/dashboard/cli/board.py +4 -4
- siliconcompiler/report/dashboard/web/components/__init__.py +5 -5
- siliconcompiler/report/dashboard/web/components/flowgraph.py +4 -4
- siliconcompiler/report/dashboard/web/components/graph.py +2 -2
- siliconcompiler/report/dashboard/web/state.py +1 -1
- siliconcompiler/report/dashboard/web/utils/__init__.py +5 -5
- siliconcompiler/report/html_report.py +1 -1
- siliconcompiler/report/report.py +4 -4
- siliconcompiler/report/summary_table.py +2 -2
- siliconcompiler/report/utils.py +5 -5
- siliconcompiler/scheduler/__init__.py +3 -1382
- siliconcompiler/scheduler/docker.py +263 -0
- siliconcompiler/scheduler/run_node.py +10 -21
- siliconcompiler/scheduler/scheduler.py +311 -0
- siliconcompiler/scheduler/schedulernode.py +944 -0
- siliconcompiler/scheduler/send_messages.py +3 -3
- siliconcompiler/scheduler/slurm.py +149 -163
- siliconcompiler/scheduler/taskscheduler.py +45 -57
- siliconcompiler/schema/__init__.py +3 -3
- siliconcompiler/schema/baseschema.py +234 -11
- siliconcompiler/schema/editableschema.py +4 -0
- siliconcompiler/schema/journal.py +210 -0
- siliconcompiler/schema/namedschema.py +55 -2
- siliconcompiler/schema/parameter.py +14 -1
- siliconcompiler/schema/parametervalue.py +1 -34
- siliconcompiler/schema/schema_cfg.py +210 -349
- siliconcompiler/tool.py +412 -148
- siliconcompiler/tools/__init__.py +2 -0
- siliconcompiler/tools/builtin/_common.py +5 -5
- siliconcompiler/tools/builtin/concatenate.py +7 -7
- siliconcompiler/tools/builtin/minimum.py +4 -4
- siliconcompiler/tools/builtin/mux.py +4 -4
- siliconcompiler/tools/builtin/nop.py +4 -4
- siliconcompiler/tools/builtin/verify.py +8 -9
- siliconcompiler/tools/execute/exec_input.py +1 -1
- siliconcompiler/tools/genfasm/genfasm.py +1 -6
- siliconcompiler/tools/openroad/_apr.py +5 -1
- siliconcompiler/tools/openroad/antenna_repair.py +1 -1
- siliconcompiler/tools/openroad/macro_placement.py +1 -1
- siliconcompiler/tools/openroad/power_grid.py +1 -1
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +32 -25
- siliconcompiler/tools/opensta/timing.py +26 -3
- siliconcompiler/tools/slang/__init__.py +2 -2
- siliconcompiler/tools/surfer/__init__.py +0 -0
- siliconcompiler/tools/surfer/show.py +53 -0
- siliconcompiler/tools/surfer/surfer.py +30 -0
- siliconcompiler/tools/vpr/route.py +82 -0
- siliconcompiler/tools/vpr/vpr.py +23 -6
- siliconcompiler/tools/yosys/__init__.py +1 -1
- siliconcompiler/tools/yosys/scripts/procs.tcl +143 -0
- siliconcompiler/tools/yosys/{sc_synth_asic.tcl → scripts/sc_synth_asic.tcl} +4 -0
- siliconcompiler/tools/yosys/{sc_synth_fpga.tcl → scripts/sc_synth_fpga.tcl} +24 -77
- siliconcompiler/tools/yosys/syn_fpga.py +14 -0
- siliconcompiler/toolscripts/_tools.json +9 -13
- siliconcompiler/toolscripts/rhel9/install-vpr.sh +0 -2
- siliconcompiler/toolscripts/ubuntu22/install-surfer.sh +33 -0
- siliconcompiler/toolscripts/ubuntu24/install-surfer.sh +33 -0
- siliconcompiler/utils/__init__.py +4 -24
- siliconcompiler/utils/flowgraph.py +29 -28
- siliconcompiler/utils/issue.py +23 -29
- siliconcompiler/utils/logging.py +37 -7
- siliconcompiler/utils/showtools.py +6 -1
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/METADATA +16 -25
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/RECORD +98 -91
- siliconcompiler/scheduler/docker_runner.py +0 -254
- siliconcompiler/schema/journalingschema.py +0 -242
- siliconcompiler/tools/yosys/procs.tcl +0 -71
- siliconcompiler/toolscripts/rhel9/install-yosys-parmys.sh +0 -68
- siliconcompiler/toolscripts/ubuntu22/install-yosys-parmys.sh +0 -68
- siliconcompiler/toolscripts/ubuntu24/install-yosys-parmys.sh +0 -68
- /siliconcompiler/tools/yosys/{sc_lec.tcl → scripts/sc_lec.tcl} +0 -0
- /siliconcompiler/tools/yosys/{sc_screenshot.tcl → scripts/sc_screenshot.tcl} +0 -0
- /siliconcompiler/tools/yosys/{syn_strategies.tcl → scripts/syn_strategies.tcl} +0 -0
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/top_level.txt +0 -0
siliconcompiler/core.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Copyright 2020 Silicon Compiler Authors. All Rights Reserved.
|
|
2
2
|
|
|
3
|
+
import copy
|
|
3
4
|
import tarfile
|
|
4
5
|
import os
|
|
5
6
|
import pathlib
|
|
@@ -13,20 +14,16 @@ import shutil
|
|
|
13
14
|
import importlib
|
|
14
15
|
import textwrap
|
|
15
16
|
import graphviz
|
|
16
|
-
import codecs
|
|
17
17
|
import csv
|
|
18
18
|
import yaml
|
|
19
19
|
from inspect import getfullargspec
|
|
20
20
|
from siliconcompiler import Schema
|
|
21
|
-
from siliconcompiler.schema import SCHEMA_VERSION, PerNode,
|
|
21
|
+
from siliconcompiler.schema import SCHEMA_VERSION, PerNode, Journal, EditableSchema
|
|
22
22
|
from siliconcompiler.schema.parametertype import NodeType
|
|
23
|
-
from siliconcompiler.schema.parametervalue import FileNodeValue
|
|
23
|
+
from siliconcompiler.schema.parametervalue import FileNodeValue
|
|
24
24
|
from siliconcompiler.schema import utils as schema_utils
|
|
25
25
|
from siliconcompiler import utils
|
|
26
|
-
from siliconcompiler.utils.logging import
|
|
27
|
-
SCLoggerFormatter, SCInRunLoggerFormatter, \
|
|
28
|
-
SCDebugLoggerFormatter, SCDebugInRunLoggerFormatter, \
|
|
29
|
-
SCBlankLoggerFormatter
|
|
26
|
+
from siliconcompiler.utils.logging import get_console_formatter, SCLoggerFormatter
|
|
30
27
|
from siliconcompiler import _metadata
|
|
31
28
|
from siliconcompiler import NodeStatus, SiliconCompilerError
|
|
32
29
|
from siliconcompiler.report import _show_summary_table
|
|
@@ -34,9 +31,8 @@ from siliconcompiler.report import _generate_summary_image, _open_summary_image
|
|
|
34
31
|
from siliconcompiler.report.dashboard.web import WebDashboard
|
|
35
32
|
from siliconcompiler.report.dashboard.cli import CliDashboard
|
|
36
33
|
from siliconcompiler.report.dashboard import DashboardType
|
|
37
|
-
from siliconcompiler import package as sc_package
|
|
38
34
|
import glob
|
|
39
|
-
from siliconcompiler.scheduler import
|
|
35
|
+
from siliconcompiler.scheduler.scheduler import Scheduler
|
|
40
36
|
from siliconcompiler.utils.flowgraph import _check_flowgraph_io, _get_flowgraph_information
|
|
41
37
|
from siliconcompiler.tools._common import get_tool_task
|
|
42
38
|
from types import FunctionType, ModuleType
|
|
@@ -73,14 +69,13 @@ class Chip:
|
|
|
73
69
|
"SiliconCompiler must be run from a directory that exists. "
|
|
74
70
|
"If you are sure that your working directory is valid, try running `cd $(pwd)`.")
|
|
75
71
|
|
|
76
|
-
|
|
77
|
-
# by each spawned (as opposed to forked) subprocess
|
|
78
|
-
self._init_codecs()
|
|
79
|
-
|
|
80
|
-
self._init_logger()
|
|
72
|
+
self.__init_logger()
|
|
81
73
|
|
|
82
74
|
self.schema = Schema(logger=self.logger)
|
|
83
75
|
|
|
76
|
+
# Setup console formatting
|
|
77
|
+
self._logger_console.setFormatter(get_console_formatter(self, False, None, None))
|
|
78
|
+
|
|
84
79
|
self.register_source('siliconcompiler',
|
|
85
80
|
'python://siliconcompiler')
|
|
86
81
|
|
|
@@ -206,96 +201,21 @@ class Chip:
|
|
|
206
201
|
else:
|
|
207
202
|
return module
|
|
208
203
|
|
|
209
|
-
def _add_file_logger(self, filename):
|
|
210
|
-
# Add a file handler for logging
|
|
211
|
-
file_handler = logging.FileHandler(filename)
|
|
212
|
-
self.logger.addHandler(file_handler)
|
|
213
|
-
|
|
214
|
-
self._init_logger_formats()
|
|
215
|
-
|
|
216
|
-
return file_handler
|
|
217
|
-
|
|
218
204
|
###########################################################################
|
|
219
|
-
def
|
|
220
|
-
|
|
205
|
+
def __init_logger(self):
|
|
221
206
|
# Check if the logger exists and create
|
|
222
207
|
if not hasattr(self, 'logger') or not self.logger:
|
|
223
208
|
self.logger = logging.getLogger(f'sc_{id(self)}')
|
|
224
209
|
|
|
225
210
|
self.logger.propagate = False
|
|
226
211
|
|
|
227
|
-
|
|
228
|
-
if hasattr(self, 'schema'):
|
|
229
|
-
loglevel = self.schema.get('option', 'loglevel', step=step, index=index)
|
|
230
|
-
else:
|
|
231
|
-
in_run = False
|
|
232
|
-
|
|
233
|
-
# Save in run flag
|
|
234
|
-
self.logger._in_run = in_run
|
|
235
|
-
self.logger._in_step = step
|
|
236
|
-
self.logger._in_index = index
|
|
237
|
-
|
|
238
|
-
self.logger.setLevel(schema_utils.translate_loglevel(loglevel))
|
|
239
|
-
|
|
240
|
-
if not self.logger.hasHandlers():
|
|
241
|
-
stream_handler = logging.StreamHandler(stream=sys.stdout)
|
|
242
|
-
# Save console handler
|
|
243
|
-
self.logger._console = stream_handler
|
|
244
|
-
self.logger.addHandler(stream_handler)
|
|
245
|
-
|
|
246
|
-
self.logger._support_color = SCColorLoggerFormatter.supports_color(stream_handler)
|
|
247
|
-
|
|
248
|
-
self._init_logger_formats(loglevel=loglevel)
|
|
249
|
-
|
|
250
|
-
def _init_logger_formats(self, loglevel=None):
|
|
251
|
-
if not loglevel:
|
|
252
|
-
loglevel = self.schema.get('option', 'loglevel',
|
|
253
|
-
step=self.logger._in_step, index=self.logger._in_index)
|
|
254
|
-
|
|
255
|
-
if loglevel == 'quiet':
|
|
256
|
-
base_format = SCBlankLoggerFormatter()
|
|
257
|
-
elif self.logger._in_run:
|
|
258
|
-
if loglevel == 'debug':
|
|
259
|
-
base_format = SCDebugInRunLoggerFormatter(
|
|
260
|
-
self,
|
|
261
|
-
self.get('option', 'jobname'),
|
|
262
|
-
self.logger._in_step, self.logger._in_index)
|
|
263
|
-
else:
|
|
264
|
-
base_format = SCInRunLoggerFormatter(
|
|
265
|
-
self,
|
|
266
|
-
self.get('option', 'jobname'),
|
|
267
|
-
self.logger._in_step, self.logger._in_index)
|
|
268
|
-
else:
|
|
269
|
-
if loglevel == 'debug':
|
|
270
|
-
base_format = SCDebugLoggerFormatter()
|
|
271
|
-
else:
|
|
272
|
-
base_format = SCLoggerFormatter()
|
|
273
|
-
|
|
274
|
-
for handler in self.logger.handlers.copy():
|
|
275
|
-
if handler == self.logger._console and self.logger._support_color:
|
|
276
|
-
formatter = SCColorLoggerFormatter(base_format)
|
|
277
|
-
else:
|
|
278
|
-
formatter = base_format
|
|
279
|
-
handler.setFormatter(formatter)
|
|
212
|
+
self.logger.setLevel(logging.INFO)
|
|
280
213
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
#
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
# open() via the 'errors' kwarg.
|
|
287
|
-
|
|
288
|
-
# Warning message/behavior for invalid characters while running tool
|
|
289
|
-
def display_error_handler(e):
|
|
290
|
-
self.logger.warning('Invalid character in tool output, displaying as �')
|
|
291
|
-
return codecs.replace_errors(e)
|
|
292
|
-
codecs.register_error('replace_with_warning', display_error_handler)
|
|
293
|
-
|
|
294
|
-
# Warning message/behavior for invalid characters while processing log
|
|
295
|
-
def log_error_handler(e):
|
|
296
|
-
self.logger.warning('Ignoring invalid character found while reading log')
|
|
297
|
-
return codecs.ignore_errors(e)
|
|
298
|
-
codecs.register_error('ignore_with_warning', log_error_handler)
|
|
214
|
+
stream_handler = logging.StreamHandler(stream=sys.stdout)
|
|
215
|
+
stream_handler.setFormatter(SCLoggerFormatter())
|
|
216
|
+
# Save console handler
|
|
217
|
+
self._logger_console = stream_handler
|
|
218
|
+
self.logger.addHandler(stream_handler)
|
|
299
219
|
|
|
300
220
|
###########################################################################
|
|
301
221
|
def create_cmdline(self,
|
|
@@ -1102,7 +1022,8 @@ class Chip:
|
|
|
1102
1022
|
'''
|
|
1103
1023
|
|
|
1104
1024
|
if package:
|
|
1105
|
-
|
|
1025
|
+
resolvers = self.get("package", field="schema").get_resolvers()
|
|
1026
|
+
filename = os.path.join(resolvers[package](), filename)
|
|
1106
1027
|
|
|
1107
1028
|
if not os.path.isfile(filename):
|
|
1108
1029
|
raise FileNotFoundError(filename)
|
|
@@ -1110,10 +1031,16 @@ class Chip:
|
|
|
1110
1031
|
package_name = f'flist-{os.path.basename(filename)}'
|
|
1111
1032
|
package_dir = os.path.dirname(os.path.abspath(filename))
|
|
1112
1033
|
|
|
1113
|
-
env_vars = utils.get_env_vars(self, None, None)
|
|
1114
|
-
|
|
1115
1034
|
def __make_path(rel, path):
|
|
1116
|
-
|
|
1035
|
+
env_save = os.environ.copy()
|
|
1036
|
+
schema_env = {}
|
|
1037
|
+
for env in self.getkeys('option', 'env'):
|
|
1038
|
+
schema_env[env] = self.get('option', 'env', env)
|
|
1039
|
+
os.environ.update(schema_env)
|
|
1040
|
+
path = os.path.expandvars(path)
|
|
1041
|
+
path = os.path.expanduser(path)
|
|
1042
|
+
os.environ.clear()
|
|
1043
|
+
os.environ.update(env_save)
|
|
1117
1044
|
if os.path.isabs(path):
|
|
1118
1045
|
if path.startswith(rel):
|
|
1119
1046
|
return os.path.relpath(path, rel), package_name
|
|
@@ -1380,18 +1307,17 @@ class Chip:
|
|
|
1380
1307
|
else:
|
|
1381
1308
|
search_paths = [self.cwd]
|
|
1382
1309
|
|
|
1383
|
-
|
|
1310
|
+
resolvers = self.get("package", field="schema").get_resolvers()
|
|
1384
1311
|
for (dependency, path) in zip(dependencies, paths):
|
|
1385
1312
|
faux_param = FileNodeValue()
|
|
1386
1313
|
faux_param.set(path)
|
|
1387
1314
|
try:
|
|
1388
1315
|
if dependency:
|
|
1389
1316
|
faux_param.set(dependency, field='package')
|
|
1390
|
-
faux_search = [
|
|
1317
|
+
faux_search = [resolvers[dependency]()]
|
|
1391
1318
|
else:
|
|
1392
1319
|
faux_search = search_paths
|
|
1393
1320
|
resolved = faux_param.resolve_path(
|
|
1394
|
-
envvars=env_vars,
|
|
1395
1321
|
search=faux_search,
|
|
1396
1322
|
collection_dir=collection_dir)
|
|
1397
1323
|
except FileNotFoundError:
|
|
@@ -1547,39 +1473,19 @@ class Chip:
|
|
|
1547
1473
|
True if all file paths are valid, otherwise False.
|
|
1548
1474
|
'''
|
|
1549
1475
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
is_file = 'file' in paramtype
|
|
1555
|
-
is_dir = 'dir' in paramtype
|
|
1556
|
-
is_list = paramtype.startswith('[')
|
|
1557
|
-
|
|
1558
|
-
if is_file or is_dir:
|
|
1559
|
-
if keypath[-2:] == ('option', 'builddir'):
|
|
1560
|
-
# Skip ['option', 'builddir'] since it will get created by run() if it doesn't
|
|
1561
|
-
# exist
|
|
1562
|
-
continue
|
|
1563
|
-
|
|
1564
|
-
for check_files, step, index in self.schema.get(*keypath, field=None).getvalues():
|
|
1565
|
-
if not check_files:
|
|
1566
|
-
continue
|
|
1476
|
+
ignore_keys = []
|
|
1477
|
+
for keypath in self.allkeys():
|
|
1478
|
+
if keypath[-2:] == ('option', 'builddir'):
|
|
1479
|
+
ignore_keys.append(keypath)
|
|
1567
1480
|
|
|
1568
|
-
|
|
1569
|
-
check_files = [check_files]
|
|
1570
|
-
|
|
1571
|
-
for idx, check_file in enumerate(check_files):
|
|
1572
|
-
found_file = self.__find_files(*keypath,
|
|
1573
|
-
missing_ok=True,
|
|
1574
|
-
step=step, index=index,
|
|
1575
|
-
list_index=idx)
|
|
1576
|
-
if is_list:
|
|
1577
|
-
found_file = found_file[0]
|
|
1578
|
-
if not found_file:
|
|
1579
|
-
self.logger.error(f"Parameter {keypath} path {check_file} is invalid")
|
|
1580
|
-
error = True
|
|
1481
|
+
package_map = self.get("package", field="schema").get_resolvers()
|
|
1581
1482
|
|
|
1582
|
-
return
|
|
1483
|
+
return self.schema.check_filepaths(
|
|
1484
|
+
ignore_keys=ignore_keys,
|
|
1485
|
+
logger=self.logger,
|
|
1486
|
+
packages=package_map,
|
|
1487
|
+
collection_dir=self._getcollectdir(),
|
|
1488
|
+
cwd=self.cwd)
|
|
1583
1489
|
|
|
1584
1490
|
###########################################################################
|
|
1585
1491
|
def check_manifest(self):
|
|
@@ -1646,7 +1552,7 @@ class Chip:
|
|
|
1646
1552
|
NodeStatus.SUCCESS:
|
|
1647
1553
|
# this task has already completed successfully, OK
|
|
1648
1554
|
continue
|
|
1649
|
-
self.logger.error(f'{step}{index} relies on {in_step}{in_index}, '
|
|
1555
|
+
self.logger.error(f'{step}/{index} relies on {in_step}/{in_index}, '
|
|
1650
1556
|
'but this task has not been run and is not in the '
|
|
1651
1557
|
'current nodes to execute.')
|
|
1652
1558
|
error = True
|
|
@@ -1691,12 +1597,12 @@ class Chip:
|
|
|
1691
1597
|
if not self._get_tool_module(step, index, flow=flow, error=False):
|
|
1692
1598
|
error = True
|
|
1693
1599
|
self.logger.error(f"Tool module {tool_name} could not be found or "
|
|
1694
|
-
f"loaded for {step}{index}.")
|
|
1600
|
+
f"loaded for {step}/{index}.")
|
|
1695
1601
|
if not self._get_task_module(step, index, flow=flow, error=False):
|
|
1696
1602
|
error = True
|
|
1697
1603
|
task_module = self.get('flowgraph', flow, step, index, 'taskmodule')
|
|
1698
1604
|
self.logger.error(f"Task module {task_module} for {tool_name}/{task_name} "
|
|
1699
|
-
f"could not be found or loaded for {step}{index}.")
|
|
1605
|
+
f"could not be found or loaded for {step}/{index}.")
|
|
1700
1606
|
|
|
1701
1607
|
# 5. Check per tool parameter requirements (when tool exists)
|
|
1702
1608
|
for (step, index) in nodes:
|
|
@@ -1796,10 +1702,7 @@ class Chip:
|
|
|
1796
1702
|
schema.write_manifest(filepath)
|
|
1797
1703
|
return
|
|
1798
1704
|
|
|
1799
|
-
tcl_record =
|
|
1800
|
-
if isinstance(schema, JournalingSchema):
|
|
1801
|
-
tcl_record = "get" in schema.get_journaling_types()
|
|
1802
|
-
schema = schema.get_base_schema()
|
|
1705
|
+
tcl_record = "get" in Journal.access(schema).get_types()
|
|
1803
1706
|
|
|
1804
1707
|
is_csv = re.search(r'(\.csv)(\.gz)*$', filepath)
|
|
1805
1708
|
|
|
@@ -1929,156 +1832,13 @@ class Chip:
|
|
|
1929
1832
|
>>> status = chip.check_checklist('iso9000', 'd000')
|
|
1930
1833
|
Returns status.
|
|
1931
1834
|
'''
|
|
1932
|
-
error = False
|
|
1933
|
-
|
|
1934
|
-
self.logger.info(f'Checking checklist {standard}')
|
|
1935
|
-
|
|
1936
1835
|
if standard not in self.getkeys('checklist'):
|
|
1937
1836
|
self.logger.error(f'{standard} has not been loaded.')
|
|
1938
1837
|
return False
|
|
1939
1838
|
|
|
1940
|
-
|
|
1941
|
-
items =
|
|
1942
|
-
|
|
1943
|
-
# these tasks are recorded by SC so there are no reports
|
|
1944
|
-
metrics_without_reports = (
|
|
1945
|
-
'tasktime',
|
|
1946
|
-
'totaltime',
|
|
1947
|
-
'exetime',
|
|
1948
|
-
'memory')
|
|
1949
|
-
|
|
1950
|
-
for item in items:
|
|
1951
|
-
if item not in self.getkeys('checklist', standard):
|
|
1952
|
-
self.logger.error(f'{item} is not a check in {standard}.')
|
|
1953
|
-
error = True
|
|
1954
|
-
continue
|
|
1955
|
-
|
|
1956
|
-
allow_missing_reports = True
|
|
1957
|
-
|
|
1958
|
-
has_check = False
|
|
1959
|
-
|
|
1960
|
-
all_criteria = self.get('checklist', standard, item, 'criteria')
|
|
1961
|
-
for criteria in all_criteria:
|
|
1962
|
-
m = re.match(r'^(\w+)\s*([\>\=\<]+)\s*([+\-]?\d+(\.\d+)?(e[+\-]?\d+)?)$',
|
|
1963
|
-
criteria.strip())
|
|
1964
|
-
if not m:
|
|
1965
|
-
self.error(f"Illegal checklist criteria: {criteria}")
|
|
1966
|
-
return False
|
|
1967
|
-
elif m.group(1) not in self.getkeys('metric'):
|
|
1968
|
-
self.error(f"Criteria must use legal metrics only: {criteria}")
|
|
1969
|
-
return False
|
|
1970
|
-
|
|
1971
|
-
metric = m.group(1)
|
|
1972
|
-
op = m.group(2)
|
|
1973
|
-
if self.get('metric', metric, field='type') == 'int':
|
|
1974
|
-
goal = int(m.group(3))
|
|
1975
|
-
number_format = 'd'
|
|
1976
|
-
else:
|
|
1977
|
-
goal = float(m.group(3))
|
|
1978
|
-
|
|
1979
|
-
if goal == 0.0 or (abs(goal) > 1e-3 and abs(goal) < 1e5):
|
|
1980
|
-
number_format = '.3f'
|
|
1981
|
-
else:
|
|
1982
|
-
number_format = '.3e'
|
|
1983
|
-
|
|
1984
|
-
if metric not in metrics_without_reports:
|
|
1985
|
-
allow_missing_reports = False
|
|
1986
|
-
|
|
1987
|
-
tasks = self.get('checklist', standard, item, 'task')
|
|
1988
|
-
for job, step, index in tasks:
|
|
1989
|
-
if job not in self.getkeys('history'):
|
|
1990
|
-
self.error(f'{job} not found in history')
|
|
1991
|
-
|
|
1992
|
-
flow = self.get('option', 'flow', job=job)
|
|
1993
|
-
|
|
1994
|
-
if step not in self.getkeys('flowgraph', flow, job=job):
|
|
1995
|
-
self.error(f'{step} not found in flowgraph')
|
|
1996
|
-
|
|
1997
|
-
if index not in self.getkeys('flowgraph', flow, step, job=job):
|
|
1998
|
-
self.error(f'{step}{index} not found in flowgraph')
|
|
1999
|
-
|
|
2000
|
-
if self.get('record', 'status', step=step, index=index, job=job) == \
|
|
2001
|
-
NodeStatus.SKIPPED:
|
|
2002
|
-
if verbose:
|
|
2003
|
-
self.logger.warning(f'{step}{index} was skipped')
|
|
2004
|
-
continue
|
|
2005
|
-
|
|
2006
|
-
has_check = True
|
|
2007
|
-
|
|
2008
|
-
# Automated checks
|
|
2009
|
-
flow = self.get('option', 'flow', job=job)
|
|
2010
|
-
tool = self.get('flowgraph', flow, step, index, 'tool', job=job)
|
|
2011
|
-
task = self.get('flowgraph', flow, step, index, 'task', job=job)
|
|
2012
|
-
|
|
2013
|
-
value = self.get('metric', metric, job=job, step=step, index=index)
|
|
2014
|
-
criteria_ok = utils.safecompare(self, value, op, goal)
|
|
2015
|
-
if metric in self.getkeys('checklist', standard, item, 'waiver'):
|
|
2016
|
-
waivers = self.get('checklist', standard, item, 'waiver', metric)
|
|
2017
|
-
else:
|
|
2018
|
-
waivers = []
|
|
2019
|
-
|
|
2020
|
-
criteria_str = f'{metric}{op}{goal:{number_format}}'
|
|
2021
|
-
compare_str = f'{value:{number_format}}{op}{goal:{number_format}}'
|
|
2022
|
-
step_desc = f'job {job} with step {step}{index} and task {tool}/{task}'
|
|
2023
|
-
if not criteria_ok and waivers:
|
|
2024
|
-
self.logger.warning(f'{item} criteria {criteria_str} ({compare_str}) unmet '
|
|
2025
|
-
f'by {step_desc}, but found waivers.')
|
|
2026
|
-
elif not criteria_ok:
|
|
2027
|
-
self.logger.error(f'{item} criteria {criteria_str} ({compare_str}) unmet '
|
|
2028
|
-
f'by {step_desc}.')
|
|
2029
|
-
error = True
|
|
2030
|
-
elif verbose and criteria_ok:
|
|
2031
|
-
self.logger.info(f'{item} criteria {criteria_str} met by {step_desc}.')
|
|
2032
|
-
|
|
2033
|
-
has_reports = \
|
|
2034
|
-
self.valid('tool', tool, 'task', task, 'report', metric, job=job) and \
|
|
2035
|
-
self.get('tool', tool, 'task', task, 'report', metric, job=job,
|
|
2036
|
-
step=step, index=index)
|
|
2037
|
-
|
|
2038
|
-
if allow_missing_reports and not has_reports:
|
|
2039
|
-
# No reports available and it is allowed
|
|
2040
|
-
continue
|
|
2041
|
-
|
|
2042
|
-
reports = []
|
|
2043
|
-
try:
|
|
2044
|
-
if has_reports:
|
|
2045
|
-
reports = self.find_files('tool', tool, 'task', task, 'report', metric,
|
|
2046
|
-
job=job,
|
|
2047
|
-
step=step, index=index,
|
|
2048
|
-
missing_ok=not require_reports)
|
|
2049
|
-
except SiliconCompilerError:
|
|
2050
|
-
reports = []
|
|
2051
|
-
continue
|
|
2052
|
-
|
|
2053
|
-
if require_reports and not reports:
|
|
2054
|
-
self.logger.error(f'No EDA reports generated for metric {metric} in '
|
|
2055
|
-
f'{step_desc}')
|
|
2056
|
-
error = True
|
|
2057
|
-
|
|
2058
|
-
for report in reports:
|
|
2059
|
-
if not report:
|
|
2060
|
-
continue
|
|
2061
|
-
|
|
2062
|
-
report = os.path.relpath(report, self.cwd)
|
|
2063
|
-
if report not in self.get('checklist', standard, item, 'report'):
|
|
2064
|
-
self.add('checklist', standard, item, 'report', report)
|
|
2065
|
-
|
|
2066
|
-
if has_check:
|
|
2067
|
-
if require_reports and \
|
|
2068
|
-
not allow_missing_reports and \
|
|
2069
|
-
not self.get('checklist', standard, item, 'report'):
|
|
2070
|
-
# TODO: validate that report exists?
|
|
2071
|
-
self.logger.error(f'No report documenting item {item}')
|
|
2072
|
-
error = True
|
|
2073
|
-
|
|
2074
|
-
if check_ok and not self.get('checklist', standard, item, 'ok'):
|
|
2075
|
-
self.logger.error(f"Item {item} 'ok' field not checked")
|
|
2076
|
-
error = True
|
|
2077
|
-
|
|
2078
|
-
if not error:
|
|
2079
|
-
self.logger.info('Check succeeded!')
|
|
2080
|
-
|
|
2081
|
-
return not error
|
|
1839
|
+
return self.get("checklist", standard, field="schema").check(
|
|
1840
|
+
items=items, check_ok=check_ok, require_reports=require_reports
|
|
1841
|
+
)
|
|
2082
1842
|
|
|
2083
1843
|
###########################################################################
|
|
2084
1844
|
def __import_library(self, libname, library, job=None, clobber=True, keep_input=True):
|
|
@@ -2691,7 +2451,7 @@ class Chip:
|
|
|
2691
2451
|
###########################################################################
|
|
2692
2452
|
def _archive_node(self, tar, step, index, include=None, verbose=True):
|
|
2693
2453
|
if verbose:
|
|
2694
|
-
self.logger.info(f'Archiving {step}{index}...')
|
|
2454
|
+
self.logger.info(f'Archiving {step}/{index}...')
|
|
2695
2455
|
|
|
2696
2456
|
basedir = self.getworkdir(step=step, index=index)
|
|
2697
2457
|
|
|
@@ -2700,7 +2460,7 @@ class Chip:
|
|
|
2700
2460
|
|
|
2701
2461
|
if not os.path.isdir(basedir):
|
|
2702
2462
|
if self.get('record', 'status', step=step, index=index) != NodeStatus.SKIPPED:
|
|
2703
|
-
self.logger.error(f'Unable to archive {step}{index} due to missing node directory')
|
|
2463
|
+
self.logger.error(f'Unable to archive {step}/{index} due to missing node directory')
|
|
2704
2464
|
return
|
|
2705
2465
|
|
|
2706
2466
|
if include:
|
|
@@ -2774,7 +2534,7 @@ class Chip:
|
|
|
2774
2534
|
|
|
2775
2535
|
if not archive_name:
|
|
2776
2536
|
if step and index:
|
|
2777
|
-
archive_name = f"{design}_{jobname}_{step}{index}.tgz"
|
|
2537
|
+
archive_name = f"{design}_{jobname}_{step}_{index}.tgz"
|
|
2778
2538
|
elif step:
|
|
2779
2539
|
archive_name = f"{design}_{jobname}_{step}.tgz"
|
|
2780
2540
|
else:
|
|
@@ -3201,9 +2961,14 @@ class Chip:
|
|
|
3201
2961
|
>>> run()
|
|
3202
2962
|
Runs the execution flow defined by the flowgraph dictionary.
|
|
3203
2963
|
'''
|
|
2964
|
+
from siliconcompiler.remote.client import ClientScheduler
|
|
3204
2965
|
|
|
3205
2966
|
try:
|
|
3206
|
-
|
|
2967
|
+
if self.get('option', 'remote'):
|
|
2968
|
+
scheduler = ClientScheduler(self)
|
|
2969
|
+
else:
|
|
2970
|
+
scheduler = Scheduler(self)
|
|
2971
|
+
scheduler.run()
|
|
3207
2972
|
except Exception as e:
|
|
3208
2973
|
if raise_exception:
|
|
3209
2974
|
raise e
|
|
@@ -3335,7 +3100,7 @@ class Chip:
|
|
|
3335
3100
|
self.unset('option', 'prune')
|
|
3336
3101
|
self.unset('option', 'from')
|
|
3337
3102
|
# build new job name
|
|
3338
|
-
self.set('option', 'jobname', f'_{taskname}_{sc_job}_{sc_step}{sc_index}', clobber=True)
|
|
3103
|
+
self.set('option', 'jobname', f'_{taskname}_{sc_job}_{sc_step}_{sc_index}', clobber=True)
|
|
3339
3104
|
|
|
3340
3105
|
# Setup in step/index variables
|
|
3341
3106
|
for step, index in self.get("flowgraph", "showflow", field="schema").get_nodes():
|
|
@@ -3464,6 +3229,7 @@ class Chip:
|
|
|
3464
3229
|
# We have to remove the chip's logger before serializing the object
|
|
3465
3230
|
# since the logger object is not serializable.
|
|
3466
3231
|
del attributes['logger']
|
|
3232
|
+
del attributes['_logger_console']
|
|
3467
3233
|
return attributes
|
|
3468
3234
|
|
|
3469
3235
|
#######################################
|
|
@@ -3471,4 +3237,7 @@ class Chip:
|
|
|
3471
3237
|
self.__dict__ = state
|
|
3472
3238
|
|
|
3473
3239
|
# Reinitialize logger on restore
|
|
3474
|
-
self.
|
|
3240
|
+
self.__init_logger()
|
|
3241
|
+
|
|
3242
|
+
def copy(self):
|
|
3243
|
+
return copy.deepcopy(self)
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
</head>
|
|
10
10
|
|
|
11
11
|
<body>
|
|
12
|
-
<h2>Node Summary: "{{ step }}{{ index }}"</h2>
|
|
12
|
+
<h2>Node Summary: "{{ step }}/{{ index }}"</h2>
|
|
13
13
|
<span>
|
|
14
14
|
<p><b>Design</b>: {{ design }}</p>
|
|
15
15
|
<p><b>Job</b>: {{ job }}</p>
|
|
16
|
-
<p><b>Node</b>: {{ step }}{{ index }}</p>
|
|
16
|
+
<p><b>Node</b>: {{ step }}/{{ index }}</p>
|
|
17
17
|
<p><b>Status</b>: {{ status }}</p>
|
|
18
18
|
</span>
|
|
19
19
|
<span>
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
<th>Metrics</th>
|
|
37
37
|
<th>units</th>
|
|
38
38
|
{% for step, index in nodes %}
|
|
39
|
-
<th align="center">{{ step }}{{ index }}</th>
|
|
39
|
+
<th align="center">{{ step }}/{{ index }}</th>
|
|
40
40
|
{% endfor %}
|
|
41
41
|
</tr>
|
|
42
42
|
{% for metric in metric_keys %}
|
|
@@ -13,7 +13,7 @@ Schema: {{ version['schema'] }}
|
|
|
13
13
|
Testcase built: {{ date }}
|
|
14
14
|
Tool: {{ run['tool'] }} {% if run['toolversion'] %}{{ run['toolversion'] }}{% endif %}
|
|
15
15
|
Task: {{ run['task'] }}
|
|
16
|
-
Node: {{ run['step'] }}{{ run['index'] }}
|
|
16
|
+
Node: {{ run['step'] }}/{{ run['index'] }}
|
|
17
17
|
|
|
18
18
|
** Python **
|
|
19
19
|
Version: {{ python['version'] }}
|
|
@@ -271,12 +271,12 @@
|
|
|
271
271
|
{% for metric in metric_keys %}
|
|
272
272
|
{% for step, index in nodes %}
|
|
273
273
|
{% if reports[step, index][metric] %}
|
|
274
|
-
var sim_log_btn = document.getElementById("{{ step }}{{ index }}_{{ metric }}_metlink");
|
|
274
|
+
var sim_log_btn = document.getElementById("{{ step }}_{{ index }}_{{ metric }}_metlink");
|
|
275
275
|
sim_log_btn.addEventListener('click', () => {
|
|
276
276
|
log_link = "{{ step }}/{{ index }}/{{ reports[step, index][metric][0] }}";
|
|
277
277
|
window.open(log_link, "_blank");
|
|
278
278
|
});
|
|
279
|
-
var sim_log_btn = document.getElementById("{{ step }}{{ index }}_{{ metric }}_ddmetlink");
|
|
279
|
+
var sim_log_btn = document.getElementById("{{ step }}_{{ index }}_{{ metric }}_ddmetlink");
|
|
280
280
|
sim_log_btn.addEventListener('click', () => {
|
|
281
281
|
log_link = "{{ step }}/{{ index }}/{{ reports[step, index][metric][0] }}";
|
|
282
282
|
window.open(log_link, "_blank");
|
|
@@ -333,7 +333,7 @@
|
|
|
333
333
|
<th>-</th>
|
|
334
334
|
<th>units</th>
|
|
335
335
|
{% for step, index in nodes %}
|
|
336
|
-
<th>{{ step }}{{ index }}</th>
|
|
336
|
+
<th>{{ step }}/{{ index }}</th>
|
|
337
337
|
{% endfor %}
|
|
338
338
|
</tr>
|
|
339
339
|
{% for metric in metric_keys %}
|
|
@@ -372,12 +372,12 @@
|
|
|
372
372
|
<h2>Metrics for {{ design }} Tasks</h2>
|
|
373
373
|
{% for step, index in nodes %}
|
|
374
374
|
<div>
|
|
375
|
-
<a class="btn btn-success" data-bs-toggle="collapse" href="#{{ step }}{{ index }}_dropdown_div", role="button", aria-controls="{{ step }}{{ index }}_dropdown_div">
|
|
376
|
-
Toggle {{ step }}{{ index }} Metrics
|
|
375
|
+
<a class="btn btn-success" data-bs-toggle="collapse" href="#{{ step }}_{{ index }}_dropdown_div", role="button", aria-controls="{{ step }}_{{ index }}_dropdown_div">
|
|
376
|
+
Toggle {{ step }}/{{ index }} Metrics
|
|
377
377
|
</a>
|
|
378
378
|
</div>
|
|
379
|
-
<div id="{{ step }}{{ index }}_dropdown_div" class="collapse">
|
|
380
|
-
<table id="{{ step }}{{ index }}_metrics_table" class="table table-dark table-striped table-bordered">
|
|
379
|
+
<div id="{{ step }}_{{ index }}_dropdown_div" class="collapse">
|
|
380
|
+
<table id="{{ step }}_{{ index }}_metrics_table" class="table table-dark table-striped table-bordered">
|
|
381
381
|
<tr>
|
|
382
382
|
{% for metric in metric_keys %}
|
|
383
383
|
<th>{{ metric }}</th>
|