siliconcompiler 0.34.1__py3-none-any.whl → 0.34.3__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 +23 -4
- siliconcompiler/__main__.py +1 -7
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/_common.py +104 -23
- siliconcompiler/apps/sc.py +4 -8
- siliconcompiler/apps/sc_dashboard.py +6 -4
- siliconcompiler/apps/sc_install.py +10 -6
- siliconcompiler/apps/sc_issue.py +7 -5
- siliconcompiler/apps/sc_remote.py +1 -1
- siliconcompiler/apps/sc_server.py +9 -14
- siliconcompiler/apps/sc_show.py +7 -6
- siliconcompiler/apps/smake.py +130 -94
- siliconcompiler/apps/utils/replay.py +4 -7
- siliconcompiler/apps/utils/summarize.py +3 -5
- siliconcompiler/asic.py +420 -0
- siliconcompiler/checklist.py +25 -2
- siliconcompiler/cmdlineschema.py +534 -0
- siliconcompiler/constraints/__init__.py +17 -0
- siliconcompiler/constraints/asic_component.py +378 -0
- siliconcompiler/constraints/asic_floorplan.py +449 -0
- siliconcompiler/constraints/asic_pins.py +489 -0
- siliconcompiler/constraints/asic_timing.py +517 -0
- siliconcompiler/core.py +10 -35
- siliconcompiler/data/templates/tcl/manifest.tcl.j2 +8 -0
- siliconcompiler/dependencyschema.py +96 -202
- siliconcompiler/design.py +327 -241
- siliconcompiler/filesetschema.py +250 -0
- siliconcompiler/flowgraph.py +298 -106
- siliconcompiler/fpga.py +124 -1
- siliconcompiler/library.py +331 -0
- siliconcompiler/metric.py +327 -92
- siliconcompiler/metrics/__init__.py +7 -0
- siliconcompiler/metrics/asic.py +245 -0
- siliconcompiler/metrics/fpga.py +220 -0
- siliconcompiler/package/__init__.py +391 -67
- siliconcompiler/package/git.py +92 -16
- siliconcompiler/package/github.py +114 -22
- siliconcompiler/package/https.py +79 -16
- siliconcompiler/packageschema.py +341 -16
- siliconcompiler/pathschema.py +255 -0
- siliconcompiler/pdk.py +566 -1
- siliconcompiler/project.py +1460 -0
- siliconcompiler/record.py +38 -1
- siliconcompiler/remote/__init__.py +5 -2
- siliconcompiler/remote/client.py +11 -6
- siliconcompiler/remote/schema.py +5 -23
- siliconcompiler/remote/server.py +41 -54
- siliconcompiler/report/__init__.py +3 -3
- siliconcompiler/report/dashboard/__init__.py +48 -14
- siliconcompiler/report/dashboard/cli/__init__.py +99 -21
- siliconcompiler/report/dashboard/cli/board.py +364 -179
- siliconcompiler/report/dashboard/web/__init__.py +90 -12
- siliconcompiler/report/dashboard/web/components/__init__.py +219 -240
- siliconcompiler/report/dashboard/web/components/flowgraph.py +49 -26
- siliconcompiler/report/dashboard/web/components/graph.py +139 -100
- siliconcompiler/report/dashboard/web/layouts/__init__.py +29 -1
- siliconcompiler/report/dashboard/web/layouts/_common.py +38 -2
- siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph.py +39 -26
- siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_node_tab.py +50 -50
- siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_sac_tabs.py +49 -46
- siliconcompiler/report/dashboard/web/state.py +141 -14
- siliconcompiler/report/dashboard/web/utils/__init__.py +79 -16
- siliconcompiler/report/dashboard/web/utils/file_utils.py +74 -11
- siliconcompiler/report/dashboard/web/viewer.py +25 -1
- siliconcompiler/report/report.py +5 -2
- siliconcompiler/report/summary_image.py +29 -11
- siliconcompiler/scheduler/__init__.py +9 -1
- siliconcompiler/scheduler/docker.py +81 -4
- siliconcompiler/scheduler/run_node.py +37 -20
- siliconcompiler/scheduler/scheduler.py +211 -36
- siliconcompiler/scheduler/schedulernode.py +394 -60
- siliconcompiler/scheduler/send_messages.py +77 -29
- siliconcompiler/scheduler/slurm.py +76 -12
- siliconcompiler/scheduler/taskscheduler.py +142 -21
- siliconcompiler/schema/__init__.py +0 -4
- siliconcompiler/schema/baseschema.py +338 -59
- siliconcompiler/schema/editableschema.py +14 -6
- siliconcompiler/schema/journal.py +28 -17
- siliconcompiler/schema/namedschema.py +22 -14
- siliconcompiler/schema/parameter.py +89 -28
- siliconcompiler/schema/parametertype.py +2 -0
- siliconcompiler/schema/parametervalue.py +258 -15
- siliconcompiler/schema/safeschema.py +25 -2
- siliconcompiler/schema/schema_cfg.py +23 -19
- siliconcompiler/schema/utils.py +2 -2
- siliconcompiler/schema_obj.py +24 -5
- siliconcompiler/tool.py +1131 -265
- siliconcompiler/tools/bambu/__init__.py +41 -0
- siliconcompiler/tools/builtin/concatenate.py +2 -2
- siliconcompiler/tools/builtin/minimum.py +2 -1
- siliconcompiler/tools/builtin/mux.py +2 -1
- siliconcompiler/tools/builtin/nop.py +2 -1
- siliconcompiler/tools/builtin/verify.py +2 -1
- siliconcompiler/tools/klayout/__init__.py +95 -0
- siliconcompiler/tools/openroad/__init__.py +289 -0
- siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +3 -0
- siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +7 -2
- siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +8 -4
- siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +9 -5
- siliconcompiler/tools/openroad/scripts/common/write_images.tcl +5 -1
- siliconcompiler/tools/slang/__init__.py +1 -1
- siliconcompiler/tools/slang/elaborate.py +2 -1
- siliconcompiler/tools/vivado/scripts/sc_run.tcl +1 -1
- siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +8 -1
- siliconcompiler/tools/vivado/syn_fpga.py +6 -0
- siliconcompiler/tools/vivado/vivado.py +35 -2
- siliconcompiler/tools/vpr/__init__.py +150 -0
- siliconcompiler/tools/yosys/__init__.py +369 -1
- siliconcompiler/tools/yosys/scripts/procs.tcl +0 -1
- siliconcompiler/toolscripts/_tools.json +5 -10
- siliconcompiler/utils/__init__.py +66 -0
- siliconcompiler/utils/flowgraph.py +2 -2
- siliconcompiler/utils/issue.py +2 -1
- siliconcompiler/utils/logging.py +14 -0
- siliconcompiler/utils/multiprocessing.py +256 -0
- siliconcompiler/utils/showtools.py +10 -0
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/METADATA +6 -6
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/RECORD +122 -115
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/entry_points.txt +3 -0
- siliconcompiler/schema/cmdlineschema.py +0 -250
- siliconcompiler/schema/packageschema.py +0 -101
- siliconcompiler/toolscripts/rhel8/install-slang.sh +0 -40
- siliconcompiler/toolscripts/rhel9/install-slang.sh +0 -40
- siliconcompiler/toolscripts/ubuntu20/install-slang.sh +0 -47
- siliconcompiler/toolscripts/ubuntu22/install-slang.sh +0 -37
- siliconcompiler/toolscripts/ubuntu24/install-slang.sh +0 -37
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.3.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import logging
|
|
1
3
|
import os
|
|
2
4
|
import re
|
|
3
5
|
import shutil
|
|
4
6
|
import sys
|
|
7
|
+
import traceback
|
|
5
8
|
|
|
6
9
|
import os.path
|
|
7
10
|
|
|
@@ -9,19 +12,43 @@ from siliconcompiler import Schema
|
|
|
9
12
|
from siliconcompiler import NodeStatus
|
|
10
13
|
from siliconcompiler.schema import Journal
|
|
11
14
|
from siliconcompiler.flowgraph import RuntimeFlowgraph
|
|
12
|
-
from siliconcompiler.scheduler
|
|
13
|
-
from siliconcompiler.scheduler
|
|
14
|
-
from siliconcompiler.scheduler
|
|
15
|
-
from siliconcompiler.scheduler
|
|
15
|
+
from siliconcompiler.scheduler import SchedulerNode
|
|
16
|
+
from siliconcompiler.scheduler import SlurmSchedulerNode
|
|
17
|
+
from siliconcompiler.scheduler import DockerSchedulerNode
|
|
18
|
+
from siliconcompiler.scheduler import TaskScheduler
|
|
16
19
|
|
|
17
20
|
from siliconcompiler import utils
|
|
21
|
+
from siliconcompiler.utils.logging import SCLoggerFormatter
|
|
22
|
+
from siliconcompiler.utils.multiprocessing import MPManager
|
|
18
23
|
from siliconcompiler.scheduler import send_messages
|
|
19
24
|
|
|
20
25
|
|
|
21
26
|
class Scheduler:
|
|
27
|
+
"""
|
|
28
|
+
A class for orchestrating and executing a compilation flowgraph.
|
|
29
|
+
|
|
30
|
+
The Scheduler is responsible for managing the entire lifecycle of a compilation
|
|
31
|
+
run. It interprets the flowgraph defined in the Chip object, determines which
|
|
32
|
+
nodes (steps) need to be run based on user settings (like 'from', 'to') and
|
|
33
|
+
the state of previous runs, and then executes the tasks in the correct order.
|
|
34
|
+
|
|
35
|
+
It handles setting up individual task nodes, managing dependencies, logging,
|
|
36
|
+
and reporting results.
|
|
37
|
+
"""
|
|
38
|
+
|
|
22
39
|
def __init__(self, chip):
|
|
40
|
+
"""
|
|
41
|
+
Initializes the Scheduler.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
chip (Chip): The Chip object containing the configuration and flowgraph.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
ValueError: If the specified flow is not defined or fails validation.
|
|
48
|
+
"""
|
|
23
49
|
self.__chip = chip
|
|
24
|
-
self.__logger =
|
|
50
|
+
self.__logger: logging.Logger = chip.logger
|
|
51
|
+
self.__name = chip.design
|
|
25
52
|
|
|
26
53
|
flow = self.__chip.get("option", "flow")
|
|
27
54
|
if not flow:
|
|
@@ -36,14 +63,14 @@ class Scheduler:
|
|
|
36
63
|
prune_nodes = self.__chip.get('option', 'prune')
|
|
37
64
|
|
|
38
65
|
if not self.__flow.validate(logger=self.__logger):
|
|
39
|
-
raise ValueError(f"{self.__flow.name
|
|
66
|
+
raise ValueError(f"{self.__flow.name} flowgraph contains errors and cannot be run.")
|
|
40
67
|
if not RuntimeFlowgraph.validate(
|
|
41
68
|
self.__flow,
|
|
42
69
|
from_steps=from_steps,
|
|
43
70
|
to_steps=to_steps,
|
|
44
71
|
prune_nodes=prune_nodes,
|
|
45
72
|
logger=chip.logger):
|
|
46
|
-
raise ValueError(f"{self.__flow.name
|
|
73
|
+
raise ValueError(f"{self.__flow.name} flowgraph contains errors and cannot be run.")
|
|
47
74
|
|
|
48
75
|
self.__flow_runtime = RuntimeFlowgraph(
|
|
49
76
|
self.__flow,
|
|
@@ -51,27 +78,40 @@ class Scheduler:
|
|
|
51
78
|
to_steps=to_steps,
|
|
52
79
|
prune_nodes=self.__chip.get('option', 'prune'))
|
|
53
80
|
|
|
54
|
-
self.__flow_runtime_no_prune = RuntimeFlowgraph(
|
|
55
|
-
self.__flow,
|
|
56
|
-
from_steps=from_steps,
|
|
57
|
-
to_steps=to_steps)
|
|
58
|
-
|
|
59
81
|
self.__flow_load_runtime = RuntimeFlowgraph(
|
|
60
82
|
self.__flow,
|
|
61
83
|
to_steps=from_steps,
|
|
62
84
|
prune_nodes=prune_nodes)
|
|
63
85
|
|
|
64
|
-
self.__flow_something = RuntimeFlowgraph(
|
|
65
|
-
self.__flow,
|
|
66
|
-
from_steps=set([step for step, _ in self.__flow.get_entry_nodes()]),
|
|
67
|
-
prune_nodes=prune_nodes)
|
|
68
|
-
|
|
69
86
|
self.__record = self.__chip.get("record", field="schema")
|
|
70
87
|
self.__metrics = self.__chip.get("metric", field="schema")
|
|
71
88
|
|
|
72
89
|
self.__tasks = {}
|
|
73
90
|
|
|
91
|
+
# Create dummy handler
|
|
92
|
+
self.__joblog_handler = logging.NullHandler()
|
|
93
|
+
self.__org_job_name = self.__chip.get("option", "jobname")
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def project(self):
|
|
97
|
+
"""
|
|
98
|
+
Returns the Project object associated with this scheduler.
|
|
99
|
+
|
|
100
|
+
This property provides access to the central Project object, which holds
|
|
101
|
+
the entire design configuration, flowgraph, and results.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Project: The Project object for the current project.
|
|
105
|
+
"""
|
|
106
|
+
return self.__chip
|
|
107
|
+
|
|
74
108
|
def __print_status(self, header):
|
|
109
|
+
"""
|
|
110
|
+
Private helper to print the current status of all nodes for debugging.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
header (str): A header message to print before the status list.
|
|
114
|
+
"""
|
|
75
115
|
self.__logger.debug(f"#### {header}")
|
|
76
116
|
for step, index in self.__flow.get_nodes():
|
|
77
117
|
self.__logger.debug(f"({step}, {index}) -> "
|
|
@@ -79,17 +119,102 @@ class Scheduler:
|
|
|
79
119
|
self.__logger.debug("####")
|
|
80
120
|
|
|
81
121
|
def check_manifest(self):
|
|
122
|
+
"""
|
|
123
|
+
Checks the validity of the Chip's manifest before a run.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
bool: True if the manifest is valid, False otherwise.
|
|
127
|
+
"""
|
|
82
128
|
self.__logger.info("Checking manifest before running.")
|
|
83
129
|
return self.__chip.check_manifest()
|
|
84
130
|
|
|
85
131
|
def run_core(self):
|
|
132
|
+
"""
|
|
133
|
+
Executes the core task scheduling loop.
|
|
134
|
+
|
|
135
|
+
This method initializes and runs the TaskScheduler, which manages the
|
|
136
|
+
execution of individual nodes based on their dependencies and status.
|
|
137
|
+
"""
|
|
86
138
|
self.__record.record_python_packages()
|
|
87
139
|
|
|
88
140
|
task_scheduler = TaskScheduler(self.__chip, self.__tasks)
|
|
89
|
-
task_scheduler.run()
|
|
141
|
+
task_scheduler.run(self.__joblog_handler)
|
|
90
142
|
task_scheduler.check()
|
|
91
143
|
|
|
144
|
+
def __excepthook(self, exc_type, exc_value, exc_traceback):
|
|
145
|
+
"""
|
|
146
|
+
Custom exception hook to ensure all fatal errors are logged.
|
|
147
|
+
|
|
148
|
+
This captures unhandled exceptions, logs them to the job log file,
|
|
149
|
+
and prints a traceback for debugging before the program terminates.
|
|
150
|
+
"""
|
|
151
|
+
if issubclass(exc_type, KeyboardInterrupt):
|
|
152
|
+
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
|
153
|
+
return
|
|
154
|
+
|
|
155
|
+
# Print a summary of the exception
|
|
156
|
+
except_msg = f"Exception raised: {exc_type.__name__}"
|
|
157
|
+
exc_value = str(exc_value).strip()
|
|
158
|
+
if exc_value:
|
|
159
|
+
except_msg += f" / {exc_value}"
|
|
160
|
+
self.__logger.error(except_msg)
|
|
161
|
+
|
|
162
|
+
trace = io.StringIO()
|
|
163
|
+
|
|
164
|
+
# Print the full traceback for debugging
|
|
165
|
+
self.__logger.error("Traceback (most recent call last):")
|
|
166
|
+
traceback.print_tb(exc_traceback, file=trace)
|
|
167
|
+
for line in trace.getvalue().splitlines():
|
|
168
|
+
self.__logger.error(line)
|
|
169
|
+
|
|
170
|
+
# Ensure dashboard receives a stop if running
|
|
171
|
+
if self.__chip._dash:
|
|
172
|
+
self.__chip._dash.stop()
|
|
173
|
+
|
|
174
|
+
# Mark error to keep logfile
|
|
175
|
+
MPManager.error("uncaught exception")
|
|
176
|
+
|
|
92
177
|
def run(self):
|
|
178
|
+
"""
|
|
179
|
+
The main entry point to start the compilation flow.
|
|
180
|
+
|
|
181
|
+
This method orchestrates the entire run, including:
|
|
182
|
+
- Setting up a custom exception hook for logging.
|
|
183
|
+
- Initializing the job directory and log files.
|
|
184
|
+
- Configuring and setting up all nodes in the flow.
|
|
185
|
+
- Validating the manifest.
|
|
186
|
+
- Executing the core run loop.
|
|
187
|
+
- Recording the final results and history.
|
|
188
|
+
"""
|
|
189
|
+
# Install hook to ensure exception is logged
|
|
190
|
+
org_excepthook = sys.excepthook
|
|
191
|
+
sys.excepthook = self.__excepthook
|
|
192
|
+
|
|
193
|
+
# Determine job name first so we can create a log
|
|
194
|
+
if not self.__increment_job_name():
|
|
195
|
+
# No need to copy, no remove org job name
|
|
196
|
+
self.__org_job_name = None
|
|
197
|
+
|
|
198
|
+
# Clean the directory early if needed
|
|
199
|
+
self.__clean_build_dir()
|
|
200
|
+
|
|
201
|
+
# Install job file logger
|
|
202
|
+
os.makedirs(self.__chip.getworkdir(), exist_ok=True)
|
|
203
|
+
file_log = os.path.join(self.__chip.getworkdir(), "job.log")
|
|
204
|
+
bak_count = 0
|
|
205
|
+
bak_file_log = f"{file_log}.bak"
|
|
206
|
+
while os.path.exists(bak_file_log):
|
|
207
|
+
bak_count += 1
|
|
208
|
+
bak_file_log = f"{file_log}.bak.{bak_count}"
|
|
209
|
+
if os.path.exists(file_log):
|
|
210
|
+
os.rename(file_log, bak_file_log)
|
|
211
|
+
self.__joblog_handler = logging.FileHandler(file_log)
|
|
212
|
+
self.__joblog_handler.setFormatter(SCLoggerFormatter())
|
|
213
|
+
self.__logger.addHandler(self.__joblog_handler)
|
|
214
|
+
|
|
215
|
+
# Configure run
|
|
216
|
+
self.__chip._init_run()
|
|
217
|
+
|
|
93
218
|
self.__run_setup()
|
|
94
219
|
self.configure_nodes()
|
|
95
220
|
|
|
@@ -103,12 +228,29 @@ class Scheduler:
|
|
|
103
228
|
self.__chip.schema.record_history()
|
|
104
229
|
|
|
105
230
|
# Record final manifest
|
|
106
|
-
filepath = os.path.join(self.__chip.getworkdir(), f"{self.
|
|
231
|
+
filepath = os.path.join(self.__chip.getworkdir(), f"{self.__name}.pkg.json")
|
|
107
232
|
self.__chip.write_manifest(filepath)
|
|
108
233
|
|
|
109
234
|
send_messages.send(self.__chip, 'summary', None, None)
|
|
110
235
|
|
|
236
|
+
self.__logger.removeHandler(self.__joblog_handler)
|
|
237
|
+
self.__joblog_handler = logging.NullHandler()
|
|
238
|
+
|
|
239
|
+
# Restore hook
|
|
240
|
+
sys.excepthook = org_excepthook
|
|
241
|
+
|
|
111
242
|
def __mark_pending(self, step, index):
|
|
243
|
+
"""
|
|
244
|
+
Private helper to recursively mark a node and its dependents as PENDING.
|
|
245
|
+
|
|
246
|
+
When a node is determined to need a re-run, this function ensures that
|
|
247
|
+
it and all subsequent nodes in the flowgraph are marked as PENDING,
|
|
248
|
+
effectively queueing them for execution.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
step (str): The step of the node to mark.
|
|
252
|
+
index (str): The index of the node to mark.
|
|
253
|
+
"""
|
|
112
254
|
if (step, index) not in self.__flow_runtime.get_nodes():
|
|
113
255
|
return
|
|
114
256
|
|
|
@@ -121,10 +263,14 @@ class Scheduler:
|
|
|
121
263
|
self.__record.set('status', NodeStatus.PENDING, step=next_step, index=next_index)
|
|
122
264
|
|
|
123
265
|
def __run_setup(self):
|
|
124
|
-
|
|
266
|
+
"""
|
|
267
|
+
Private helper to perform initial setup for the entire run.
|
|
125
268
|
|
|
126
|
-
|
|
127
|
-
|
|
269
|
+
This includes checking for a display environment, creating SchedulerNode
|
|
270
|
+
objects for each task, and copying results from a previous job if one
|
|
271
|
+
is specified.
|
|
272
|
+
"""
|
|
273
|
+
self.__check_display()
|
|
128
274
|
|
|
129
275
|
# Create tasks
|
|
130
276
|
copy_from_nodes = set(self.__flow_load_runtime.get_nodes()).difference(
|
|
@@ -141,22 +287,27 @@ class Scheduler:
|
|
|
141
287
|
if self.__flow.get(step, index, "tool") == "builtin":
|
|
142
288
|
self.__tasks[(step, index)].set_builtin()
|
|
143
289
|
|
|
144
|
-
if
|
|
145
|
-
self.__tasks[(step, index)].copy_from(
|
|
290
|
+
if self.__org_job_name and (step, index) in copy_from_nodes:
|
|
291
|
+
self.__tasks[(step, index)].copy_from(self.__org_job_name)
|
|
146
292
|
|
|
147
|
-
if
|
|
293
|
+
if self.__org_job_name:
|
|
148
294
|
# Copy collection directory
|
|
149
|
-
copy_from = self.__chip._getcollectdir(jobname=
|
|
295
|
+
copy_from = self.__chip._getcollectdir(jobname=self.__org_job_name)
|
|
150
296
|
copy_to = self.__chip._getcollectdir()
|
|
151
297
|
if os.path.exists(copy_from):
|
|
152
298
|
shutil.copytree(copy_from, copy_to,
|
|
153
299
|
dirs_exist_ok=True,
|
|
154
300
|
copy_function=utils.link_copy)
|
|
155
301
|
|
|
156
|
-
self.__clean_build_dir()
|
|
157
302
|
self.__reset_flow_nodes()
|
|
158
303
|
|
|
159
304
|
def __reset_flow_nodes(self):
|
|
305
|
+
"""
|
|
306
|
+
Private helper to reset the status and metrics for all nodes in the flow.
|
|
307
|
+
|
|
308
|
+
This prepares the schema for a new run by clearing out results from any
|
|
309
|
+
previous executions.
|
|
310
|
+
"""
|
|
160
311
|
# Reset record
|
|
161
312
|
for step, index in self.__flow.get_nodes():
|
|
162
313
|
self.__record.clear(step, index, keep=['remoteid', 'status', 'pythonpackage'])
|
|
@@ -167,6 +318,12 @@ class Scheduler:
|
|
|
167
318
|
self.__metrics.clear(step, index)
|
|
168
319
|
|
|
169
320
|
def __clean_build_dir(self):
|
|
321
|
+
"""
|
|
322
|
+
Private helper to clean the build directory if necessary.
|
|
323
|
+
|
|
324
|
+
If ['option', 'clean'] is True and the run starts from the beginning,
|
|
325
|
+
the entire build directory is removed to ensure a fresh start.
|
|
326
|
+
"""
|
|
170
327
|
if self.__record.get('remoteid'):
|
|
171
328
|
return
|
|
172
329
|
|
|
@@ -178,6 +335,14 @@ class Scheduler:
|
|
|
178
335
|
shutil.rmtree(cur_job_dir)
|
|
179
336
|
|
|
180
337
|
def configure_nodes(self):
|
|
338
|
+
"""
|
|
339
|
+
Configures all nodes before execution.
|
|
340
|
+
|
|
341
|
+
This is a critical step that determines the final state of each node
|
|
342
|
+
(SUCCESS, PENDING, SKIPPED) before the scheduler starts. It loads
|
|
343
|
+
results from previous runs, checks for any modifications to parameters
|
|
344
|
+
or input files, and marks nodes for re-run accordingly.
|
|
345
|
+
"""
|
|
181
346
|
from_nodes = []
|
|
182
347
|
extra_setup_nodes = {}
|
|
183
348
|
|
|
@@ -206,7 +371,7 @@ class Scheduler:
|
|
|
206
371
|
|
|
207
372
|
manifest = os.path.join(self.__chip.getworkdir(step=step, index=index),
|
|
208
373
|
'outputs',
|
|
209
|
-
f'{self.
|
|
374
|
+
f'{self.__name}.pkg.json')
|
|
210
375
|
if os.path.exists(manifest):
|
|
211
376
|
# ensure we setup these nodes again
|
|
212
377
|
try:
|
|
@@ -262,8 +427,9 @@ class Scheduler:
|
|
|
262
427
|
|
|
263
428
|
self.__print_status("After ensure")
|
|
264
429
|
|
|
430
|
+
os.makedirs(self.__chip.getworkdir(), exist_ok=True)
|
|
265
431
|
self.__chip.write_manifest(os.path.join(self.__chip.getworkdir(),
|
|
266
|
-
f"{self.
|
|
432
|
+
f"{self.__name}.pkg.json"))
|
|
267
433
|
journal.stop()
|
|
268
434
|
|
|
269
435
|
# Clean nodes marked pending
|
|
@@ -273,9 +439,13 @@ class Scheduler:
|
|
|
273
439
|
self.__tasks[(step, index)].clean_directory()
|
|
274
440
|
|
|
275
441
|
def __check_display(self):
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
442
|
+
"""
|
|
443
|
+
Private helper to automatically disable GUI display on headless systems.
|
|
444
|
+
|
|
445
|
+
If running on Linux without a DISPLAY or WAYLAND_DISPLAY environment
|
|
446
|
+
variable, this sets ['option', 'nodisplay'] to True to prevent tools
|
|
447
|
+
from attempting to open a GUI.
|
|
448
|
+
"""
|
|
279
449
|
|
|
280
450
|
if not self.__chip.get('option', 'nodisplay') and sys.platform == 'linux' \
|
|
281
451
|
and 'DISPLAY' not in os.environ and 'WAYLAND_DISPLAY' not in os.environ:
|
|
@@ -284,11 +454,16 @@ class Scheduler:
|
|
|
284
454
|
self.__chip.set('option', 'nodisplay', True)
|
|
285
455
|
|
|
286
456
|
def __increment_job_name(self):
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
457
|
+
"""
|
|
458
|
+
Private helper to auto-increment the jobname if ['option', 'jobincr'] is True.
|
|
459
|
+
|
|
460
|
+
This prevents overwriting previous job results by finding the highest
|
|
461
|
+
numbered existing job directory and creating a new one with an
|
|
462
|
+
incremented number.
|
|
291
463
|
|
|
464
|
+
Returns:
|
|
465
|
+
bool: True if the job name was incremented, False otherwise.
|
|
466
|
+
"""
|
|
292
467
|
if not self.__chip.get('option', 'clean'):
|
|
293
468
|
return False
|
|
294
469
|
if not self.__chip.get('option', 'jobincr'):
|