siliconcompiler 0.33.1__py3-none-any.whl → 0.34.0__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 (59) hide show
  1. siliconcompiler/__init__.py +2 -0
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/sc_issue.py +5 -3
  4. siliconcompiler/apps/sc_remote.py +0 -17
  5. siliconcompiler/apps/utils/replay.py +5 -5
  6. siliconcompiler/checklist.py +1 -1
  7. siliconcompiler/core.py +39 -48
  8. siliconcompiler/data/templates/replay/replay.sh.j2 +18 -1
  9. siliconcompiler/dependencyschema.py +392 -0
  10. siliconcompiler/design.py +664 -0
  11. siliconcompiler/flowgraph.py +32 -1
  12. siliconcompiler/metric.py +19 -0
  13. siliconcompiler/package/__init__.py +383 -223
  14. siliconcompiler/package/git.py +75 -77
  15. siliconcompiler/package/github.py +70 -97
  16. siliconcompiler/package/https.py +77 -93
  17. siliconcompiler/packageschema.py +260 -0
  18. siliconcompiler/pdk.py +2 -2
  19. siliconcompiler/record.py +57 -5
  20. siliconcompiler/remote/client.py +61 -13
  21. siliconcompiler/remote/server.py +109 -64
  22. siliconcompiler/report/dashboard/cli/board.py +1 -2
  23. siliconcompiler/scheduler/__init__.py +3 -1375
  24. siliconcompiler/scheduler/docker.py +268 -0
  25. siliconcompiler/scheduler/run_node.py +20 -19
  26. siliconcompiler/scheduler/scheduler.py +308 -0
  27. siliconcompiler/scheduler/schedulernode.py +934 -0
  28. siliconcompiler/scheduler/slurm.py +147 -163
  29. siliconcompiler/scheduler/taskscheduler.py +39 -52
  30. siliconcompiler/schema/__init__.py +3 -3
  31. siliconcompiler/schema/baseschema.py +256 -11
  32. siliconcompiler/schema/editableschema.py +4 -0
  33. siliconcompiler/schema/journal.py +210 -0
  34. siliconcompiler/schema/namedschema.py +31 -2
  35. siliconcompiler/schema/parameter.py +14 -1
  36. siliconcompiler/schema/parametervalue.py +1 -34
  37. siliconcompiler/schema/schema_cfg.py +211 -350
  38. siliconcompiler/tool.py +139 -37
  39. siliconcompiler/tools/_common/__init__.py +14 -11
  40. siliconcompiler/tools/builtin/concatenate.py +2 -2
  41. siliconcompiler/tools/builtin/verify.py +1 -2
  42. siliconcompiler/tools/openroad/scripts/common/procs.tcl +27 -25
  43. siliconcompiler/tools/slang/__init__.py +3 -2
  44. siliconcompiler/tools/vpr/route.py +69 -0
  45. siliconcompiler/tools/yosys/sc_synth_asic.tcl +0 -4
  46. siliconcompiler/toolscripts/_tools.json +13 -8
  47. siliconcompiler/toolscripts/ubuntu22/install-klayout.sh +4 -0
  48. siliconcompiler/toolscripts/ubuntu24/install-klayout.sh +4 -0
  49. siliconcompiler/utils/__init__.py +2 -23
  50. siliconcompiler/utils/flowgraph.py +5 -5
  51. siliconcompiler/utils/logging.py +2 -1
  52. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/METADATA +8 -6
  53. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/RECORD +57 -52
  54. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/WHEEL +1 -1
  55. siliconcompiler/scheduler/docker_runner.py +0 -254
  56. siliconcompiler/schema/journalingschema.py +0 -238
  57. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/entry_points.txt +0 -0
  58. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/licenses/LICENSE +0 -0
  59. {siliconcompiler-0.33.1.dist-info → siliconcompiler-0.34.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,260 @@
1
+ import os
2
+
3
+ import os.path
4
+
5
+ from siliconcompiler.schema import BaseSchema
6
+ from siliconcompiler.schema import EditableSchema, Parameter, Scope
7
+ from siliconcompiler.schema.utils import trim
8
+ from siliconcompiler.package import Resolver
9
+
10
+
11
+ class PackageSchema(BaseSchema):
12
+ def __init__(self):
13
+ super().__init__()
14
+
15
+ schema_package(self)
16
+
17
+ self.__cache = {}
18
+
19
+ def register(self, name, path, ref=None, clobber=True):
20
+ """
21
+ Registers a package by its name with the source path and reference
22
+
23
+ Registered package sources are stored in the package section of the schema.
24
+
25
+ Args:
26
+ name (str): Package name
27
+ path (str): Path to the sources, can be file, git url, archive url
28
+ ref (str): Reference of the sources, can be commitid, branch name, tag
29
+ clobber (bool): Overwrite existing
30
+
31
+ Examples:
32
+ >>> schema.register('siliconcompiler_data',
33
+ 'git+https://github.com/siliconcompiler/siliconcompiler',
34
+ 'cd328131bafd361787f9137a6ffed999d64c8c30')
35
+ """
36
+
37
+ # If this is a file, get the directory for this
38
+ if os.path.isfile(path):
39
+ path = os.path.dirname(os.path.abspath(path))
40
+ elif os.path.isdir(path):
41
+ path = os.path.abspath(path)
42
+
43
+ success = False
44
+ if self.set('source', name, 'path', path, clobber=clobber):
45
+ success = True
46
+ if success and ref:
47
+ success = False
48
+ if self.set('source', name, 'ref', ref, clobber=clobber):
49
+ success = True
50
+ return success
51
+
52
+ def get_resolver(self, package):
53
+ '''
54
+ Returns a specific resolver
55
+
56
+ Args:
57
+ package (str): name of package
58
+ '''
59
+ resolver_cls = Resolver.find_resolver(self.get("source", package, "path"))
60
+ resolver = resolver_cls(package, self._parent(root=True),
61
+ self.get("source", package, "path"),
62
+ self.get("source", package, "ref"))
63
+ resolver.set_cache(self.__cache)
64
+ return resolver
65
+
66
+ def get_resolvers(self):
67
+ '''
68
+ Returns a dictionary of packages with their resolver method.
69
+ '''
70
+ resolvers = {}
71
+ for package in self.getkeys("source"):
72
+ resolvers[package] = self.get_resolver(package).get_path
73
+
74
+ return resolvers
75
+
76
+ def _set_cache(self, package, path):
77
+ self.__cache[package] = path
78
+
79
+ def get_path_cache(self):
80
+ return self.__cache.copy()
81
+
82
+
83
+ ############################################
84
+ # Package information
85
+ ############################################
86
+ def schema_package(schema):
87
+ schema = EditableSchema(schema)
88
+
89
+ schema.insert(
90
+ 'version',
91
+ Parameter(
92
+ 'str',
93
+ scope=Scope.GLOBAL,
94
+ shorthelp="Package: version",
95
+ switch="-package_version <str>",
96
+ example=[
97
+ "cli: -package_version 1.0",
98
+ "api: chip.set('package', 'version', '1.0')"],
99
+ help=trim("""Package version. Can be a branch, tag, commit hash,
100
+ or a semver compatible version.""")))
101
+
102
+ schema.insert(
103
+ 'description',
104
+ Parameter(
105
+ 'str',
106
+ scope=Scope.GLOBAL,
107
+ shorthelp="Package: description",
108
+ switch="-package_description <str>",
109
+ example=[
110
+ "cli: -package_description 'Yet another cpu'",
111
+ "api: chip.set('package', 'description', 'Yet another cpu')"],
112
+ help=trim("""Package short one line description for package
113
+ managers and summary reports.""")))
114
+
115
+ schema.insert(
116
+ 'keyword',
117
+ Parameter(
118
+ 'str',
119
+ scope=Scope.GLOBAL,
120
+ shorthelp="Package: keyword",
121
+ switch="-package_keyword <str>",
122
+ example=[
123
+ "cli: -package_keyword cpu",
124
+ "api: chip.set('package', 'keyword', 'cpu')"],
125
+ help=trim("""Package keyword(s) used to characterize package.""")))
126
+ schema.insert(
127
+ 'doc', 'homepage',
128
+ Parameter(
129
+ 'str',
130
+ scope=Scope.GLOBAL,
131
+ shorthelp="Package: documentation homepage",
132
+ switch="-package_doc_homepage <str>",
133
+ example=[
134
+ "cli: -package_doc_homepage index.html",
135
+ "api: chip.set('package', 'doc', 'homepage', 'index.html')"],
136
+ help=trim("""
137
+ Package documentation homepage. Filepath to design docs homepage.
138
+ Complex designs can can include a long non standard list of
139
+ documents dependent. A single html entry point can be used to
140
+ present an organized documentation dashboard to the designer.""")))
141
+
142
+ doctypes = ['datasheet',
143
+ 'reference',
144
+ 'userguide',
145
+ 'quickstart',
146
+ 'releasenotes',
147
+ 'testplan',
148
+ 'signoff',
149
+ 'tutorial']
150
+
151
+ for item in doctypes:
152
+ schema.insert(
153
+ 'doc', item,
154
+ Parameter(
155
+ '[file]',
156
+ scope=Scope.GLOBAL,
157
+ shorthelp=f"Package: {item} document",
158
+ switch=f"-package_doc_{item} <file>",
159
+ example=[
160
+ f"cli: -package_doc_{item} {item}.pdf",
161
+ f"api: chip.set('package', 'doc', '{item}', '{item}.pdf')"],
162
+ help=trim(f"""Package list of {item} documents.""")))
163
+
164
+ schema.insert(
165
+ 'license',
166
+ Parameter(
167
+ '[str]',
168
+ scope=Scope.GLOBAL,
169
+ shorthelp="Package: license identifiers",
170
+ switch="-package_license <str>",
171
+ example=[
172
+ "cli: -package_license 'Apache-2.0'",
173
+ "api: chip.set('package', 'license', 'Apache-2.0')"],
174
+ help=trim("""Package list of SPDX license identifiers.""")))
175
+
176
+ schema.insert(
177
+ 'licensefile',
178
+ Parameter(
179
+ '[file]',
180
+ scope=Scope.GLOBAL,
181
+ shorthelp="Package: license files",
182
+ switch="-package_licensefile <file>",
183
+ example=[
184
+ "cli: -package_licensefile './LICENSE'",
185
+ "api: chip.set('package', 'licensefile', './LICENSE')"],
186
+ help=trim("""Package list of license files for to be
187
+ applied in cases when a SPDX identifier is not available.
188
+ (eg. proprietary licenses).""")))
189
+
190
+ schema.insert(
191
+ 'organization',
192
+ Parameter(
193
+ '[str]',
194
+ scope=Scope.GLOBAL,
195
+ shorthelp="Package: sponsoring organization",
196
+ switch="-package_organization <str>",
197
+ example=[
198
+ "cli: -package_organization 'humanity'",
199
+ "api: chip.set('package', 'organization', 'humanity')"],
200
+ help=trim("""Package sponsoring organization. The field can be left
201
+ blank if not applicable.""")))
202
+
203
+ record = ['name',
204
+ 'email',
205
+ 'username',
206
+ 'location',
207
+ 'organization',
208
+ 'publickey']
209
+
210
+ for item in record:
211
+ schema.insert(
212
+ 'author', 'default', item,
213
+ Parameter(
214
+ 'str',
215
+ scope=Scope.GLOBAL,
216
+ shorthelp=f"Package: author {item}",
217
+ switch=f"-package_author_{item} 'userid <str>'",
218
+ example=[
219
+ f"cli: -package_author_{item} 'wiley wiley@acme.com'",
220
+ f"api: chip.set('package', 'author', 'wiley', '{item}', 'wiley@acme.com')"],
221
+ help=trim(f"""Package author {item} provided with full name as key and
222
+ {item} as value.""")))
223
+
224
+ schema.insert(
225
+ 'source', 'default', 'path',
226
+ Parameter(
227
+ 'str',
228
+ scope=Scope.GLOBAL,
229
+ shorthelp="Package: data source path",
230
+ switch="-package_source_path 'source <str>'",
231
+ example=[
232
+ "cli: -package_source_path "
233
+ "'freepdk45_data ssh://git@github.com/siliconcompiler/freepdk45/'",
234
+ "api: chip.set('package', 'source', "
235
+ "'freepdk45_data', 'path', 'ssh://git@github.com/siliconcompiler/freepdk45/')"],
236
+ help=trim("""
237
+ Package data source path, allowed paths:
238
+
239
+ * /path/on/network/drive
240
+ * file:///path/on/network/drive
241
+ * git+https://github.com/xyz/xyz
242
+ * git://github.com/xyz/xyz
243
+ * git+ssh://github.com/xyz/xyz
244
+ * ssh://github.com/xyz/xyz
245
+ * https://github.com/xyz/xyz/archive
246
+ * https://zeroasic.com/xyz.tar.gz
247
+ * python://siliconcompiler
248
+ """)))
249
+
250
+ schema.insert(
251
+ 'source', 'default', 'ref',
252
+ Parameter(
253
+ 'str',
254
+ scope=Scope.GLOBAL,
255
+ shorthelp="Package: data source reference",
256
+ switch="-package_source_ref 'source <str>'",
257
+ example=[
258
+ "cli: -package_source_ref 'freepdk45_data 07ec4aa'",
259
+ "api: chip.set('package', 'source', 'freepdk45_data', 'ref', '07ec4aa')"],
260
+ help=trim("""Package data source reference""")))
siliconcompiler/pdk.py CHANGED
@@ -4,8 +4,8 @@ from siliconcompiler.schema.utils import trim
4
4
 
5
5
 
6
6
  class PDKSchema(NamedSchema, PackageSchema):
7
- def __init__(self, name=None, package=None):
8
- NamedSchema.__init__(self, name=name)
7
+ def __init__(self, name, package=None):
8
+ NamedSchema.__init__(self, name)
9
9
  PackageSchema.__init__(self, package=package)
10
10
 
11
11
  schema_pdk(self)
siliconcompiler/record.py CHANGED
@@ -30,13 +30,25 @@ class RecordTool(Enum):
30
30
 
31
31
 
32
32
  class RecordSchema(BaseSchema):
33
- __TIMEFORMAT = "%Y-%m-%d %H:%M:%S"
33
+ __TIMEFORMAT = "%Y-%m-%d %H:%M:%S.%f"
34
34
 
35
35
  def __init__(self):
36
36
  super().__init__()
37
37
 
38
38
  schema_record(self)
39
39
 
40
+ def _from_dict(self, manifest, keypath, version=None):
41
+ ret = super()._from_dict(manifest, keypath, version)
42
+
43
+ # Correct for change specification
44
+ if version and version < (0, 50, 4):
45
+ for timekey in RecordTime:
46
+ start_param = self.get(timekey.value, field=None)
47
+ for value, step, index in start_param.getvalues():
48
+ start_param.set(f"{value}.000000", step=step, index=index)
49
+
50
+ return ret
51
+
40
52
  def clear(self, step, index, keep=None):
41
53
  '''
42
54
  Clear all saved metrics for a given step and index
@@ -275,6 +287,44 @@ class RecordSchema(BaseSchema):
275
287
  record_time+"+0000",
276
288
  RecordSchema.__TIMEFORMAT+"%z").timestamp()
277
289
 
290
+ def get_earliest_time(self, type):
291
+ '''
292
+ Returns the earliest recorded time.
293
+
294
+ Args:
295
+ type (:class:`RecordTime`): type of time to record
296
+ '''
297
+ type = RecordTime(type)
298
+ record_param = self.get(type.value, field=None)
299
+
300
+ times = set()
301
+ for _, step, index in record_param.getvalues():
302
+ times.add(self.get_recorded_time(step, index, type))
303
+
304
+ if not times:
305
+ return None
306
+
307
+ return min(times)
308
+
309
+ def get_latest_time(self, type):
310
+ '''
311
+ Returns the last recorded time.
312
+
313
+ Args:
314
+ type (:class:`RecordTime`): type of time to record
315
+ '''
316
+ type = RecordTime(type)
317
+ record_param = self.get(type.value, field=None)
318
+
319
+ times = set()
320
+ for _, step, index in record_param.getvalues():
321
+ times.add(self.get_recorded_time(step, index, type))
322
+
323
+ if not times:
324
+ return None
325
+
326
+ return max(times)
327
+
278
328
  def record_tool(self, step, index, info, type):
279
329
  '''
280
330
  Record information about the tool used during this record.
@@ -320,11 +370,13 @@ def schema_record(schema):
320
370
  'x86_64',
321
371
  '(x86_64, rv64imafdc)'],
322
372
  'starttime': ['start time',
323
- '\"2021-09-06 12:20:20\"',
324
- 'Time is reported in the ISO 8601 format YYYY-MM-DD HR:MIN:SEC'],
373
+ '\"2021-09-06 12:20:20.000000\"',
374
+ 'Time is recorded with the format YYYY-MM-DD HR:MIN:SEC.MICROSEC for '
375
+ 'UTC'],
325
376
  'endtime': ['end time',
326
- '\"2021-09-06 12:20:20\"',
327
- 'Time is reported in the ISO 8601 format YYYY-MM-DD HR:MIN:SEC'],
377
+ '\"2021-09-06 12:20:20.000000\"',
378
+ 'Time is recorded with the format YYYY-MM-DD HR:MIN:SEC.MICROSEC for '
379
+ 'UTC'],
328
380
  'region': ['cloud region',
329
381
  '\"US Gov Boston\"',
330
382
  """Recommended naming methodology:
@@ -10,18 +10,32 @@ import tarfile
10
10
  import tempfile
11
11
  import multiprocessing
12
12
 
13
- from siliconcompiler import utils, SiliconCompilerError, NodeStatus
13
+ import os.path
14
+
15
+ from siliconcompiler import utils, SiliconCompilerError
14
16
  from siliconcompiler import NodeStatus as SCNodeStatus
15
17
  from siliconcompiler._metadata import default_server
16
- from siliconcompiler.remote import JobStatus
18
+ from siliconcompiler.remote import JobStatus, NodeStatus
17
19
  from siliconcompiler.report.dashboard import DashboardType
18
20
  from siliconcompiler.flowgraph import RuntimeFlowgraph
19
- from siliconcompiler.schema import JournalingSchema
21
+ from siliconcompiler.scheduler.scheduler import Scheduler
22
+ from siliconcompiler.schema import Journal
20
23
 
21
24
  # Step name to use while logging
22
25
  remote_step_name = 'remote'
23
26
 
24
27
 
28
+ class ClientScheduler(Scheduler):
29
+ def run_core(self):
30
+ Client(self._Scheduler__chip).run()
31
+
32
+ def configure_nodes(self):
33
+ return
34
+
35
+ def check_manifest(self):
36
+ return True
37
+
38
+
25
39
  class Client():
26
40
  # Step name to use while logging
27
41
  STEP_NAME = "remote"
@@ -310,19 +324,29 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
310
324
  try:
311
325
  # Decode response JSON, if possible.
312
326
  job_info = json.loads(info['message'])
313
- except json.JSONDecodeError as e:
314
- self.__logger.warning(f"Job is still running: {e}")
327
+ if "null" in job_info:
328
+ job_info[None] = job_info["null"]
329
+ del job_info["null"]
330
+ except json.JSONDecodeError:
331
+ self.__logger.warning(f"Job is still running: {info['message']}")
315
332
  return completed, starttimes, True
316
333
 
317
334
  nodes_to_log = {}
318
335
  for node, node_info in job_info.items():
319
336
  status = node_info['status']
320
- nodes_to_log.setdefault(status, []).append((node, node_info))
337
+
338
+ if status == NodeStatus.UPLOADED:
339
+ status = SCNodeStatus.PENDING
321
340
 
322
341
  if SCNodeStatus.is_done(status):
323
342
  # collect completed
324
343
  completed.append(node)
325
344
 
345
+ if not node:
346
+ continue
347
+
348
+ nodes_to_log.setdefault(status, []).append((node, node_info))
349
+
326
350
  if self.__node_information and node in self.__node_information:
327
351
  self.__chip.set('record', 'status', status,
328
352
  step=self.__node_information[node]["step"],
@@ -580,6 +604,22 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
580
604
  raise SiliconCompilerError('Job canceled by user keyboard interrupt')
581
605
 
582
606
  def __import_run_manifests(self, starttimes):
607
+ if not self.__setup_information_loaded:
608
+ if self.__setup_information_fetched:
609
+ manifest = os.path.join(self.__chip.getworkdir(), f'{self.__chip.design}.pkg.json')
610
+ if os.path.exists(manifest):
611
+ try:
612
+ Journal.replay_file(self.__chip.schema, manifest)
613
+ self.__setup_information_loaded = True
614
+ changed = True
615
+ except: # noqa E722
616
+ # Import may fail if file is still getting written
617
+ pass
618
+
619
+ if not self.__setup_information_loaded:
620
+ # Dont do anything until this has been loaded
621
+ return
622
+
583
623
  changed = False
584
624
  for _, node_info in self.__node_information.items():
585
625
  if node_info["imported"]:
@@ -591,7 +631,7 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
591
631
  f'{self.__chip.design}.pkg.json')
592
632
  if os.path.exists(manifest):
593
633
  try:
594
- JournalingSchema(self.__chip.schema).read_journal(manifest)
634
+ Journal.replay_file(self.__chip.schema, manifest)
595
635
  node_info["imported"] = True
596
636
  changed = True
597
637
  except: # noqa E722
@@ -599,7 +639,7 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
599
639
  pass
600
640
  elif self.__chip.get('record', 'status',
601
641
  step=node_info["step"], index=node_info["index"]) \
602
- == NodeStatus.SKIPPED:
642
+ == SCNodeStatus.SKIPPED:
603
643
  node_info["imported"] = True
604
644
  changed = True
605
645
 
@@ -618,6 +658,9 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
618
658
  check_info = self.__check()
619
659
  self.__check_interval = check_info['progress_interval']
620
660
 
661
+ self.__setup_information_fetched = False
662
+ self.__setup_information_loaded = False
663
+
621
664
  self.__node_information = {}
622
665
  runtime = RuntimeFlowgraph(
623
666
  self.__chip.schema.get("flowgraph", self.__chip.get('option', 'flow'), field='schema'),
@@ -666,6 +709,11 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
666
709
  # Update dashboard if active
667
710
  self.__chip._dash.update_manifest({"starttimes": starttimes})
668
711
 
712
+ if None in completed:
713
+ completed.remove(None)
714
+ if not self.__setup_information_fetched:
715
+ self.__schedule_fetch_result(None)
716
+
669
717
  nodes_to_fetch = []
670
718
  for node in completed:
671
719
  if not self.__node_information[node]["fetched"]:
@@ -681,7 +729,6 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
681
729
  for node, node_info in self.__node_information.items():
682
730
  if not node_info["fetched"]:
683
731
  self.__schedule_fetch_result(node)
684
- self.__schedule_fetch_result(node)
685
732
 
686
733
  self._finalize_loop()
687
734
 
@@ -700,11 +747,12 @@ service, provided by SiliconCompiler, is not intended to process proprietary IP.
700
747
  self.__import_run_manifests({})
701
748
 
702
749
  def __schedule_fetch_result(self, node):
703
- self.__node_information[node]["fetched"] = True
750
+ if node:
751
+ self.__node_information[node]["fetched"] = True
752
+ self.__logger.info(f' {node}')
753
+ else:
754
+ self.__setup_information_fetched = True
704
755
  self.__download_pool.apply_async(Client._fetch_result, (self, node))
705
- if node is None:
706
- node = 'final result'
707
- self.__logger.info(f' {node}')
708
756
 
709
757
  def _fetch_result(self, node):
710
758
  '''