siliconcompiler 0.34.2__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.
Files changed (121) hide show
  1. siliconcompiler/__init__.py +12 -5
  2. siliconcompiler/__main__.py +1 -7
  3. siliconcompiler/_metadata.py +1 -1
  4. siliconcompiler/apps/_common.py +104 -23
  5. siliconcompiler/apps/sc.py +4 -8
  6. siliconcompiler/apps/sc_dashboard.py +6 -4
  7. siliconcompiler/apps/sc_install.py +10 -6
  8. siliconcompiler/apps/sc_issue.py +7 -5
  9. siliconcompiler/apps/sc_remote.py +1 -1
  10. siliconcompiler/apps/sc_server.py +9 -14
  11. siliconcompiler/apps/sc_show.py +6 -5
  12. siliconcompiler/apps/smake.py +130 -94
  13. siliconcompiler/apps/utils/replay.py +4 -7
  14. siliconcompiler/apps/utils/summarize.py +3 -5
  15. siliconcompiler/asic.py +420 -0
  16. siliconcompiler/checklist.py +25 -2
  17. siliconcompiler/cmdlineschema.py +534 -0
  18. siliconcompiler/constraints/asic_component.py +2 -2
  19. siliconcompiler/constraints/asic_pins.py +2 -2
  20. siliconcompiler/constraints/asic_timing.py +3 -3
  21. siliconcompiler/core.py +7 -32
  22. siliconcompiler/data/templates/tcl/manifest.tcl.j2 +8 -0
  23. siliconcompiler/dependencyschema.py +89 -31
  24. siliconcompiler/design.py +176 -207
  25. siliconcompiler/filesetschema.py +250 -0
  26. siliconcompiler/flowgraph.py +274 -95
  27. siliconcompiler/fpga.py +124 -1
  28. siliconcompiler/library.py +218 -20
  29. siliconcompiler/metric.py +233 -20
  30. siliconcompiler/package/__init__.py +271 -50
  31. siliconcompiler/package/git.py +92 -16
  32. siliconcompiler/package/github.py +108 -12
  33. siliconcompiler/package/https.py +79 -16
  34. siliconcompiler/packageschema.py +88 -7
  35. siliconcompiler/pathschema.py +31 -2
  36. siliconcompiler/pdk.py +566 -1
  37. siliconcompiler/project.py +1095 -94
  38. siliconcompiler/record.py +38 -1
  39. siliconcompiler/remote/__init__.py +5 -2
  40. siliconcompiler/remote/client.py +11 -6
  41. siliconcompiler/remote/schema.py +5 -23
  42. siliconcompiler/remote/server.py +41 -54
  43. siliconcompiler/report/__init__.py +3 -3
  44. siliconcompiler/report/dashboard/__init__.py +48 -14
  45. siliconcompiler/report/dashboard/cli/__init__.py +99 -21
  46. siliconcompiler/report/dashboard/cli/board.py +364 -179
  47. siliconcompiler/report/dashboard/web/__init__.py +90 -12
  48. siliconcompiler/report/dashboard/web/components/__init__.py +219 -240
  49. siliconcompiler/report/dashboard/web/components/flowgraph.py +49 -26
  50. siliconcompiler/report/dashboard/web/components/graph.py +139 -100
  51. siliconcompiler/report/dashboard/web/layouts/__init__.py +29 -1
  52. siliconcompiler/report/dashboard/web/layouts/_common.py +38 -2
  53. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph.py +39 -26
  54. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_node_tab.py +50 -50
  55. siliconcompiler/report/dashboard/web/layouts/vertical_flowgraph_sac_tabs.py +49 -46
  56. siliconcompiler/report/dashboard/web/state.py +141 -14
  57. siliconcompiler/report/dashboard/web/utils/__init__.py +79 -16
  58. siliconcompiler/report/dashboard/web/utils/file_utils.py +74 -11
  59. siliconcompiler/report/dashboard/web/viewer.py +25 -1
  60. siliconcompiler/report/report.py +5 -2
  61. siliconcompiler/report/summary_image.py +29 -11
  62. siliconcompiler/scheduler/__init__.py +9 -1
  63. siliconcompiler/scheduler/docker.py +79 -1
  64. siliconcompiler/scheduler/run_node.py +35 -19
  65. siliconcompiler/scheduler/scheduler.py +208 -24
  66. siliconcompiler/scheduler/schedulernode.py +372 -46
  67. siliconcompiler/scheduler/send_messages.py +77 -29
  68. siliconcompiler/scheduler/slurm.py +76 -12
  69. siliconcompiler/scheduler/taskscheduler.py +140 -20
  70. siliconcompiler/schema/__init__.py +0 -2
  71. siliconcompiler/schema/baseschema.py +194 -38
  72. siliconcompiler/schema/journal.py +7 -4
  73. siliconcompiler/schema/namedschema.py +16 -10
  74. siliconcompiler/schema/parameter.py +55 -9
  75. siliconcompiler/schema/parametervalue.py +60 -0
  76. siliconcompiler/schema/safeschema.py +25 -2
  77. siliconcompiler/schema/schema_cfg.py +5 -5
  78. siliconcompiler/schema/utils.py +2 -2
  79. siliconcompiler/schema_obj.py +20 -3
  80. siliconcompiler/tool.py +979 -302
  81. siliconcompiler/tools/bambu/__init__.py +41 -0
  82. siliconcompiler/tools/builtin/concatenate.py +2 -2
  83. siliconcompiler/tools/builtin/minimum.py +2 -1
  84. siliconcompiler/tools/builtin/mux.py +2 -1
  85. siliconcompiler/tools/builtin/nop.py +2 -1
  86. siliconcompiler/tools/builtin/verify.py +2 -1
  87. siliconcompiler/tools/klayout/__init__.py +95 -0
  88. siliconcompiler/tools/openroad/__init__.py +289 -0
  89. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +3 -0
  90. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +7 -2
  91. siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +8 -4
  92. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +9 -5
  93. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +5 -1
  94. siliconcompiler/tools/slang/__init__.py +1 -1
  95. siliconcompiler/tools/slang/elaborate.py +2 -1
  96. siliconcompiler/tools/vivado/scripts/sc_run.tcl +1 -1
  97. siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +8 -1
  98. siliconcompiler/tools/vivado/syn_fpga.py +6 -0
  99. siliconcompiler/tools/vivado/vivado.py +35 -2
  100. siliconcompiler/tools/vpr/__init__.py +150 -0
  101. siliconcompiler/tools/yosys/__init__.py +369 -1
  102. siliconcompiler/tools/yosys/scripts/procs.tcl +0 -1
  103. siliconcompiler/toolscripts/_tools.json +5 -10
  104. siliconcompiler/utils/__init__.py +66 -0
  105. siliconcompiler/utils/flowgraph.py +2 -2
  106. siliconcompiler/utils/issue.py +2 -1
  107. siliconcompiler/utils/logging.py +14 -0
  108. siliconcompiler/utils/multiprocessing.py +256 -0
  109. siliconcompiler/utils/showtools.py +10 -0
  110. {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/METADATA +5 -5
  111. {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/RECORD +115 -118
  112. {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/entry_points.txt +3 -0
  113. siliconcompiler/schema/cmdlineschema.py +0 -250
  114. siliconcompiler/toolscripts/rhel8/install-slang.sh +0 -40
  115. siliconcompiler/toolscripts/rhel9/install-slang.sh +0 -40
  116. siliconcompiler/toolscripts/ubuntu20/install-slang.sh +0 -47
  117. siliconcompiler/toolscripts/ubuntu22/install-slang.sh +0 -37
  118. siliconcompiler/toolscripts/ubuntu24/install-slang.sh +0 -37
  119. {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/WHEEL +0 -0
  120. {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/licenses/LICENSE +0 -0
  121. {siliconcompiler-0.34.2.dist-info → siliconcompiler-0.34.3.dist-info}/top_level.txt +0 -0
@@ -16,18 +16,37 @@ from siliconcompiler.report.dashboard.web import utils
16
16
 
17
17
 
18
18
  class WebDashboard(AbstractDashboard):
19
+ """
20
+ A web-based dashboard for SiliconCompiler that uses the Streamlit framework.
21
+
22
+ This class launches a Streamlit server in a separate process to provide a
23
+ real-time, interactive web UI for monitoring a chip's compilation flow.
24
+ It manages a temporary directory for passing manifests and configuration
25
+ between the main SC process and the Streamlit dashboard process.
26
+
27
+ Args:
28
+ chip (Chip): The main chip object to display.
29
+ port (int, optional): The port to run the Streamlit server on. If not
30
+ provided, it will search for an available port.
31
+ graph_chips (list, optional): A list of other chip objects to include
32
+ for comparison or display in the dashboard.
33
+ """
19
34
  __port = 8501
20
35
 
21
36
  @staticmethod
22
37
  def __signal_handler(signal, frame):
38
+ """A no-op signal handler to gracefully manage shutdown."""
23
39
  # used to avoid issues during shutdown
24
40
  pass
25
41
 
26
42
  def __init__(self, chip, port=None, graph_chips=None):
43
+ """
44
+ Initializes the WebDashboard.
45
+ """
27
46
  try:
28
47
  from streamlit.web import bootstrap # noqa: F401
29
48
  except ModuleNotFoundError:
30
- raise NotImplementedError('streamlit is not available')
49
+ raise NotImplementedError('streamlit is not available for dashboard')
31
50
 
32
51
  super().__init__(chip)
33
52
 
@@ -46,6 +65,7 @@ class WebDashboard(AbstractDashboard):
46
65
  dirname = os.path.dirname(__file__)
47
66
  self.__streamlit_file = os.path.join(dirname, 'viewer.py')
48
67
 
68
+ # Configure Streamlit server options
49
69
  self.__streamlit_args = [
50
70
  ("browser.gatherUsageStats", False),
51
71
  ("browser.serverPort", self.__port),
@@ -57,11 +77,7 @@ class WebDashboard(AbstractDashboard):
57
77
  if "PYTEST_CURRENT_TEST" in os.environ:
58
78
  self.__streamlit_args.append(("server.headless", True))
59
79
 
60
- # pass in a json object called __graph_chips
61
- # the key is the chip_name and value is the filepath
62
- # if another argument is passed
63
-
64
- # use of list is to preserve order
80
+ # Prepare configuration for any additional chips to be displayed
65
81
  self.__graph_chips = []
66
82
  graph_chips_config = []
67
83
  if graph_chips:
@@ -80,6 +96,7 @@ class WebDashboard(AbstractDashboard):
80
96
  chip_object_and_name['cfg_path'])
81
97
  })
82
98
 
99
+ # Final configuration object to be passed to the Streamlit process
83
100
  self.__config = {
84
101
  "manifest": self.__manifest,
85
102
  "lock": self.__manifest_lock,
@@ -91,27 +108,43 @@ class WebDashboard(AbstractDashboard):
91
108
 
92
109
  self.__lock = fasteners.InterProcessLock(self.__manifest_lock)
93
110
 
111
+ # Ensure cleanup is called on exit
94
112
  atexit.register(self.__cleanup)
95
113
 
96
114
  def open_dashboard(self):
115
+ """
116
+ Starts the Streamlit dashboard server in a new process.
117
+
118
+ This method writes the necessary configuration and manifests, then
119
+ launches the Streamlit bootstrap function in a separate process.
120
+ """
121
+ # Write the configuration file for the Streamlit app to read
97
122
  with open(self.__get_config_file(), 'w') as f:
98
123
  json.dump(self.__config, f, indent=4)
99
124
 
100
125
  self.update_manifest()
101
-
102
126
  self.update_graph_manifests()
103
127
 
128
+ # Launch Streamlit in a separate process
104
129
  self.__dashboard = multiprocessing.Process(
105
130
  target=self._run_streamlit_bootstrap)
106
131
 
132
+ # Temporarily override the SIGINT handler for graceful shutdown
107
133
  self.__signal_handler = signal.signal(signal.SIGINT, WebDashboard.__signal_handler)
108
134
 
109
135
  self.__dashboard.start()
110
136
 
111
137
  def update_manifest(self, payload=None):
138
+ """
139
+ Writes the main chip's manifest to the shared temporary directory.
140
+
141
+ This method is the primary way data is passed from the main process
142
+ to the dashboard process. It uses a file lock to prevent race conditions.
143
+ """
112
144
  if not self.__manifest:
113
145
  return
114
146
 
147
+ # Write to a new file and then move it to be atomic
115
148
  new_file = f"{self.__manifest}.new.json"
116
149
  self.__chip.write_manifest(new_file)
117
150
 
@@ -119,71 +152,108 @@ class WebDashboard(AbstractDashboard):
119
152
  shutil.move(new_file, self.__manifest)
120
153
 
121
154
  def update_graph_manifests(self):
155
+ """
156
+ Writes the manifests for all additional graph chips to the shared directory.
157
+ """
122
158
  for chip_object_and_name in self.__graph_chips:
123
159
  chip = chip_object_and_name['chip']
124
160
  file_path = chip_object_and_name['name']
125
161
  chip.write_manifest(file_path)
126
162
 
127
163
  def __get_config_file(self):
164
+ """Returns the path to the dashboard's JSON configuration file."""
128
165
  return os.path.join(self.__directory, 'config.json')
129
166
 
130
167
  def is_running(self):
168
+ """
169
+ Checks if the dashboard server process is currently running.
170
+
171
+ Returns:
172
+ bool: True if the dashboard is running, False otherwise.
173
+ """
131
174
  if self.__dashboard is None:
132
175
  return False
133
176
 
134
177
  if self.__dashboard.is_alive():
135
178
  return True
136
179
 
180
+ # Process is no longer alive, so clean up
137
181
  self.__dashboard = None
138
182
  self.__manifest = None
139
183
  return False
140
184
 
141
185
  def end_of_run(self):
186
+ """A placeholder method to fulfill the AbstractDashboard interface."""
142
187
  pass
143
188
 
144
189
  def stop(self):
190
+ """
191
+ Stops the dashboard server process.
192
+ """
145
193
  if not self.is_running():
146
194
  return
147
195
 
196
+ # Terminate the process
148
197
  while self.__dashboard.is_alive():
149
198
  self.__dashboard.terminate()
150
199
  self._sleep()
151
200
 
201
+ # Restore the original signal handler
152
202
  if self.__signal_handler:
153
203
  signal.signal(signal.SIGINT, self.__signal_handler)
154
204
 
205
+ # Clean up state
155
206
  self.__dashboard = None
156
207
  self.__manifest = None
157
208
  self.__signal_handler = None
158
209
 
159
210
  def wait(self):
160
- self.__dashboard.join()
211
+ """
212
+ Waits for the dashboard server process to terminate.
213
+ """
214
+ if self.is_running():
215
+ self.__dashboard.join()
161
216
 
162
217
  def _sleep(self):
218
+ """Pauses execution for a short duration."""
163
219
  time.sleep(self.__sleep_time)
164
220
 
165
221
  def _run_streamlit_bootstrap(self):
222
+ """
223
+ The target function for the multiprocessing.Process.
224
+
225
+ This function configures and runs the Streamlit application.
226
+ """
166
227
  from streamlit.web import bootstrap
167
228
  from streamlit import config as _config
168
229
 
230
+ # Set all configured Streamlit options
169
231
  for config, val in self.__streamlit_args:
170
232
  _config.set_option(config, val)
171
233
 
234
+ # Run the Streamlit script
172
235
  bootstrap.run(self.__streamlit_file,
173
236
  False,
174
237
  [self.__get_config_file()],
175
238
  flag_options={})
176
239
 
177
240
  def __run_streamlit_subproc(self):
241
+ """
242
+ An alternative (unused) method to run Streamlit using a subprocess.
243
+ """
178
244
  cmd = ['streamlit', 'run',
179
245
  self.__streamlit_file, self.__get_config_file()]
180
246
  for config, val in self.__streamlit_args:
181
247
  cmd.append(f'--{config}')
182
- cmd.append(val)
248
+ cmd.append(str(val))
183
249
 
184
250
  subprocess.Popen(cmd)
185
251
 
186
252
  def __cleanup(self):
253
+ """
254
+ Cleans up resources by stopping the dashboard and removing the temp directory.
255
+ This method is registered with atexit to be called on program exit.
256
+ """
187
257
  self.stop()
188
258
 
189
259
  if os.path.exists(self.__directory):
@@ -191,6 +261,14 @@ class WebDashboard(AbstractDashboard):
191
261
 
192
262
  @staticmethod
193
263
  def get_next_port():
194
- with socketserver.TCPServer(("localhost", 0), None) as s:
195
- return s.server_address[1]
196
- return None
264
+ """
265
+ Finds an available TCP port on the local machine.
266
+
267
+ Returns:
268
+ int or None: An available port number, or None if one cannot be found.
269
+ """
270
+ try:
271
+ with socketserver.TCPServer(("localhost", 0), None) as s:
272
+ return s.server_address[1]
273
+ except OSError:
274
+ return None