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.
Files changed (104) hide show
  1. siliconcompiler/__init__.py +2 -0
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/_common.py +1 -1
  4. siliconcompiler/apps/sc.py +1 -1
  5. siliconcompiler/apps/sc_issue.py +6 -4
  6. siliconcompiler/apps/sc_remote.py +3 -20
  7. siliconcompiler/apps/sc_show.py +2 -2
  8. siliconcompiler/apps/utils/replay.py +4 -4
  9. siliconcompiler/checklist.py +202 -1
  10. siliconcompiler/core.py +62 -293
  11. siliconcompiler/data/templates/email/general.j2 +3 -3
  12. siliconcompiler/data/templates/email/summary.j2 +1 -1
  13. siliconcompiler/data/templates/issue/README.txt +1 -1
  14. siliconcompiler/data/templates/report/sc_report.j2 +7 -7
  15. siliconcompiler/dependencyschema.py +392 -0
  16. siliconcompiler/design.py +758 -0
  17. siliconcompiler/flowgraph.py +79 -13
  18. siliconcompiler/optimizer/vizier.py +2 -2
  19. siliconcompiler/package/__init__.py +383 -223
  20. siliconcompiler/package/git.py +75 -77
  21. siliconcompiler/package/github.py +70 -97
  22. siliconcompiler/package/https.py +77 -93
  23. siliconcompiler/packageschema.py +260 -0
  24. siliconcompiler/pdk.py +5 -5
  25. siliconcompiler/remote/client.py +33 -15
  26. siliconcompiler/remote/server.py +2 -2
  27. siliconcompiler/report/dashboard/cli/__init__.py +6 -6
  28. siliconcompiler/report/dashboard/cli/board.py +4 -4
  29. siliconcompiler/report/dashboard/web/components/__init__.py +5 -5
  30. siliconcompiler/report/dashboard/web/components/flowgraph.py +4 -4
  31. siliconcompiler/report/dashboard/web/components/graph.py +2 -2
  32. siliconcompiler/report/dashboard/web/state.py +1 -1
  33. siliconcompiler/report/dashboard/web/utils/__init__.py +5 -5
  34. siliconcompiler/report/html_report.py +1 -1
  35. siliconcompiler/report/report.py +4 -4
  36. siliconcompiler/report/summary_table.py +2 -2
  37. siliconcompiler/report/utils.py +5 -5
  38. siliconcompiler/scheduler/__init__.py +3 -1382
  39. siliconcompiler/scheduler/docker.py +263 -0
  40. siliconcompiler/scheduler/run_node.py +10 -21
  41. siliconcompiler/scheduler/scheduler.py +311 -0
  42. siliconcompiler/scheduler/schedulernode.py +944 -0
  43. siliconcompiler/scheduler/send_messages.py +3 -3
  44. siliconcompiler/scheduler/slurm.py +149 -163
  45. siliconcompiler/scheduler/taskscheduler.py +45 -57
  46. siliconcompiler/schema/__init__.py +3 -3
  47. siliconcompiler/schema/baseschema.py +234 -11
  48. siliconcompiler/schema/editableschema.py +4 -0
  49. siliconcompiler/schema/journal.py +210 -0
  50. siliconcompiler/schema/namedschema.py +55 -2
  51. siliconcompiler/schema/parameter.py +14 -1
  52. siliconcompiler/schema/parametervalue.py +1 -34
  53. siliconcompiler/schema/schema_cfg.py +210 -349
  54. siliconcompiler/tool.py +412 -148
  55. siliconcompiler/tools/__init__.py +2 -0
  56. siliconcompiler/tools/builtin/_common.py +5 -5
  57. siliconcompiler/tools/builtin/concatenate.py +7 -7
  58. siliconcompiler/tools/builtin/minimum.py +4 -4
  59. siliconcompiler/tools/builtin/mux.py +4 -4
  60. siliconcompiler/tools/builtin/nop.py +4 -4
  61. siliconcompiler/tools/builtin/verify.py +8 -9
  62. siliconcompiler/tools/execute/exec_input.py +1 -1
  63. siliconcompiler/tools/genfasm/genfasm.py +1 -6
  64. siliconcompiler/tools/openroad/_apr.py +5 -1
  65. siliconcompiler/tools/openroad/antenna_repair.py +1 -1
  66. siliconcompiler/tools/openroad/macro_placement.py +1 -1
  67. siliconcompiler/tools/openroad/power_grid.py +1 -1
  68. siliconcompiler/tools/openroad/scripts/common/procs.tcl +32 -25
  69. siliconcompiler/tools/opensta/timing.py +26 -3
  70. siliconcompiler/tools/slang/__init__.py +2 -2
  71. siliconcompiler/tools/surfer/__init__.py +0 -0
  72. siliconcompiler/tools/surfer/show.py +53 -0
  73. siliconcompiler/tools/surfer/surfer.py +30 -0
  74. siliconcompiler/tools/vpr/route.py +82 -0
  75. siliconcompiler/tools/vpr/vpr.py +23 -6
  76. siliconcompiler/tools/yosys/__init__.py +1 -1
  77. siliconcompiler/tools/yosys/scripts/procs.tcl +143 -0
  78. siliconcompiler/tools/yosys/{sc_synth_asic.tcl → scripts/sc_synth_asic.tcl} +4 -0
  79. siliconcompiler/tools/yosys/{sc_synth_fpga.tcl → scripts/sc_synth_fpga.tcl} +24 -77
  80. siliconcompiler/tools/yosys/syn_fpga.py +14 -0
  81. siliconcompiler/toolscripts/_tools.json +9 -13
  82. siliconcompiler/toolscripts/rhel9/install-vpr.sh +0 -2
  83. siliconcompiler/toolscripts/ubuntu22/install-surfer.sh +33 -0
  84. siliconcompiler/toolscripts/ubuntu24/install-surfer.sh +33 -0
  85. siliconcompiler/utils/__init__.py +4 -24
  86. siliconcompiler/utils/flowgraph.py +29 -28
  87. siliconcompiler/utils/issue.py +23 -29
  88. siliconcompiler/utils/logging.py +37 -7
  89. siliconcompiler/utils/showtools.py +6 -1
  90. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/METADATA +16 -25
  91. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/RECORD +98 -91
  92. siliconcompiler/scheduler/docker_runner.py +0 -254
  93. siliconcompiler/schema/journalingschema.py +0 -242
  94. siliconcompiler/tools/yosys/procs.tcl +0 -71
  95. siliconcompiler/toolscripts/rhel9/install-yosys-parmys.sh +0 -68
  96. siliconcompiler/toolscripts/ubuntu22/install-yosys-parmys.sh +0 -68
  97. siliconcompiler/toolscripts/ubuntu24/install-yosys-parmys.sh +0 -68
  98. /siliconcompiler/tools/yosys/{sc_lec.tcl → scripts/sc_lec.tcl} +0 -0
  99. /siliconcompiler/tools/yosys/{sc_screenshot.tcl → scripts/sc_screenshot.tcl} +0 -0
  100. /siliconcompiler/tools/yosys/{syn_strategies.tcl → scripts/syn_strategies.tcl} +0 -0
  101. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/WHEEL +0 -0
  102. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/entry_points.txt +0 -0
  103. {siliconcompiler-0.33.2.dist-info → siliconcompiler-0.34.1.dist-info}/licenses/LICENSE +0 -0
  104. {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, JournalingSchema, EditableSchema
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, PathNodeValue
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 SCColorLoggerFormatter, \
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 run as sc_runner
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
- # Initialize custom error handling for codecs. This has to be called
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 _init_logger(self, step=None, index=None, in_run=False):
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
- loglevel = 'info'
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
- def _init_codecs(self):
283
- # Custom error handlers used to provide warnings when invalid characters
284
- # are encountered in a file for a given encoding. The names
285
- # 'replace_with_warning' and 'ignore_with_warning' are supplied to
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
- filename = os.path.join(sc_package.path(self, package), filename)
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
- path = PathNodeValue.resolve_env_vars(path, envvars=env_vars)
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
- env_vars = utils.get_env_vars(self, step, index)
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 = [os.path.abspath(os.path.join(sc_package.path(self, dependency)))]
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
- allkeys = self.allkeys()
1551
- error = False
1552
- for keypath in allkeys:
1553
- paramtype = self.get(*keypath, field='type')
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
- if not is_list:
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 not error
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 = False
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
- if items is None:
1941
- items = self.getkeys('checklist', standard)
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
- sc_runner(self)
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._init_logger()
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 %}
@@ -14,7 +14,7 @@
14
14
  <th>-</th>
15
15
  <th>units</th>
16
16
  {% for step, index in nodes %}
17
- <th align="center">{{ step }}{{ index }}</th>
17
+ <th align="center">{{ step }}/{{ index }}</th>
18
18
  {% endfor %}
19
19
  </tr>
20
20
  {% 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>