siliconcompiler 0.35.2__py3-none-any.whl → 0.35.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/_metadata.py +1 -1
- siliconcompiler/apps/sc_issue.py +18 -2
- siliconcompiler/apps/smake.py +106 -100
- siliconcompiler/checklist.py +2 -1
- siliconcompiler/constraints/asic_component.py +49 -11
- siliconcompiler/constraints/asic_floorplan.py +23 -21
- siliconcompiler/constraints/asic_pins.py +55 -17
- siliconcompiler/constraints/asic_timing.py +53 -22
- siliconcompiler/constraints/fpga_timing.py +5 -6
- siliconcompiler/data/templates/replay/replay.sh.j2 +27 -14
- siliconcompiler/flowgraph.py +418 -129
- siliconcompiler/library.py +5 -4
- siliconcompiler/package/__init__.py +17 -6
- siliconcompiler/package/https.py +10 -5
- siliconcompiler/project.py +92 -33
- siliconcompiler/remote/client.py +17 -6
- siliconcompiler/scheduler/docker.py +24 -25
- siliconcompiler/scheduler/scheduler.py +284 -121
- siliconcompiler/scheduler/schedulernode.py +196 -90
- siliconcompiler/scheduler/slurm.py +113 -29
- siliconcompiler/scheduler/taskscheduler.py +0 -7
- siliconcompiler/schema/__init__.py +3 -2
- siliconcompiler/schema/_metadata.py +1 -1
- siliconcompiler/schema/baseschema.py +205 -93
- siliconcompiler/schema/editableschema.py +29 -0
- siliconcompiler/schema/namedschema.py +21 -13
- siliconcompiler/schema/parametervalue.py +14 -2
- siliconcompiler/schema/safeschema.py +18 -7
- siliconcompiler/schema_support/dependencyschema.py +4 -3
- siliconcompiler/schema_support/option.py +82 -1
- siliconcompiler/schema_support/pathschema.py +14 -15
- siliconcompiler/schema_support/record.py +5 -4
- siliconcompiler/targets/asap7_demo.py +4 -1
- siliconcompiler/tool.py +56 -29
- siliconcompiler/tools/builtin/__init__.py +2 -0
- siliconcompiler/tools/builtin/filter.py +8 -1
- siliconcompiler/tools/builtin/importfiles.py +2 -0
- siliconcompiler/tools/klayout/__init__.py +3 -0
- siliconcompiler/tools/klayout/scripts/klayout_convert_drc_db.py +1 -0
- siliconcompiler/tools/klayout/scripts/klayout_export.py +1 -0
- siliconcompiler/tools/klayout/scripts/klayout_operations.py +1 -0
- siliconcompiler/tools/klayout/scripts/klayout_show.py +2 -1
- siliconcompiler/tools/klayout/scripts/klayout_utils.py +3 -4
- siliconcompiler/tools/klayout/show.py +17 -5
- siliconcompiler/tools/openroad/__init__.py +27 -1
- siliconcompiler/tools/openroad/_apr.py +81 -4
- siliconcompiler/tools/openroad/clock_tree_synthesis.py +1 -0
- siliconcompiler/tools/openroad/global_placement.py +1 -0
- siliconcompiler/tools/openroad/init_floorplan.py +116 -7
- siliconcompiler/tools/openroad/power_grid_analysis.py +174 -0
- siliconcompiler/tools/openroad/repair_design.py +1 -0
- siliconcompiler/tools/openroad/repair_timing.py +1 -0
- siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +42 -4
- siliconcompiler/tools/openroad/scripts/apr/sc_irdrop.tcl +146 -0
- siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +4 -6
- siliconcompiler/tools/openroad/scripts/common/procs.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/common/reports.tcl +1 -1
- siliconcompiler/tools/openroad/scripts/rcx/sc_rcx_bench.tcl +2 -4
- siliconcompiler/tools/opensta/__init__.py +1 -1
- siliconcompiler/tools/opensta/scripts/sc_timing.tcl +17 -12
- siliconcompiler/tools/vivado/scripts/sc_bitstream.tcl +11 -0
- siliconcompiler/tools/vivado/scripts/sc_place.tcl +11 -0
- siliconcompiler/tools/vivado/scripts/sc_route.tcl +11 -0
- siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +10 -0
- siliconcompiler/tools/vpr/__init__.py +28 -0
- siliconcompiler/tools/yosys/prepareLib.py +7 -2
- siliconcompiler/tools/yosys/scripts/sc_screenshot.tcl +1 -1
- siliconcompiler/tools/yosys/scripts/sc_synth_asic.tcl +40 -4
- siliconcompiler/tools/yosys/scripts/sc_synth_fpga.tcl +15 -5
- siliconcompiler/tools/yosys/syn_asic.py +62 -2
- siliconcompiler/tools/yosys/syn_fpga.py +8 -0
- siliconcompiler/toolscripts/_tools.json +6 -6
- siliconcompiler/utils/__init__.py +243 -51
- siliconcompiler/utils/curation.py +89 -56
- siliconcompiler/utils/issue.py +6 -1
- siliconcompiler/utils/multiprocessing.py +35 -2
- siliconcompiler/utils/paths.py +21 -0
- siliconcompiler/utils/settings.py +141 -0
- {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/METADATA +5 -4
- {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/RECORD +86 -83
- {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.4.dist-info}/top_level.txt +0 -0
|
@@ -5,15 +5,18 @@ import shutil
|
|
|
5
5
|
import stat
|
|
6
6
|
import subprocess
|
|
7
7
|
import uuid
|
|
8
|
+
import time
|
|
8
9
|
|
|
9
10
|
import os.path
|
|
10
11
|
|
|
11
|
-
from
|
|
12
|
-
|
|
13
|
-
from siliconcompiler
|
|
12
|
+
from typing import List, Union, Final
|
|
13
|
+
|
|
14
|
+
from siliconcompiler import utils, sc_open
|
|
15
|
+
from siliconcompiler.utils.paths import jobdir
|
|
14
16
|
from siliconcompiler.package import RemoteResolver
|
|
15
|
-
from siliconcompiler.flowgraph import RuntimeFlowgraph
|
|
16
17
|
from siliconcompiler.scheduler import SchedulerNode
|
|
18
|
+
from siliconcompiler.utils.logging import SCBlankLoggerFormatter
|
|
19
|
+
from siliconcompiler.utils.multiprocessing import MPManager
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
class SlurmSchedulerNode(SchedulerNode):
|
|
@@ -24,6 +27,10 @@ class SlurmSchedulerNode(SchedulerNode):
|
|
|
24
27
|
It prepares a run script, a manifest, and uses the 'srun' command
|
|
25
28
|
to execute the step on a compute node.
|
|
26
29
|
"""
|
|
30
|
+
__OPTIONS: Final[str] = "scheduler-slurm"
|
|
31
|
+
|
|
32
|
+
_MAX_FS_DELAY = 2
|
|
33
|
+
_FS_DWELL = 0.1
|
|
27
34
|
|
|
28
35
|
def __init__(self, project, step, index, replay=False):
|
|
29
36
|
"""Initializes a SlurmSchedulerNode.
|
|
@@ -52,34 +59,31 @@ class SlurmSchedulerNode(SchedulerNode):
|
|
|
52
59
|
"""
|
|
53
60
|
A static pre-processing hook for the Slurm scheduler.
|
|
54
61
|
|
|
55
|
-
This method
|
|
56
|
-
|
|
57
|
-
into a central location before any remote jobs are submitted. This
|
|
58
|
-
ensures that compute nodes have access to all required source files.
|
|
62
|
+
This method ensures that the Slurm environment is available and loads
|
|
63
|
+
any existing user configuration for the scheduler.
|
|
59
64
|
|
|
60
65
|
Args:
|
|
61
66
|
project (Project): The project object to perform pre-processing on.
|
|
62
67
|
"""
|
|
63
|
-
|
|
64
|
-
# nothing to do
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
do_collect = False
|
|
68
|
-
flow = project.get('option', 'flow')
|
|
69
|
-
entry_nodes = project.get("flowgraph", flow, field="schema").get_entry_nodes()
|
|
68
|
+
SlurmSchedulerNode.assert_slurm()
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
prune_nodes=project.get('option', 'prune'))
|
|
70
|
+
@staticmethod
|
|
71
|
+
def _set_user_config(tag: str, value: Union[List[str], str]) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Sets a specific value in the user configuration map.
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
Args:
|
|
76
|
+
tag (str): The configuration key to update.
|
|
77
|
+
value (Union[List[str], str]): The value to assign to the key.
|
|
78
|
+
"""
|
|
79
|
+
MPManager.get_settings().set(SlurmSchedulerNode.__OPTIONS, tag, value)
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
@staticmethod
|
|
82
|
+
def _write_user_config() -> None:
|
|
83
|
+
"""
|
|
84
|
+
Writes the current system configuration to the user configuration file.
|
|
85
|
+
"""
|
|
86
|
+
MPManager.get_settings().save()
|
|
83
87
|
|
|
84
88
|
@property
|
|
85
89
|
def is_local(self):
|
|
@@ -150,6 +154,49 @@ class SlurmSchedulerNode(SchedulerNode):
|
|
|
150
154
|
# Return the first listed partition
|
|
151
155
|
return sinfo['nodes'][0]['partitions'][0]
|
|
152
156
|
|
|
157
|
+
@staticmethod
|
|
158
|
+
def assert_slurm() -> None:
|
|
159
|
+
"""
|
|
160
|
+
Check if slurm is installed and throw error when not installed.
|
|
161
|
+
"""
|
|
162
|
+
if shutil.which('sinfo') is None:
|
|
163
|
+
raise RuntimeError('slurm is not available or installed on this machine')
|
|
164
|
+
|
|
165
|
+
def mark_copy(self) -> bool:
|
|
166
|
+
sharedprefix: List[str] = MPManager.get_settings().get(
|
|
167
|
+
SlurmSchedulerNode.__OPTIONS, "sharedpaths", default=[])
|
|
168
|
+
|
|
169
|
+
if "/" in sharedprefix:
|
|
170
|
+
# Entire filesystem is shared so no need to check
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
do_collect = False
|
|
174
|
+
for key in self.get_required_path_keys():
|
|
175
|
+
mark_copy = True
|
|
176
|
+
if sharedprefix:
|
|
177
|
+
mark_copy = False
|
|
178
|
+
|
|
179
|
+
check_step, check_index = self.step, self.index
|
|
180
|
+
if self.project.get(*key, field='pernode').is_never():
|
|
181
|
+
check_step, check_index = None, None
|
|
182
|
+
|
|
183
|
+
paths = self.project.find_files(*key, missing_ok=True,
|
|
184
|
+
step=check_step, index=check_index)
|
|
185
|
+
if not isinstance(paths, list):
|
|
186
|
+
paths = [paths]
|
|
187
|
+
paths = [str(path) for path in paths if path]
|
|
188
|
+
|
|
189
|
+
for path in paths:
|
|
190
|
+
if not any([path.startswith(shared) for shared in sharedprefix]):
|
|
191
|
+
# File exists outside shared paths and needs to be copied
|
|
192
|
+
mark_copy = True
|
|
193
|
+
break
|
|
194
|
+
|
|
195
|
+
if mark_copy:
|
|
196
|
+
self.project.set(*key, True, field='copy')
|
|
197
|
+
do_collect = True
|
|
198
|
+
return do_collect
|
|
199
|
+
|
|
153
200
|
def run(self):
|
|
154
201
|
"""
|
|
155
202
|
Runs the node's task as a job on a Slurm cluster.
|
|
@@ -161,9 +208,6 @@ class SlurmSchedulerNode(SchedulerNode):
|
|
|
161
208
|
|
|
162
209
|
self._init_run_logger()
|
|
163
210
|
|
|
164
|
-
if shutil.which('sinfo') is None:
|
|
165
|
-
raise RuntimeError('slurm is not available or installed on this machine')
|
|
166
|
-
|
|
167
211
|
# Determine which cluster parititon to use.
|
|
168
212
|
partition = self.project.get('option', 'scheduler', 'queue',
|
|
169
213
|
step=self.step, index=self.index)
|
|
@@ -191,7 +235,7 @@ class SlurmSchedulerNode(SchedulerNode):
|
|
|
191
235
|
with open(script_file, 'w') as sf:
|
|
192
236
|
sf.write(utils.get_file_template('slurm/run.sh').render(
|
|
193
237
|
cfg_file=shlex.quote(cfg_file),
|
|
194
|
-
build_dir=shlex.quote(self.project.
|
|
238
|
+
build_dir=shlex.quote(self.project.option.get_builddir()),
|
|
195
239
|
step=shlex.quote(self.step),
|
|
196
240
|
index=shlex.quote(self.index),
|
|
197
241
|
cachedir=shlex.quote(str(RemoteResolver.determine_cache_dir(self.project)))
|
|
@@ -217,9 +261,12 @@ class SlurmSchedulerNode(SchedulerNode):
|
|
|
217
261
|
|
|
218
262
|
schedule_cmd.append(script_file)
|
|
219
263
|
|
|
264
|
+
self.logger.debug(f"Executing slurm command: {shlex.join(schedule_cmd)}")
|
|
265
|
+
|
|
220
266
|
# Run the 'srun' command, and track its output.
|
|
221
267
|
# TODO: output should be fed to log, and stdout if quiet = False
|
|
222
268
|
step_result = subprocess.Popen(schedule_cmd,
|
|
269
|
+
stdin=subprocess.DEVNULL,
|
|
223
270
|
stdout=subprocess.PIPE,
|
|
224
271
|
stderr=subprocess.STDOUT)
|
|
225
272
|
|
|
@@ -227,3 +274,40 @@ class SlurmSchedulerNode(SchedulerNode):
|
|
|
227
274
|
# as it has closed its output stream. But if we don't call '.wait()',
|
|
228
275
|
# the '.returncode' value will not be set correctly.
|
|
229
276
|
step_result.wait()
|
|
277
|
+
|
|
278
|
+
# Attempt to list dir to trigger network FS to update
|
|
279
|
+
try:
|
|
280
|
+
os.listdir(os.path.dirname(log_file))
|
|
281
|
+
except: # noqa E722
|
|
282
|
+
pass
|
|
283
|
+
|
|
284
|
+
# Print the log to logger
|
|
285
|
+
if os.path.exists(log_file):
|
|
286
|
+
org_formatter = self.project._logger_console.formatter
|
|
287
|
+
try:
|
|
288
|
+
self.project._logger_console.setFormatter(SCBlankLoggerFormatter())
|
|
289
|
+
with sc_open(log_file) as log:
|
|
290
|
+
for line in log.readlines():
|
|
291
|
+
self.logger.info(line.rstrip())
|
|
292
|
+
finally:
|
|
293
|
+
self.project._logger_console.setFormatter(org_formatter)
|
|
294
|
+
|
|
295
|
+
if step_result.returncode != 0:
|
|
296
|
+
self.logger.error(f"Slurm exited with a non-zero code ({step_result.returncode}).")
|
|
297
|
+
if os.path.exists(log_file):
|
|
298
|
+
self.logger.error(f"Node log file: {log_file}")
|
|
299
|
+
self.halt()
|
|
300
|
+
|
|
301
|
+
# Wait for manifest to propagate through network filesystem
|
|
302
|
+
start = time.time()
|
|
303
|
+
elapsed = 0
|
|
304
|
+
manifest_path = self.get_manifest()
|
|
305
|
+
while not os.path.exists(manifest_path) and elapsed <= SlurmSchedulerNode._MAX_FS_DELAY:
|
|
306
|
+
os.listdir(os.path.dirname(manifest_path))
|
|
307
|
+
elapsed = time.time() - start
|
|
308
|
+
time.sleep(SlurmSchedulerNode._FS_DWELL)
|
|
309
|
+
if not os.path.exists(manifest_path):
|
|
310
|
+
self.logger.error(f"Manifest was not created on time: {manifest_path}")
|
|
311
|
+
|
|
312
|
+
def check_required_paths(self) -> bool:
|
|
313
|
+
return True
|
|
@@ -117,8 +117,6 @@ class TaskScheduler:
|
|
|
117
117
|
from_steps=set([step for step, _ in self.__flow.get_entry_nodes()]),
|
|
118
118
|
prune_nodes=self.__project.option.get_prune())
|
|
119
119
|
|
|
120
|
-
init_funcs = set()
|
|
121
|
-
|
|
122
120
|
for step, index in self.__runtime_flow.get_nodes():
|
|
123
121
|
if self.__record.get('status', step=step, index=index) != NodeStatus.PENDING:
|
|
124
122
|
continue
|
|
@@ -145,7 +143,6 @@ class TaskScheduler:
|
|
|
145
143
|
task["node"].set_queue(pipe, self.__log_queue)
|
|
146
144
|
|
|
147
145
|
task["proc"] = multiprocessing.Process(target=task["node"].run)
|
|
148
|
-
init_funcs.add(task["node"].init)
|
|
149
146
|
self.__nodes[(step, index)] = task
|
|
150
147
|
|
|
151
148
|
# Create ordered list of nodes
|
|
@@ -155,10 +152,6 @@ class TaskScheduler:
|
|
|
155
152
|
if node in self.__nodes:
|
|
156
153
|
self.__ordered_nodes.append(node)
|
|
157
154
|
|
|
158
|
-
# Call preprocessing for schedulers
|
|
159
|
-
for init_func in init_funcs:
|
|
160
|
-
init_func(self.__project)
|
|
161
|
-
|
|
162
155
|
def run(self, job_log_handler: logging.Handler) -> None:
|
|
163
156
|
"""
|
|
164
157
|
The main entry point for the task scheduling loop.
|
|
@@ -4,7 +4,7 @@ from .parameter import Parameter, Scope, PerNode
|
|
|
4
4
|
from .journal import Journal
|
|
5
5
|
from .safeschema import SafeSchema
|
|
6
6
|
from .editableschema import EditableSchema
|
|
7
|
-
from .baseschema import BaseSchema
|
|
7
|
+
from .baseschema import BaseSchema, LazyLoad
|
|
8
8
|
from .namedschema import NamedSchema
|
|
9
9
|
from .docschema import DocsSchema
|
|
10
10
|
|
|
@@ -17,7 +17,8 @@ __all__ = [
|
|
|
17
17
|
"Scope",
|
|
18
18
|
"PerNode",
|
|
19
19
|
"Journal",
|
|
20
|
-
"DocsSchema"
|
|
20
|
+
"DocsSchema",
|
|
21
|
+
"LazyLoad"
|
|
21
22
|
]
|
|
22
23
|
|
|
23
24
|
SCHEMA_VERSION = __version__
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# Version number following semver standard.
|
|
2
|
-
version = '0.52.
|
|
2
|
+
version = '0.52.1'
|