siliconcompiler 0.28.9__py3-none-any.whl → 0.29.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 (164) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/__init__.py +26 -0
  3. siliconcompiler/apps/sc_remote.py +15 -14
  4. siliconcompiler/apps/sc_show.py +5 -5
  5. siliconcompiler/apps/utils/replay.py +194 -0
  6. siliconcompiler/checklists/__init__.py +12 -0
  7. siliconcompiler/core.py +89 -22
  8. siliconcompiler/flows/__init__.py +34 -0
  9. siliconcompiler/flows/_common.py +11 -13
  10. siliconcompiler/flows/asicflow.py +83 -42
  11. siliconcompiler/flows/showflow.py +1 -1
  12. siliconcompiler/libs/__init__.py +5 -0
  13. siliconcompiler/optimizer/__init__.py +199 -0
  14. siliconcompiler/optimizer/vizier.py +259 -0
  15. siliconcompiler/pdks/__init__.py +5 -0
  16. siliconcompiler/remote/__init__.py +11 -0
  17. siliconcompiler/remote/client.py +753 -815
  18. siliconcompiler/report/report.py +2 -0
  19. siliconcompiler/report/summary_table.py +1 -1
  20. siliconcompiler/scheduler/__init__.py +118 -58
  21. siliconcompiler/scheduler/send_messages.py +1 -1
  22. siliconcompiler/schema/schema_cfg.py +16 -4
  23. siliconcompiler/schema/schema_obj.py +29 -10
  24. siliconcompiler/schema/utils.py +2 -0
  25. siliconcompiler/sphinx_ext/__init__.py +85 -0
  26. siliconcompiler/sphinx_ext/dynamicgen.py +19 -34
  27. siliconcompiler/sphinx_ext/schemagen.py +3 -2
  28. siliconcompiler/targets/__init__.py +26 -0
  29. siliconcompiler/targets/gf180_demo.py +3 -3
  30. siliconcompiler/templates/replay/replay.py.j2 +62 -0
  31. siliconcompiler/templates/replay/requirements.txt +7 -0
  32. siliconcompiler/templates/replay/setup.sh +130 -0
  33. siliconcompiler/tools/__init__.py +60 -0
  34. siliconcompiler/tools/_common/__init__.py +15 -1
  35. siliconcompiler/tools/_common/asic.py +17 -9
  36. siliconcompiler/tools/builtin/concatenate.py +1 -1
  37. siliconcompiler/tools/ghdl/ghdl.py +1 -2
  38. siliconcompiler/tools/klayout/convert_drc_db.py +1 -1
  39. siliconcompiler/tools/klayout/drc.py +1 -1
  40. siliconcompiler/tools/klayout/export.py +8 -1
  41. siliconcompiler/tools/klayout/klayout.py +2 -2
  42. siliconcompiler/tools/klayout/klayout_convert_drc_db.py +2 -2
  43. siliconcompiler/tools/klayout/klayout_export.py +7 -5
  44. siliconcompiler/tools/klayout/klayout_operations.py +4 -3
  45. siliconcompiler/tools/klayout/klayout_show.py +3 -2
  46. siliconcompiler/tools/klayout/klayout_utils.py +1 -1
  47. siliconcompiler/tools/klayout/operations.py +8 -0
  48. siliconcompiler/tools/klayout/screenshot.py +6 -1
  49. siliconcompiler/tools/klayout/show.py +8 -1
  50. siliconcompiler/tools/magic/magic.py +1 -1
  51. siliconcompiler/tools/openroad/__init__.py +103 -0
  52. siliconcompiler/tools/openroad/{openroad.py → _apr.py} +415 -423
  53. siliconcompiler/tools/openroad/antenna_repair.py +78 -0
  54. siliconcompiler/tools/openroad/clock_tree_synthesis.py +64 -0
  55. siliconcompiler/tools/openroad/detailed_placement.py +59 -0
  56. siliconcompiler/tools/openroad/detailed_route.py +62 -0
  57. siliconcompiler/tools/openroad/endcap_tapcell_insertion.py +52 -0
  58. siliconcompiler/tools/openroad/fillercell_insertion.py +58 -0
  59. siliconcompiler/tools/openroad/{dfm.py → fillmetal_insertion.py} +35 -19
  60. siliconcompiler/tools/openroad/global_placement.py +58 -0
  61. siliconcompiler/tools/openroad/global_route.py +63 -0
  62. siliconcompiler/tools/openroad/init_floorplan.py +103 -0
  63. siliconcompiler/tools/openroad/macro_placement.py +65 -0
  64. siliconcompiler/tools/openroad/metrics.py +23 -8
  65. siliconcompiler/tools/openroad/pin_placement.py +56 -0
  66. siliconcompiler/tools/openroad/power_grid.py +65 -0
  67. siliconcompiler/tools/openroad/rcx_bench.py +7 -4
  68. siliconcompiler/tools/openroad/rcx_extract.py +2 -1
  69. siliconcompiler/tools/openroad/rdlroute.py +4 -4
  70. siliconcompiler/tools/openroad/repair_design.py +59 -0
  71. siliconcompiler/tools/openroad/repair_timing.py +63 -0
  72. siliconcompiler/tools/openroad/screenshot.py +9 -20
  73. siliconcompiler/tools/openroad/scripts/apr/postamble.tcl +44 -0
  74. siliconcompiler/tools/openroad/scripts/apr/preamble.tcl +95 -0
  75. siliconcompiler/tools/openroad/scripts/apr/sc_antenna_repair.tcl +51 -0
  76. siliconcompiler/tools/openroad/scripts/apr/sc_clock_tree_synthesis.tcl +66 -0
  77. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_placement.tcl +41 -0
  78. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +71 -0
  79. siliconcompiler/tools/openroad/scripts/apr/sc_endcap_tapcell_insertion.tcl +55 -0
  80. siliconcompiler/tools/openroad/scripts/apr/sc_fillercell_insertion.tcl +27 -0
  81. siliconcompiler/tools/openroad/scripts/apr/sc_fillmetal_insertion.tcl +36 -0
  82. siliconcompiler/tools/openroad/scripts/apr/sc_global_placement.tcl +26 -0
  83. siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +61 -0
  84. siliconcompiler/tools/openroad/scripts/apr/sc_init_floorplan.tcl +333 -0
  85. siliconcompiler/tools/openroad/scripts/apr/sc_macro_placement.tcl +123 -0
  86. siliconcompiler/tools/openroad/scripts/apr/sc_metrics.tcl +22 -0
  87. siliconcompiler/tools/openroad/scripts/apr/sc_pin_placement.tcl +41 -0
  88. siliconcompiler/tools/openroad/scripts/apr/sc_power_grid.tcl +60 -0
  89. siliconcompiler/tools/openroad/scripts/apr/sc_repair_design.tcl +68 -0
  90. siliconcompiler/tools/openroad/scripts/apr/sc_repair_timing.tcl +83 -0
  91. siliconcompiler/tools/openroad/scripts/apr/sc_write_data.tcl +125 -0
  92. siliconcompiler/tools/openroad/scripts/common/debugging.tcl +28 -0
  93. siliconcompiler/tools/openroad/scripts/common/procs.tcl +727 -0
  94. siliconcompiler/tools/openroad/scripts/common/read_input_files.tcl +59 -0
  95. siliconcompiler/tools/openroad/scripts/common/read_liberty.tcl +20 -0
  96. siliconcompiler/tools/openroad/scripts/common/read_timing_constraints.tcl +16 -0
  97. siliconcompiler/tools/openroad/scripts/common/reports.tcl +180 -0
  98. siliconcompiler/tools/openroad/scripts/common/screenshot.tcl +18 -0
  99. siliconcompiler/tools/openroad/scripts/common/write_images.tcl +395 -0
  100. siliconcompiler/tools/openroad/scripts/{sc_rcx_bench.tcl → rcx/sc_rcx_bench.tcl} +5 -5
  101. siliconcompiler/tools/openroad/scripts/{sc_rcx_extract.tcl → rcx/sc_rcx_extract.tcl} +0 -0
  102. siliconcompiler/tools/openroad/scripts/sc_rcx.tcl +5 -16
  103. siliconcompiler/tools/openroad/scripts/sc_rdlroute.tcl +51 -51
  104. siliconcompiler/tools/openroad/scripts/sc_show.tcl +110 -0
  105. siliconcompiler/tools/openroad/show.py +28 -23
  106. siliconcompiler/tools/openroad/{export.py → write_data.py} +31 -26
  107. siliconcompiler/tools/opensta/__init__.py +2 -2
  108. siliconcompiler/tools/opensta/check_library.py +27 -0
  109. siliconcompiler/tools/opensta/scripts/sc_check_library.tcl +255 -0
  110. siliconcompiler/tools/opensta/scripts/sc_timing.tcl +1 -1
  111. siliconcompiler/tools/sv2v/sv2v.py +1 -2
  112. siliconcompiler/tools/verilator/verilator.py +6 -7
  113. siliconcompiler/tools/vivado/vivado.py +1 -1
  114. siliconcompiler/tools/yosys/__init__.py +149 -0
  115. siliconcompiler/tools/yosys/lec.py +22 -9
  116. siliconcompiler/tools/yosys/sc_lec.tcl +94 -49
  117. siliconcompiler/tools/yosys/sc_syn.tcl +1 -0
  118. siliconcompiler/tools/yosys/screenshot.py +2 -2
  119. siliconcompiler/tools/yosys/syn_asic.py +105 -74
  120. siliconcompiler/tools/yosys/syn_asic.tcl +58 -12
  121. siliconcompiler/tools/yosys/syn_fpga.py +2 -3
  122. siliconcompiler/tools/yosys/syn_fpga.tcl +26 -19
  123. siliconcompiler/toolscripts/_tools.json +5 -5
  124. siliconcompiler/utils/__init__.py +7 -3
  125. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.1.dist-info}/METADATA +22 -17
  126. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.1.dist-info}/RECORD +131 -114
  127. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.1.dist-info}/WHEEL +1 -1
  128. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.1.dist-info}/entry_points.txt +13 -0
  129. siliconcompiler/libs/asap7sc7p5t.py +0 -8
  130. siliconcompiler/libs/gf180mcu.py +0 -8
  131. siliconcompiler/libs/interposer.py +0 -8
  132. siliconcompiler/libs/nangate45.py +0 -8
  133. siliconcompiler/libs/sg13g2_stdcell.py +0 -8
  134. siliconcompiler/libs/sky130hd.py +0 -8
  135. siliconcompiler/libs/sky130io.py +0 -8
  136. siliconcompiler/pdks/asap7.py +0 -8
  137. siliconcompiler/pdks/freepdk45.py +0 -8
  138. siliconcompiler/pdks/gf180.py +0 -8
  139. siliconcompiler/pdks/ihp130.py +0 -8
  140. siliconcompiler/pdks/interposer.py +0 -8
  141. siliconcompiler/pdks/skywater130.py +0 -8
  142. siliconcompiler/tools/openroad/cts.py +0 -45
  143. siliconcompiler/tools/openroad/floorplan.py +0 -75
  144. siliconcompiler/tools/openroad/physyn.py +0 -27
  145. siliconcompiler/tools/openroad/place.py +0 -41
  146. siliconcompiler/tools/openroad/route.py +0 -45
  147. siliconcompiler/tools/openroad/scripts/__init__.py +0 -0
  148. siliconcompiler/tools/openroad/scripts/sc_apr.tcl +0 -514
  149. siliconcompiler/tools/openroad/scripts/sc_cts.tcl +0 -68
  150. siliconcompiler/tools/openroad/scripts/sc_dfm.tcl +0 -22
  151. siliconcompiler/tools/openroad/scripts/sc_export.tcl +0 -100
  152. siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +0 -456
  153. siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +0 -1
  154. siliconcompiler/tools/openroad/scripts/sc_physyn.tcl +0 -6
  155. siliconcompiler/tools/openroad/scripts/sc_place.tcl +0 -84
  156. siliconcompiler/tools/openroad/scripts/sc_procs.tcl +0 -494
  157. siliconcompiler/tools/openroad/scripts/sc_report.tcl +0 -189
  158. siliconcompiler/tools/openroad/scripts/sc_route.tcl +0 -143
  159. siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +0 -18
  160. siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +0 -393
  161. siliconcompiler/tools/yosys/yosys.py +0 -148
  162. /siliconcompiler/tools/openroad/scripts/{sc_write.tcl → common/write_data.tcl} +0 -0
  163. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.1.dist-info}/LICENSE +0 -0
  164. {siliconcompiler-0.28.9.dist-info → siliconcompiler-0.29.1.dist-info}/top_level.txt +0 -0
@@ -60,6 +60,8 @@ def get_flowgraph_nodes(chip, step, index):
60
60
  if value is not None:
61
61
  if key == 'inputnode':
62
62
  value = ", ".join([f'{step}{index}' for step, index in value])
63
+ if key == 'pythonpackage':
64
+ value = ", ".join(value)
63
65
  nodes[key] = str(value)
64
66
  return nodes
65
67
 
@@ -14,7 +14,7 @@ def _show_summary_table(chip, flow, flowgraph_nodes, show_all_indices):
14
14
  # Display data
15
15
  column_width = 15
16
16
 
17
- max_line_width = max(2 * column_width, int(0.95*shutil.get_terminal_size().columns))
17
+ max_line_width = max(4 * column_width, int(0.95*shutil.get_terminal_size().columns))
18
18
 
19
19
  nodes, _, metrics, metrics_unit, metrics_to_show, _ = \
20
20
  _collect_data(chip, flow, flowgraph_nodes)
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  import copy
2
3
  import distro
3
4
  import getpass
@@ -20,7 +21,7 @@ from datetime import datetime
20
21
  from siliconcompiler import sc_open
21
22
  from siliconcompiler import utils
22
23
  from siliconcompiler import _metadata
23
- from siliconcompiler.remote import client
24
+ from siliconcompiler.remote import Client
24
25
  from siliconcompiler.schema import Schema
25
26
  from siliconcompiler.scheduler import slurm
26
27
  from siliconcompiler.scheduler import docker_runner
@@ -92,6 +93,7 @@ def run(chip):
92
93
  copy_old_run_dir(chip, org_jobname)
93
94
  clean_build_dir(chip)
94
95
  _reset_flow_nodes(chip, flow, nodes_to_execute(chip, flow))
96
+ __record_packages(chip)
95
97
 
96
98
  # Save current environment
97
99
  environment = copy.deepcopy(os.environ)
@@ -101,7 +103,8 @@ def run(chip):
101
103
  os.environ[envvar] = val
102
104
 
103
105
  if chip.get('option', 'remote'):
104
- client.remote_process(chip)
106
+ client = Client(chip)
107
+ client.run()
105
108
  else:
106
109
  _local_process(chip, flow)
107
110
 
@@ -427,7 +430,7 @@ def _check_version(chip, reported_version, tool, step, index):
427
430
 
428
431
 
429
432
  ###########################################################################
430
- def _runtask(chip, flow, step, index, exec_func, replay=False):
433
+ def _runtask(chip, flow, step, index, exec_func, pipe=None, replay=False):
431
434
  '''
432
435
  Private per node run method called by run().
433
436
 
@@ -477,6 +480,9 @@ def _runtask(chip, flow, step, index, exec_func, replay=False):
477
480
  os.chdir(cwd)
478
481
  chip.schema._stop_journal()
479
482
 
483
+ if pipe:
484
+ pipe.send(chip._packages)
485
+
480
486
 
481
487
  ###########################################################################
482
488
  def _haltstep(chip, flow, step, index, log=True):
@@ -612,17 +618,19 @@ def _copy_previous_steps_output_data(chip, step, index, replay):
612
618
  os.rename(f'inputs/{outfile.name}', f'inputs/{new_name}')
613
619
 
614
620
 
615
- def __read_std_streams(chip, quiet, is_stdout_log, stdout_reader, is_stderr_log, stderr_reader):
621
+ def __read_std_streams(chip, quiet,
622
+ is_stdout_log, stdout_reader, stdout_print,
623
+ is_stderr_log, stderr_reader, stderr_print):
616
624
  '''
617
625
  Handle directing tool outputs to logger
618
626
  '''
619
627
  if not quiet:
620
628
  if is_stdout_log:
621
629
  for line in stdout_reader.readlines():
622
- chip.logger.info(line.rstrip())
630
+ stdout_print(line.rstrip())
623
631
  if is_stderr_log:
624
632
  for line in stderr_reader.readlines():
625
- chip.logger.error(line.rstrip())
633
+ stderr_print(line.rstrip())
626
634
 
627
635
 
628
636
  ############################################################################
@@ -770,36 +778,89 @@ def _makecmd(chip, tool, task, step, index, script_name='replay.sh', include_pat
770
778
  return cmdlist, print_cmd, cmd, cmd_args
771
779
 
772
780
 
781
+ def __get_stdio(chip, tool, task, flow, step, index):
782
+ def get_file(io_type):
783
+ suffix = chip.get('tool', tool, 'task', task, io_type, 'suffix',
784
+ step=step, index=index)
785
+ destination = chip.get('tool', tool, 'task', task, io_type, 'destination',
786
+ step=step, index=index)
787
+
788
+ io_file = None
789
+ if destination == 'log':
790
+ io_file = step + "." + suffix
791
+ elif destination == 'output':
792
+ io_file = os.path.join('outputs', chip.top() + "." + suffix)
793
+ elif destination == 'none':
794
+ io_file = os.devnull
795
+ else:
796
+ # This should not happen
797
+ chip.logger.error(f'{io_type}/destination has no support for {destination}.')
798
+ _haltstep(chip, flow, step, index)
799
+
800
+ return io_file
801
+
802
+ stdout_file = get_file('stdout')
803
+ stderr_file = get_file('stderr')
804
+
805
+ return stdout_file, stderr_file
806
+
807
+
773
808
  def _run_executable_or_builtin(chip, step, index, version, toolpath, workdir, run_func=None):
774
809
  '''
775
810
  Run executable (or copy inputs to outputs for builtin functions)
776
811
  '''
777
812
 
778
813
  flow = chip.get('option', 'flow')
779
- top = chip.top()
780
814
  tool, task = get_tool_task(chip, step, index, flow)
781
815
 
782
816
  quiet = (
783
- chip.get('option', 'quiet', step=step, index=index) and not
784
- chip.get('option', 'breakpoint', step=step, index=index)
817
+ chip.get('option', 'quiet', step=step, index=index) and
818
+ not chip.get('option', 'breakpoint', step=step, index=index)
785
819
  )
786
820
 
821
+ stdout_print = chip.logger.info
822
+ stderr_print = chip.logger.error
823
+ if chip.get('option', 'loglevel', step=step, index=index) == "quiet":
824
+ stdout_print = chip.logger.error
825
+ stderr_print = chip.logger.error
826
+
787
827
  # TODO: Currently no memory usage tracking in breakpoints, builtins, or unexpected errors.
788
828
  max_mem_bytes = 0
789
829
 
830
+ stdout_file, stderr_file = __get_stdio(chip, tool, task, flow, step, index)
831
+ is_stdout_log = chip.get('tool', tool, 'task', task, 'stdout', 'destination',
832
+ step=step, index=index) == 'log'
833
+ is_stderr_log = chip.get('tool', tool, 'task', task, 'stderr', 'destination',
834
+ step=step, index=index) == 'log' and stderr_file != stdout_file
835
+
790
836
  retcode = 0
791
837
  cmdlist = []
792
838
  cmd_args = []
793
839
  if run_func:
794
840
  logfile = None
795
841
  try:
796
- retcode = run_func(chip)
842
+ with open(stdout_file, 'w') as stdout_writer, \
843
+ open(stderr_file, 'w') as stderr_writer:
844
+ if stderr_file == stdout_file:
845
+ stderr_writer.close()
846
+ stderr_writer = sys.stdout
847
+
848
+ with contextlib.redirect_stderr(stderr_writer), \
849
+ contextlib.redirect_stdout(stdout_writer):
850
+ retcode = run_func(chip)
797
851
  except Exception as e:
798
852
  chip.logger.error(f'Failed in run() for {tool}/{task}: {e}')
799
853
  retcode = 1 # default to non-zero
800
854
  print_traceback(chip, e)
801
855
  chip._error = True
802
856
  finally:
857
+ with sc_open(stdout_file) as stdout_reader, \
858
+ sc_open(stderr_file) as stderr_reader:
859
+ __read_std_streams(chip,
860
+ quiet,
861
+ is_stdout_log, stdout_reader, stdout_print,
862
+ is_stderr_log, stderr_reader, stderr_print)
863
+
803
864
  try:
804
865
  if resource:
805
866
  # Since memory collection is not possible, collect the current process
@@ -838,48 +899,10 @@ def _run_executable_or_builtin(chip, step, index, version, toolpath, workdir, ru
838
899
  import pty # Note: this import throws exception on Windows
839
900
  retcode = pty.spawn(cmdlist, read)
840
901
  else:
841
- stdout_file = ''
842
- stdout_suffix = chip.get('tool', tool, 'task', task, 'stdout', 'suffix',
843
- step=step, index=index)
844
- stdout_destination = chip.get('tool', tool, 'task', task, 'stdout', 'destination',
845
- step=step, index=index)
846
- if stdout_destination == 'log':
847
- stdout_file = step + "." + stdout_suffix
848
- elif stdout_destination == 'output':
849
- stdout_file = os.path.join('outputs', top + "." + stdout_suffix)
850
- elif stdout_destination == 'none':
851
- stdout_file = os.devnull
852
- else:
853
- chip.logger.error(f'stdout/destination has no support for {stdout_destination}. '
854
- 'Use [log|output|none].')
855
- _haltstep(chip, flow, step, index)
856
-
857
- stderr_file = ''
858
- stderr_suffix = chip.get('tool', tool, 'task', task, 'stderr', 'suffix',
859
- step=step, index=index)
860
- stderr_destination = chip.get('tool', tool, 'task', task, 'stderr', 'destination',
861
- step=step, index=index)
862
- if stderr_destination == 'log':
863
- stderr_file = step + "." + stderr_suffix
864
- elif stderr_destination == 'output':
865
- stderr_file = os.path.join('outputs', top + "." + stderr_suffix)
866
- elif stderr_destination == 'none':
867
- stderr_file = os.devnull
868
- else:
869
- chip.logger.error(f'stderr/destination has no support for {stderr_destination}. '
870
- 'Use [log|output|none].')
871
- _haltstep(chip, flow, step, index)
872
-
873
902
  with open(stdout_file, 'w') as stdout_writer, \
874
903
  open(stdout_file, 'r', errors='replace_with_warning') as stdout_reader, \
875
904
  open(stderr_file, 'w') as stderr_writer, \
876
905
  open(stderr_file, 'r', errors='replace_with_warning') as stderr_reader:
877
- # Use separate reader/writer file objects as hack to display
878
- # live output in non-blocking way, so we can monitor the
879
- # timeout. Based on https://stackoverflow.com/a/18422264.
880
- is_stdout_log = chip.get('tool', tool, 'task', task, 'stdout', 'destination',
881
- step=step, index=index) == 'log'
882
- is_stderr_log = stderr_destination == 'log' and stderr_file != stdout_file
883
906
  # if STDOUT and STDERR are to be redirected to the same file,
884
907
  # use a single writer
885
908
  if stderr_file == stdout_file:
@@ -937,8 +960,8 @@ def _run_executable_or_builtin(chip, step, index, version, toolpath, workdir, ru
937
960
  # Loop until process terminates
938
961
  __read_std_streams(chip,
939
962
  quiet,
940
- is_stdout_log, stdout_reader,
941
- is_stderr_log, stderr_reader)
963
+ is_stdout_log, stdout_reader, stdout_print,
964
+ is_stderr_log, stderr_reader, stderr_print)
942
965
 
943
966
  if timeout is not None and time.time() - cmd_start_time > timeout:
944
967
  chip.logger.error(f'Step timed out after {timeout} seconds')
@@ -956,8 +979,8 @@ def _run_executable_or_builtin(chip, step, index, version, toolpath, workdir, ru
956
979
  # Read the remaining
957
980
  __read_std_streams(chip,
958
981
  quiet,
959
- is_stdout_log, stdout_reader,
960
- is_stderr_log, stderr_reader)
982
+ is_stdout_log, stdout_reader, stdout_print,
983
+ is_stderr_log, stderr_reader, stderr_print)
961
984
  retcode = proc.returncode
962
985
 
963
986
  chip.set('record', 'toolexitcode', retcode, step=step, index=index)
@@ -1389,7 +1412,10 @@ def _reset_flow_nodes(chip, flow, nodes_to_execute):
1389
1412
  for metric in chip.getkeys('metric'):
1390
1413
  _clear_metric(chip, step, index, metric)
1391
1414
  for record in chip.getkeys('record'):
1392
- _clear_record(chip, step, index, record, preserve=['remoteid', 'status'])
1415
+ _clear_record(chip, step, index, record, preserve=[
1416
+ 'remoteid',
1417
+ 'status',
1418
+ 'pythonpackage'])
1393
1419
 
1394
1420
  # Mark all nodes as pending
1395
1421
  for step, index in _get_flowgraph_nodes(chip, flow):
@@ -1464,8 +1490,18 @@ def _prepare_nodes(chip, nodes_to_run, processes, local_processes, flow):
1464
1490
  else:
1465
1491
  local_processes.append((step, index))
1466
1492
 
1467
- processes[node] = multiprocessing.Process(target=_runtask,
1468
- args=(chip, flow, step, index, exec_func))
1493
+ process = {
1494
+ "child_pipe": None,
1495
+ "parent_pipe": None,
1496
+ "proc": None
1497
+ }
1498
+ process["parent_pipe"], process["child_pipe"] = multiprocessing.Pipe()
1499
+ process["proc"] = multiprocessing.Process(
1500
+ target=_runtask,
1501
+ args=(chip, flow, step, index, exec_func),
1502
+ kwargs={"pipe": process["child_pipe"]})
1503
+
1504
+ processes[node] = process
1469
1505
 
1470
1506
  for init_func in init_funcs:
1471
1507
  init_func(chip)
@@ -1563,7 +1599,7 @@ def _launch_nodes(chip, nodes_to_run, processes, local_processes):
1563
1599
  chip.set('record', 'status', NodeStatus.RUNNING, step=node[0], index=node[1])
1564
1600
  changed = True
1565
1601
 
1566
- processes[node].start()
1602
+ processes[node]["proc"].start()
1567
1603
  del nodes_to_run[node]
1568
1604
  running_nodes[node] = requested_threads
1569
1605
 
@@ -1586,7 +1622,7 @@ def _launch_nodes(chip, nodes_to_run, processes, local_processes):
1586
1622
  def _process_completed_nodes(chip, processes, running_nodes):
1587
1623
  changed = False
1588
1624
  for node in list(running_nodes.keys()):
1589
- if not processes[node].is_alive():
1625
+ if not processes[node]["proc"].is_alive():
1590
1626
  step, index = node
1591
1627
  manifest = os.path.join(chip.getworkdir(step=step, index=index),
1592
1628
  'outputs',
@@ -1595,8 +1631,16 @@ def _process_completed_nodes(chip, processes, running_nodes):
1595
1631
  if os.path.exists(manifest):
1596
1632
  chip.schema.read_journal(manifest)
1597
1633
 
1634
+ if processes[node]["parent_pipe"] and processes[node]["parent_pipe"].poll(1):
1635
+ try:
1636
+ packages = processes[node]["parent_pipe"].recv()
1637
+ if isinstance(packages, dict):
1638
+ chip._packages.update(packages)
1639
+ except: # noqa E722
1640
+ pass
1641
+
1598
1642
  del running_nodes[node]
1599
- if processes[node].exitcode > 0:
1643
+ if processes[node]["proc"].exitcode > 0:
1600
1644
  status = NodeStatus.ERROR
1601
1645
  else:
1602
1646
  status = chip.get('record', 'status', step=step, index=index)
@@ -1627,6 +1671,22 @@ def _check_nodes_status(chip, flow):
1627
1671
  #######################################
1628
1672
  def __record_version(chip, step, index):
1629
1673
  chip.set('record', 'scversion', _metadata.version, step=step, index=index)
1674
+ chip.set('record', 'pythonversion', platform.python_version(), step=step, index=index)
1675
+
1676
+
1677
+ #######################################
1678
+ def __record_packages(chip):
1679
+ try:
1680
+ from pip._internal.operations.freeze import freeze
1681
+ except: # noqa E722
1682
+ freeze = None
1683
+
1684
+ if freeze:
1685
+ # clear record
1686
+ chip.set('record', 'pythonpackage', [])
1687
+
1688
+ for pkg in freeze():
1689
+ chip.add('record', 'pythonpackage', pkg)
1630
1690
 
1631
1691
 
1632
1692
  #######################################
@@ -12,7 +12,6 @@ import fastjsonschema
12
12
  from pathlib import Path
13
13
  from siliconcompiler.flowgraph import get_executed_nodes
14
14
  import uuid
15
- from siliconcompiler.targets import freepdk45_demo
16
15
 
17
16
 
18
17
  # Compile validation code for API request bodies.
@@ -176,6 +175,7 @@ def send(chip, msg_type, step, index):
176
175
 
177
176
  if __name__ == "__main__":
178
177
  from siliconcompiler import Chip
178
+ from siliconcompiler.targets import freepdk45_demo
179
179
  chip = Chip('test')
180
180
  chip.use(freepdk45_demo)
181
181
  chip.set('option', 'scheduler', 'msgevent', 'ALL')
@@ -10,7 +10,7 @@ try:
10
10
  except ImportError:
11
11
  from siliconcompiler.schema.utils import trim
12
12
 
13
- SCHEMA_VERSION = '0.48.4'
13
+ SCHEMA_VERSION = '0.48.6'
14
14
 
15
15
  #############################################################################
16
16
  # PARAM DEFINITION
@@ -2482,6 +2482,9 @@ def schema_record(cfg, step='default', index='default'):
2482
2482
  'toolargs': ['tool CLI arguments',
2483
2483
  '-I include/ foo.v',
2484
2484
  'Arguments passed to tool via CLI.'],
2485
+ 'pythonversion': ['Python version',
2486
+ '3.12.3',
2487
+ """Version of python used to run this task."""],
2485
2488
  'osversion': ['O/S version',
2486
2489
  '20.04.1-Ubuntu',
2487
2490
  """Since there is not standard version system for operating
@@ -2515,16 +2518,25 @@ def schema_record(cfg, step='default', index='default'):
2515
2518
  pernode='required',
2516
2519
  schelp='Record tracking the tool exit code per step and index basis.')
2517
2520
 
2518
- # Unlike most other 'record' fields, job ID is not set per-node.
2521
+ # Non-per-node records.
2519
2522
  scparam(cfg, ['record', 'remoteid'],
2520
2523
  sctype='str',
2521
2524
  shorthelp="Record: remote job ID",
2522
- switch="-record_remoteid 'step index <str>'",
2525
+ switch="-record_remoteid '<str>'",
2523
2526
  example=[
2524
2527
  "cli: -record_remoteid '0123456789abcdeffedcba9876543210'",
2525
2528
  "api: chip.set('record', 'remoteid', '0123456789abcdeffedcba9876543210')"],
2526
2529
  schelp='Record tracking the job ID for a remote run.')
2527
2530
 
2531
+ scparam(cfg, ['record', 'pythonpackage'],
2532
+ sctype='[str]',
2533
+ shorthelp="Record: python packages",
2534
+ switch="-record_pythonpackage '<str>'",
2535
+ example=[
2536
+ "cli: -record_pythonpackage 'siliconcompiler==0.28.0'",
2537
+ "api: chip.set('record', 'pythonpackage', 'siliconcompiler==0.28.0')"],
2538
+ schelp='Record tracking for the python packages installed.')
2539
+
2528
2540
  # flowgraph status
2529
2541
  scparam(cfg, ['record', 'status'],
2530
2542
  sctype='enum',
@@ -2760,7 +2772,7 @@ def schema_option(cfg):
2760
2772
 
2761
2773
  scparam(cfg, ['option', 'loglevel'],
2762
2774
  sctype='enum',
2763
- enum=["info", "warning", "error", "critical", "debug"],
2775
+ enum=["info", "warning", "error", "critical", "debug", "quiet"],
2764
2776
  pernode='optional',
2765
2777
  scope='job',
2766
2778
  defvalue='info',
@@ -506,6 +506,22 @@ class Schema:
506
506
  else:
507
507
  self.set(*key, values, step=step, index=index)
508
508
 
509
+ ###########################################################################
510
+ def copy_key(self, src, dst):
511
+ '''
512
+ Copy a parameters information from the source keypath to the destination
513
+ keypath.
514
+
515
+ Args:
516
+ src (list): Key to use as source.
517
+ dst (list): Key to use as destination
518
+ '''
519
+
520
+ data = self.getdict(*src)
521
+
522
+ cfg = self.__search(*dst[0:-1], insert_defaults=True)
523
+ cfg[dst[-1]] = data
524
+
509
525
  ###########################################################################
510
526
  def remove(self, *keypath):
511
527
  '''
@@ -1495,7 +1511,7 @@ class Schema:
1495
1511
  switchstrs, metavar = self.__get_switches(schema, *keypath)
1496
1512
 
1497
1513
  # Three switch types (bool, list, scalar)
1498
- if not switchlist or any(switch in switchlist for switch in switchstrs):
1514
+ if switchlist is None or any(switch in switchlist for switch in switchstrs):
1499
1515
  used_switches.update(switchstrs)
1500
1516
  if typestr == 'bool':
1501
1517
  # Boolean type arguments
@@ -1590,7 +1606,18 @@ class Schema:
1590
1606
  # Grab argument from pre-process sysargs
1591
1607
  cmdargs = vars(parser.parse_args(scargs))
1592
1608
 
1593
- if print_banner:
1609
+ # Set loglevel if set at command line
1610
+ do_print_banner = True
1611
+ if 'option_loglevel' in cmdargs.keys():
1612
+ log_level = cmdargs['option_loglevel']
1613
+ if isinstance(log_level, list):
1614
+ # if multiple found, pick the first one
1615
+ log_level = log_level[0]
1616
+ if log_level == 'quiet':
1617
+ do_print_banner = False
1618
+ logger.setLevel(translate_loglevel(log_level).split()[-1])
1619
+
1620
+ if print_banner and do_print_banner:
1594
1621
  print_banner()
1595
1622
 
1596
1623
  extra_params = None
@@ -1607,14 +1634,6 @@ class Schema:
1607
1634
  # Remove from cmdargs
1608
1635
  del cmdargs[arg]
1609
1636
 
1610
- # Set loglevel if set at command line
1611
- if 'option_loglevel' in cmdargs.keys():
1612
- log_level = cmdargs['option_loglevel']
1613
- if isinstance(log_level, list):
1614
- # if multiple found, pick the first one
1615
- log_level = log_level[0]
1616
- logger.setLevel(translate_loglevel(log_level).split()[-1])
1617
-
1618
1637
  # Read in all cfg files
1619
1638
  if 'option_cfg' in cmdargs.keys():
1620
1639
  for item in cmdargs['option_cfg']:
@@ -90,4 +90,6 @@ def trim(docstring):
90
90
 
91
91
 
92
92
  def translate_loglevel(level):
93
+ if level == "quiet":
94
+ level = "error"
93
95
  return level.upper()
@@ -0,0 +1,85 @@
1
+ import os.path
2
+
3
+ import siliconcompiler
4
+ from siliconcompiler import __version__ as sc_version
5
+
6
+ from siliconcompiler.targets import get_targets
7
+ from siliconcompiler.flows import get_flows
8
+ from siliconcompiler.checklists import get_checklists
9
+ from siliconcompiler.libs import get_libs
10
+ from siliconcompiler.pdks import get_pdks
11
+ from siliconcompiler.apps import get_apps
12
+ from siliconcompiler.tools import get_tools
13
+
14
+
15
+ sc_root = os.path.dirname(os.path.dirname(os.path.abspath(siliconcompiler.__file__)))
16
+
17
+
18
+ def relpath(file):
19
+ file = os.path.abspath(file)
20
+ if file.startswith(sc_root):
21
+ return os.path.relpath(file, sc_root)
22
+ return None
23
+
24
+
25
+ def get_codeurl(file=None):
26
+ base_url = f"https://github.com/siliconcompiler/siliconcompiler/blob/v{sc_version}"
27
+
28
+ if not file:
29
+ return base_url
30
+
31
+ if os.path.isabs(file):
32
+ file = relpath(file)
33
+ if not file:
34
+ return None
35
+
36
+ return f"{base_url}/{file}"
37
+
38
+
39
+ def targets():
40
+ modules = []
41
+ for name, mod in get_targets().items():
42
+ modules.append((mod, name))
43
+ return modules
44
+
45
+
46
+ def flows():
47
+ modules = []
48
+ for name, mod in get_flows().items():
49
+ modules.append((mod, name))
50
+ return modules
51
+
52
+
53
+ def libraries():
54
+ modules = []
55
+ for name, mod in get_libs().items():
56
+ modules.append((mod, name))
57
+ return modules
58
+
59
+
60
+ def pdks():
61
+ modules = []
62
+ for name, mod in get_pdks().items():
63
+ modules.append((mod, name))
64
+ return modules
65
+
66
+
67
+ def tools():
68
+ modules = []
69
+ for name, mod in get_tools().items():
70
+ modules.append((mod, name))
71
+ return modules
72
+
73
+
74
+ def apps():
75
+ modules = []
76
+ for name, mod in get_apps().items():
77
+ modules.append((mod, name))
78
+ return modules
79
+
80
+
81
+ def checklists():
82
+ modules = []
83
+ for name, mod in get_checklists().items():
84
+ modules.append((mod, name))
85
+ return modules