siliconcompiler 0.26.5__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 (251) hide show
  1. siliconcompiler/__init__.py +24 -0
  2. siliconcompiler/__main__.py +12 -0
  3. siliconcompiler/_common.py +49 -0
  4. siliconcompiler/_metadata.py +36 -0
  5. siliconcompiler/apps/__init__.py +0 -0
  6. siliconcompiler/apps/_common.py +76 -0
  7. siliconcompiler/apps/sc.py +92 -0
  8. siliconcompiler/apps/sc_dashboard.py +94 -0
  9. siliconcompiler/apps/sc_issue.py +178 -0
  10. siliconcompiler/apps/sc_remote.py +199 -0
  11. siliconcompiler/apps/sc_server.py +39 -0
  12. siliconcompiler/apps/sc_show.py +142 -0
  13. siliconcompiler/apps/smake.py +232 -0
  14. siliconcompiler/checklists/__init__.py +0 -0
  15. siliconcompiler/checklists/oh_tapeout.py +41 -0
  16. siliconcompiler/core.py +3221 -0
  17. siliconcompiler/data/RobotoMono/LICENSE.txt +202 -0
  18. siliconcompiler/data/RobotoMono/RobotoMono-Regular.ttf +0 -0
  19. siliconcompiler/data/heartbeat.v +18 -0
  20. siliconcompiler/data/logo.png +0 -0
  21. siliconcompiler/flowgraph.py +570 -0
  22. siliconcompiler/flows/__init__.py +0 -0
  23. siliconcompiler/flows/_common.py +67 -0
  24. siliconcompiler/flows/asicflow.py +180 -0
  25. siliconcompiler/flows/asictopflow.py +38 -0
  26. siliconcompiler/flows/dvflow.py +86 -0
  27. siliconcompiler/flows/fpgaflow.py +202 -0
  28. siliconcompiler/flows/generate_openroad_rcx.py +66 -0
  29. siliconcompiler/flows/lintflow.py +35 -0
  30. siliconcompiler/flows/screenshotflow.py +51 -0
  31. siliconcompiler/flows/showflow.py +59 -0
  32. siliconcompiler/flows/signoffflow.py +53 -0
  33. siliconcompiler/flows/synflow.py +128 -0
  34. siliconcompiler/fpgas/__init__.py +0 -0
  35. siliconcompiler/fpgas/lattice_ice40.py +42 -0
  36. siliconcompiler/fpgas/vpr_example.py +109 -0
  37. siliconcompiler/issue.py +300 -0
  38. siliconcompiler/libs/__init__.py +0 -0
  39. siliconcompiler/libs/asap7sc7p5t.py +8 -0
  40. siliconcompiler/libs/gf180mcu.py +8 -0
  41. siliconcompiler/libs/nangate45.py +8 -0
  42. siliconcompiler/libs/sky130hd.py +8 -0
  43. siliconcompiler/libs/sky130io.py +8 -0
  44. siliconcompiler/package.py +412 -0
  45. siliconcompiler/pdks/__init__.py +0 -0
  46. siliconcompiler/pdks/asap7.py +8 -0
  47. siliconcompiler/pdks/freepdk45.py +8 -0
  48. siliconcompiler/pdks/gf180.py +8 -0
  49. siliconcompiler/pdks/skywater130.py +8 -0
  50. siliconcompiler/remote/__init__.py +36 -0
  51. siliconcompiler/remote/client.py +891 -0
  52. siliconcompiler/remote/schema.py +106 -0
  53. siliconcompiler/remote/server.py +507 -0
  54. siliconcompiler/remote/server_schema/requests/cancel_job.json +51 -0
  55. siliconcompiler/remote/server_schema/requests/check_progress.json +61 -0
  56. siliconcompiler/remote/server_schema/requests/check_server.json +38 -0
  57. siliconcompiler/remote/server_schema/requests/delete_job.json +51 -0
  58. siliconcompiler/remote/server_schema/requests/get_results.json +48 -0
  59. siliconcompiler/remote/server_schema/requests/remote_run.json +40 -0
  60. siliconcompiler/remote/server_schema/responses/cancel_job.json +18 -0
  61. siliconcompiler/remote/server_schema/responses/check_progress.json +30 -0
  62. siliconcompiler/remote/server_schema/responses/check_server.json +32 -0
  63. siliconcompiler/remote/server_schema/responses/delete_job.json +18 -0
  64. siliconcompiler/remote/server_schema/responses/get_results.json +21 -0
  65. siliconcompiler/remote/server_schema/responses/remote_run.json +25 -0
  66. siliconcompiler/report/__init__.py +13 -0
  67. siliconcompiler/report/html_report.py +74 -0
  68. siliconcompiler/report/report.py +355 -0
  69. siliconcompiler/report/streamlit_report.py +137 -0
  70. siliconcompiler/report/streamlit_viewer.py +944 -0
  71. siliconcompiler/report/summary_image.py +117 -0
  72. siliconcompiler/report/summary_table.py +105 -0
  73. siliconcompiler/report/utils.py +163 -0
  74. siliconcompiler/scheduler/__init__.py +2092 -0
  75. siliconcompiler/scheduler/docker_runner.py +253 -0
  76. siliconcompiler/scheduler/run_node.py +138 -0
  77. siliconcompiler/scheduler/send_messages.py +178 -0
  78. siliconcompiler/scheduler/slurm.py +208 -0
  79. siliconcompiler/scheduler/validation/email_credentials.json +54 -0
  80. siliconcompiler/schema/__init__.py +7 -0
  81. siliconcompiler/schema/schema_cfg.py +4014 -0
  82. siliconcompiler/schema/schema_obj.py +1841 -0
  83. siliconcompiler/schema/utils.py +93 -0
  84. siliconcompiler/sphinx_ext/__init__.py +0 -0
  85. siliconcompiler/sphinx_ext/dynamicgen.py +1006 -0
  86. siliconcompiler/sphinx_ext/schemagen.py +221 -0
  87. siliconcompiler/sphinx_ext/utils.py +166 -0
  88. siliconcompiler/targets/__init__.py +0 -0
  89. siliconcompiler/targets/asap7_demo.py +68 -0
  90. siliconcompiler/targets/asic_demo.py +38 -0
  91. siliconcompiler/targets/fpgaflow_demo.py +47 -0
  92. siliconcompiler/targets/freepdk45_demo.py +59 -0
  93. siliconcompiler/targets/gf180_demo.py +77 -0
  94. siliconcompiler/targets/skywater130_demo.py +70 -0
  95. siliconcompiler/templates/email/general.j2 +66 -0
  96. siliconcompiler/templates/email/summary.j2 +43 -0
  97. siliconcompiler/templates/issue/README.txt +26 -0
  98. siliconcompiler/templates/issue/run.sh +6 -0
  99. siliconcompiler/templates/report/bootstrap.min.css +7 -0
  100. siliconcompiler/templates/report/bootstrap.min.js +7 -0
  101. siliconcompiler/templates/report/bootstrap_LICENSE.md +24 -0
  102. siliconcompiler/templates/report/sc_report.j2 +427 -0
  103. siliconcompiler/templates/slurm/run.sh +9 -0
  104. siliconcompiler/templates/tcl/manifest.tcl.j2 +137 -0
  105. siliconcompiler/tools/__init__.py +0 -0
  106. siliconcompiler/tools/_common/__init__.py +432 -0
  107. siliconcompiler/tools/_common/asic.py +115 -0
  108. siliconcompiler/tools/_common/sdc/sc_constraints.sdc +76 -0
  109. siliconcompiler/tools/_common/tcl/sc_pin_constraints.tcl +63 -0
  110. siliconcompiler/tools/bambu/bambu.py +32 -0
  111. siliconcompiler/tools/bambu/convert.py +77 -0
  112. siliconcompiler/tools/bluespec/bluespec.py +40 -0
  113. siliconcompiler/tools/bluespec/convert.py +103 -0
  114. siliconcompiler/tools/builtin/_common.py +155 -0
  115. siliconcompiler/tools/builtin/builtin.py +26 -0
  116. siliconcompiler/tools/builtin/concatenate.py +85 -0
  117. siliconcompiler/tools/builtin/join.py +27 -0
  118. siliconcompiler/tools/builtin/maximum.py +46 -0
  119. siliconcompiler/tools/builtin/minimum.py +57 -0
  120. siliconcompiler/tools/builtin/mux.py +70 -0
  121. siliconcompiler/tools/builtin/nop.py +38 -0
  122. siliconcompiler/tools/builtin/verify.py +83 -0
  123. siliconcompiler/tools/chisel/SCDriver.scala +10 -0
  124. siliconcompiler/tools/chisel/build.sbt +27 -0
  125. siliconcompiler/tools/chisel/chisel.py +37 -0
  126. siliconcompiler/tools/chisel/convert.py +140 -0
  127. siliconcompiler/tools/execute/exec_input.py +41 -0
  128. siliconcompiler/tools/execute/execute.py +17 -0
  129. siliconcompiler/tools/genfasm/bitstream.py +61 -0
  130. siliconcompiler/tools/genfasm/genfasm.py +40 -0
  131. siliconcompiler/tools/ghdl/convert.py +87 -0
  132. siliconcompiler/tools/ghdl/ghdl.py +41 -0
  133. siliconcompiler/tools/icarus/compile.py +87 -0
  134. siliconcompiler/tools/icarus/icarus.py +36 -0
  135. siliconcompiler/tools/icepack/bitstream.py +20 -0
  136. siliconcompiler/tools/icepack/icepack.py +43 -0
  137. siliconcompiler/tools/klayout/export.py +117 -0
  138. siliconcompiler/tools/klayout/klayout.py +119 -0
  139. siliconcompiler/tools/klayout/klayout_export.py +205 -0
  140. siliconcompiler/tools/klayout/klayout_operations.py +363 -0
  141. siliconcompiler/tools/klayout/klayout_show.py +242 -0
  142. siliconcompiler/tools/klayout/klayout_utils.py +176 -0
  143. siliconcompiler/tools/klayout/operations.py +194 -0
  144. siliconcompiler/tools/klayout/screenshot.py +98 -0
  145. siliconcompiler/tools/klayout/show.py +101 -0
  146. siliconcompiler/tools/magic/drc.py +49 -0
  147. siliconcompiler/tools/magic/extspice.py +19 -0
  148. siliconcompiler/tools/magic/magic.py +85 -0
  149. siliconcompiler/tools/magic/sc_drc.tcl +96 -0
  150. siliconcompiler/tools/magic/sc_extspice.tcl +54 -0
  151. siliconcompiler/tools/magic/sc_magic.tcl +47 -0
  152. siliconcompiler/tools/montage/montage.py +30 -0
  153. siliconcompiler/tools/montage/tile.py +66 -0
  154. siliconcompiler/tools/netgen/count_lvs.py +132 -0
  155. siliconcompiler/tools/netgen/lvs.py +90 -0
  156. siliconcompiler/tools/netgen/netgen.py +36 -0
  157. siliconcompiler/tools/netgen/sc_lvs.tcl +46 -0
  158. siliconcompiler/tools/nextpnr/apr.py +24 -0
  159. siliconcompiler/tools/nextpnr/nextpnr.py +59 -0
  160. siliconcompiler/tools/openfpgaloader/openfpgaloader.py +39 -0
  161. siliconcompiler/tools/openroad/__init__.py +0 -0
  162. siliconcompiler/tools/openroad/cts.py +45 -0
  163. siliconcompiler/tools/openroad/dfm.py +66 -0
  164. siliconcompiler/tools/openroad/export.py +131 -0
  165. siliconcompiler/tools/openroad/floorplan.py +70 -0
  166. siliconcompiler/tools/openroad/openroad.py +977 -0
  167. siliconcompiler/tools/openroad/physyn.py +27 -0
  168. siliconcompiler/tools/openroad/place.py +41 -0
  169. siliconcompiler/tools/openroad/rcx_bench.py +95 -0
  170. siliconcompiler/tools/openroad/rcx_extract.py +34 -0
  171. siliconcompiler/tools/openroad/route.py +45 -0
  172. siliconcompiler/tools/openroad/screenshot.py +60 -0
  173. siliconcompiler/tools/openroad/scripts/sc_apr.tcl +499 -0
  174. siliconcompiler/tools/openroad/scripts/sc_cts.tcl +64 -0
  175. siliconcompiler/tools/openroad/scripts/sc_dfm.tcl +20 -0
  176. siliconcompiler/tools/openroad/scripts/sc_export.tcl +98 -0
  177. siliconcompiler/tools/openroad/scripts/sc_floorplan.tcl +413 -0
  178. siliconcompiler/tools/openroad/scripts/sc_metrics.tcl +158 -0
  179. siliconcompiler/tools/openroad/scripts/sc_physyn.tcl +7 -0
  180. siliconcompiler/tools/openroad/scripts/sc_place.tcl +84 -0
  181. siliconcompiler/tools/openroad/scripts/sc_procs.tcl +423 -0
  182. siliconcompiler/tools/openroad/scripts/sc_rcx.tcl +63 -0
  183. siliconcompiler/tools/openroad/scripts/sc_rcx_bench.tcl +20 -0
  184. siliconcompiler/tools/openroad/scripts/sc_rcx_extract.tcl +12 -0
  185. siliconcompiler/tools/openroad/scripts/sc_route.tcl +133 -0
  186. siliconcompiler/tools/openroad/scripts/sc_screenshot.tcl +21 -0
  187. siliconcompiler/tools/openroad/scripts/sc_write.tcl +5 -0
  188. siliconcompiler/tools/openroad/scripts/sc_write_images.tcl +361 -0
  189. siliconcompiler/tools/openroad/show.py +94 -0
  190. siliconcompiler/tools/openroad/templates/pex.tcl +8 -0
  191. siliconcompiler/tools/opensta/__init__.py +101 -0
  192. siliconcompiler/tools/opensta/report_libraries.py +28 -0
  193. siliconcompiler/tools/opensta/scripts/sc_procs.tcl +47 -0
  194. siliconcompiler/tools/opensta/scripts/sc_report_libraries.tcl +74 -0
  195. siliconcompiler/tools/opensta/scripts/sc_timing.tcl +268 -0
  196. siliconcompiler/tools/opensta/timing.py +214 -0
  197. siliconcompiler/tools/slang/__init__.py +49 -0
  198. siliconcompiler/tools/slang/lint.py +101 -0
  199. siliconcompiler/tools/surelog/__init__.py +123 -0
  200. siliconcompiler/tools/surelog/parse.py +183 -0
  201. siliconcompiler/tools/surelog/templates/output.v +7 -0
  202. siliconcompiler/tools/sv2v/convert.py +46 -0
  203. siliconcompiler/tools/sv2v/sv2v.py +37 -0
  204. siliconcompiler/tools/template/template.py +125 -0
  205. siliconcompiler/tools/verilator/compile.py +139 -0
  206. siliconcompiler/tools/verilator/lint.py +19 -0
  207. siliconcompiler/tools/verilator/parse.py +27 -0
  208. siliconcompiler/tools/verilator/verilator.py +172 -0
  209. siliconcompiler/tools/vivado/__init__.py +7 -0
  210. siliconcompiler/tools/vivado/bitstream.py +21 -0
  211. siliconcompiler/tools/vivado/place.py +21 -0
  212. siliconcompiler/tools/vivado/route.py +21 -0
  213. siliconcompiler/tools/vivado/scripts/sc_bitstream.tcl +6 -0
  214. siliconcompiler/tools/vivado/scripts/sc_place.tcl +2 -0
  215. siliconcompiler/tools/vivado/scripts/sc_route.tcl +4 -0
  216. siliconcompiler/tools/vivado/scripts/sc_run.tcl +45 -0
  217. siliconcompiler/tools/vivado/scripts/sc_syn_fpga.tcl +25 -0
  218. siliconcompiler/tools/vivado/syn_fpga.py +20 -0
  219. siliconcompiler/tools/vivado/vivado.py +147 -0
  220. siliconcompiler/tools/vpr/_json_constraint.py +63 -0
  221. siliconcompiler/tools/vpr/_xml_constraint.py +109 -0
  222. siliconcompiler/tools/vpr/place.py +137 -0
  223. siliconcompiler/tools/vpr/route.py +124 -0
  224. siliconcompiler/tools/vpr/screenshot.py +54 -0
  225. siliconcompiler/tools/vpr/show.py +88 -0
  226. siliconcompiler/tools/vpr/vpr.py +357 -0
  227. siliconcompiler/tools/xyce/xyce.py +36 -0
  228. siliconcompiler/tools/yosys/lec.py +56 -0
  229. siliconcompiler/tools/yosys/prepareLib.py +59 -0
  230. siliconcompiler/tools/yosys/sc_lec.tcl +84 -0
  231. siliconcompiler/tools/yosys/sc_syn.tcl +79 -0
  232. siliconcompiler/tools/yosys/syn_asic.py +565 -0
  233. siliconcompiler/tools/yosys/syn_asic.tcl +377 -0
  234. siliconcompiler/tools/yosys/syn_asic_fpga_shared.tcl +31 -0
  235. siliconcompiler/tools/yosys/syn_fpga.py +146 -0
  236. siliconcompiler/tools/yosys/syn_fpga.tcl +233 -0
  237. siliconcompiler/tools/yosys/syn_strategies.tcl +81 -0
  238. siliconcompiler/tools/yosys/techmaps/lcu_kogge_stone.v +39 -0
  239. siliconcompiler/tools/yosys/templates/abc.const +2 -0
  240. siliconcompiler/tools/yosys/yosys.py +147 -0
  241. siliconcompiler/units.py +259 -0
  242. siliconcompiler/use.py +177 -0
  243. siliconcompiler/utils/__init__.py +423 -0
  244. siliconcompiler/utils/asic.py +158 -0
  245. siliconcompiler/utils/showtools.py +25 -0
  246. siliconcompiler-0.26.5.dist-info/LICENSE +190 -0
  247. siliconcompiler-0.26.5.dist-info/METADATA +195 -0
  248. siliconcompiler-0.26.5.dist-info/RECORD +251 -0
  249. siliconcompiler-0.26.5.dist-info/WHEEL +5 -0
  250. siliconcompiler-0.26.5.dist-info/entry_points.txt +12 -0
  251. siliconcompiler-0.26.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,355 @@
1
+ import pandas
2
+ import os
3
+ from siliconcompiler import Schema
4
+ from siliconcompiler.report import utils
5
+ from siliconcompiler.flowgraph import nodes_to_execute
6
+ from siliconcompiler.tools._common import get_tool_task
7
+
8
+
9
+ def make_metric_dataframe(chip):
10
+ '''
11
+ Returns a pandas dataframe to display in the data metrics table. All nodes
12
+ (steps and indices) are included on the x-axis while the metrics tracked
13
+ are on the y-axis. The y-axis row headers are in the form of a tuple where
14
+ the first element is the metric tracked and the second element is the unit.
15
+
16
+ Args:
17
+ chip (Chip) : The chip object that contains the schema read from.
18
+
19
+ Example:
20
+ >>> make_metric_dataframe(chip)
21
+ Returns pandas dataframe of tracked metrics.
22
+ '''
23
+ nodes, errors, metrics, metrics_unit, metrics_to_show, reports = utils._collect_data(chip)
24
+ # converts from 2d dictionary to pandas DataFrame, transposes so
25
+ # orientation is correct, and filters based on the metrics we track
26
+ data = (pandas.DataFrame.from_dict(metrics, orient='index').transpose())
27
+ data = data.loc[metrics_to_show]
28
+ # include metrics_unit
29
+ data.index = data.index.map(lambda x: (x, metrics_unit[x]))
30
+ return data
31
+
32
+
33
+ def get_flowgraph_nodes(chip, step, index):
34
+ '''
35
+ Returns a dictionary to display in the data metrics table. One node
36
+ (step and index) is included on the x-axis while all the metrics tracked
37
+ are on the y-axis. Removes all key value pairs where the value is None.
38
+
39
+ Args:
40
+ chip (Chip) : The chip object that contains the schema read from.
41
+ step (string) : Step of node.
42
+ index (string) : Index of node.
43
+
44
+ Example:
45
+ >>> get_flowgraph_nodes(chip, [(import, 0), (syn, 0)])
46
+ Returns pandas dataframe of tracked metrics.
47
+ '''
48
+ nodes = {}
49
+ tool, task = get_tool_task(chip, step, index)
50
+ if tool is not None:
51
+ nodes['tool'] = tool
52
+ if task is not None:
53
+ nodes['task'] = task
54
+ for key in chip.getkeys('record'):
55
+ if chip.get('record', key, field='pernode') == 'never':
56
+ value = chip.get('record', key)
57
+ else:
58
+ value = chip.get('record', key, step=step, index=index)
59
+ if value is not None:
60
+ if key == 'inputnode':
61
+ value = ", ".join([f'{step}{index}' for step, index in value])
62
+ nodes[key] = str(value)
63
+ return nodes
64
+
65
+
66
+ def get_flowgraph_edges(chip):
67
+ '''
68
+ Returns a dicitionary where each key is one node, a tuple in the form
69
+ (step, index) and the value of each key is a set of tuples in the form
70
+ (step, index). The value of each key represents all the nodes that are
71
+ inputs to the key node.
72
+
73
+ Args:
74
+ chip (Chip) : The chip object that contains the schema read from.
75
+
76
+ Example:
77
+ >>> get_flowgraph_edges(chip)
78
+ Returns dictionary where the values of the keys are the edges.
79
+ '''
80
+ flowgraph_edges = {}
81
+ flow = chip.get('option', 'flow')
82
+ for step in chip.getkeys('flowgraph', flow):
83
+ for index in chip.getkeys('flowgraph', flow, step):
84
+ flowgraph_edges[step, index] = set()
85
+ for in_step, in_index in chip.get('flowgraph', flow, step, index, 'input'):
86
+ flowgraph_edges[step, index].add((in_step, in_index))
87
+ return flowgraph_edges
88
+
89
+
90
+ def make_manifest_helper(manifest_subsect, modified_manifest_subsect):
91
+ '''
92
+ Function is a helper function to make_manifest. It mutates the input json.
93
+
94
+ Args:
95
+ manifest_subsect (dict) : Represents a subset of the original manifest.
96
+ modified_manifest_subsect (dict) : Represents a subset of the original
97
+ manifest, modified for readability.
98
+
99
+ Example:
100
+ >>> make_manifest_helper(manifest_subsection, {})
101
+ Mutates second paramaeter to remove simplify leaf nodes and remove
102
+ 'default' nodes.
103
+ '''
104
+
105
+ def build_leaf(manifest_subsect):
106
+ if manifest_subsect['pernode'] == 'never':
107
+ if Schema.GLOBAL_KEY in manifest_subsect['node']:
108
+ value = manifest_subsect['node'][Schema.GLOBAL_KEY][Schema.GLOBAL_KEY]['value']
109
+ else:
110
+ value = manifest_subsect['node']['default']['default']['value']
111
+ return value
112
+ else:
113
+ nodes = manifest_subsect['node']
114
+ node_values = {}
115
+ for step in nodes:
116
+ if step == 'default' or step == Schema.GLOBAL_KEY:
117
+ value = nodes[step][step]['value']
118
+ node_values[step] = value
119
+ else:
120
+ for index in nodes[step]:
121
+ value = nodes[step][index]['value']
122
+ if value is None:
123
+ continue
124
+ if index == 'default' or index == Schema.GLOBAL_KEY:
125
+ node_values[step] = value
126
+ else:
127
+ node_values[step + index] = value
128
+ return node_values
129
+
130
+ if Schema._is_leaf(manifest_subsect):
131
+ if manifest_subsect['pernode'] == 'never':
132
+ if Schema.GLOBAL_KEY in manifest_subsect['node']:
133
+ value = manifest_subsect['node'][Schema.GLOBAL_KEY][Schema.GLOBAL_KEY]['value']
134
+ else:
135
+ value = manifest_subsect['node']['default']['default']['value']
136
+ modified_manifest_subsect['value'] = value
137
+ else:
138
+ nodes = manifest_subsect['node']
139
+ for step in nodes:
140
+ if step == 'default' or step == Schema.GLOBAL_KEY:
141
+ value = nodes[step][step]['value']
142
+ modified_manifest_subsect[step] = value
143
+ else:
144
+ for index in nodes[step]:
145
+ value = nodes[step][index]['value']
146
+ if value is None:
147
+ continue
148
+ if index == 'default' or index == Schema.GLOBAL_KEY:
149
+ modified_manifest_subsect[step] = value
150
+ else:
151
+ modified_manifest_subsect[step + index] = value
152
+
153
+ for key, key_dict in manifest_subsect.items():
154
+ if key != 'default':
155
+ if Schema._is_leaf(key_dict):
156
+ modified_manifest_subsect[key] = build_leaf(key_dict)
157
+ else:
158
+ modified_manifest_subsect[key] = {}
159
+ make_manifest_helper(key_dict, modified_manifest_subsect[key])
160
+
161
+
162
+ def make_manifest(chip):
163
+ '''
164
+ Returns a dictionary of dictionaries/json
165
+
166
+ Args:
167
+ chip (Chip) : The chip object that contains the schema read from.
168
+
169
+ Example:
170
+ >>> make_manifest(chip)
171
+ Returns tree/json of manifest.
172
+ '''
173
+ manifest = chip.schema.cfg
174
+ modified_manifest = {}
175
+ make_manifest_helper(manifest, modified_manifest)
176
+ return modified_manifest
177
+
178
+
179
+ def get_flowgraph_path(chip):
180
+ '''
181
+ Returns a set of all the nodes in the 'winning' path.
182
+
183
+ Args:
184
+ chip (Chip) : The chip object that contains the schema read from.
185
+
186
+ Example:
187
+ >>> get_flowgraph_path(chip)
188
+ Returns the "winning" path for that job.
189
+ '''
190
+ flow = chip.get('option', 'flow')
191
+ return utils._get_flowgraph_path(chip, flow, nodes_to_execute(chip))
192
+
193
+
194
+ def search_manifest_keys(manifest, key):
195
+ '''
196
+ Function is a recursive helper to search_manifest, more info there.
197
+
198
+ Args:
199
+ manifest (dictionary) : A dictionary representing the manifest.
200
+ key (string) : Searches all keys for partial matches on this string.
201
+ '''
202
+ filtered_manifest = {}
203
+ for dict_key in manifest:
204
+ if key in dict_key:
205
+ filtered_manifest[dict_key] = manifest[dict_key]
206
+ elif isinstance(manifest[dict_key], dict):
207
+ result = search_manifest_keys(manifest[dict_key], key)
208
+ if result: # result is non-empty
209
+ filtered_manifest[dict_key] = result
210
+ return filtered_manifest
211
+
212
+
213
+ def search_manifest_values(manifest, value):
214
+ '''
215
+ Function is a recursive helper to search_manifest, more info there.
216
+
217
+ Args:
218
+ manifest (dictionary) : A dicitionary representing the manifest.
219
+ value (string) : Searches all values for partial matches on this
220
+ string.
221
+ '''
222
+ filtered_manifest = {}
223
+ for key in manifest:
224
+ if isinstance(manifest[key], dict):
225
+ result = search_manifest_values(manifest[key], value)
226
+ if result: # result is non-empty
227
+ filtered_manifest[key] = result
228
+ elif isinstance(manifest[key], str) and value in manifest[key]:
229
+ filtered_manifest[key] = manifest[key]
230
+ return filtered_manifest
231
+
232
+
233
+ def search_manifest(manifest, key_search=None, value_search=None):
234
+ '''
235
+ Returns the same structure as make_manifest, but it is filtered by partial
236
+ matches by keys or values. If both key_search and value_search are None,
237
+ the original manifest is returned.
238
+
239
+ Args:
240
+ manifest (dictionary) : A dicitionary representing the manifest.
241
+ key_search (string) : Searches all keys for partial matches on this
242
+ string
243
+ value_search(string) : Searches all values for partial matches
244
+ on this string.
245
+
246
+ Example:
247
+ >>> search_manifest(jsonDict, key_search='input', value_search='v')
248
+ Returns a filtered version of jsonDict where each path contains at
249
+ least one key that contains the substring input and has values that
250
+ contain v.
251
+ '''
252
+ return_manifest = manifest
253
+ if key_search:
254
+ return_manifest = search_manifest_keys(return_manifest, key_search)
255
+ if value_search:
256
+ return_manifest = search_manifest_values(return_manifest, value_search)
257
+ return return_manifest
258
+
259
+
260
+ def get_total_manifest_key_count(manifest):
261
+ '''
262
+ Returns (int) the number of keys
263
+
264
+ Args:
265
+ manifest (dictionary) : A dicitionary representing the manifest.
266
+ acc (int) : An accumulator of the current number of folders and files.
267
+ '''
268
+ acc = len(manifest)
269
+ for dictKeys in manifest:
270
+ if isinstance(manifest[dictKeys], dict):
271
+ acc += get_total_manifest_key_count(manifest[dictKeys])
272
+ return acc
273
+
274
+
275
+ def get_metrics_source(chip, step, index):
276
+ '''
277
+ Returns a dictionary where the keys are files in the logs and reports for
278
+ a given step and index. The values are a list of the metrics that come from
279
+ that file. If a file is not in the dictionary, that implies that no metrics
280
+ come from it.
281
+
282
+ Args:
283
+ chip (Chip) : The chip object that contains the schema read from.
284
+ step (string) : Step of node.
285
+ index (string) : Index of node.
286
+ '''
287
+ file_to_metric = {}
288
+ tool, task = get_tool_task(chip, step, index)
289
+ metrics = chip.getkeys('tool', tool, 'task', task, 'report')
290
+ for metric in metrics:
291
+ sources = chip.get('tool', tool, 'task', task, 'report', metric, step=step, index=index)
292
+ for source in sources:
293
+ if source in file_to_metric:
294
+ file_to_metric[source].append(metric)
295
+ else:
296
+ file_to_metric[source] = [metric]
297
+ return file_to_metric
298
+
299
+
300
+ def get_files(chip, step, index):
301
+ '''
302
+ Returns a list of 3-tuple that contain the path name of how to get to that
303
+ folder, the subfolders of that directory, and it's files. The list is
304
+ ordered by layer of directory.
305
+
306
+ Args:
307
+ chip (Chip) : The chip object that contains the schema read from.
308
+ step (string) : Step of node.
309
+ index (string) : Index of node.
310
+ '''
311
+ # could combine filters, but slightly more efficient to separate them
312
+ # Is remaking the list with sets instead of list worth it?
313
+ logs_and_reports = []
314
+ all_paths = os.walk(chip.getworkdir(step=step, index=index))
315
+ for path_name, folders, files in all_paths:
316
+ logs_and_reports.append((path_name, set(folders), set(files)))
317
+ return logs_and_reports
318
+
319
+
320
+ def get_chart_data(chips, metric, nodes):
321
+ '''
322
+ Returns returns a a tuple where the first element is a 2d dictionary of
323
+ data points, following the forms {step+index: {chip_name: value}} where
324
+ each dictionary can have many keys. The second element is a string that represents the unit.
325
+
326
+ Args:
327
+ chips (list) : A list of dictionaries with the form
328
+ {'chip_object': chip, 'chip_name': name}.
329
+ metric (string) : The metric that the user is searching.
330
+ nodes (list) : A list of dictionaries with the form (step, index).
331
+ '''
332
+ metric_units = set() # the set of all units for this metric (hopefully, it's length is 0 or 1)
333
+ metric_datapoints = {}
334
+ metric_unit = ''
335
+ for chip_and_chip_name in chips:
336
+ chip = chip_and_chip_name['chip_object']
337
+ chip_name = chip_and_chip_name['chip_name']
338
+ nodes_list, errors, metrics, metrics_unit, metrics_to_show, reports = \
339
+ utils._collect_data(chip, format_as_string=False)
340
+ if metric in metrics_unit:
341
+ metric_unit = metrics_unit[metric]
342
+ metric_units.add(metric_unit)
343
+ for node in nodes:
344
+ if node not in metrics:
345
+ continue
346
+ value = metrics[node][metric]
347
+ if value is None:
348
+ continue
349
+ if node in metric_datapoints:
350
+ metric_datapoints[node][chip_name] = value
351
+ else:
352
+ metric_datapoints[node] = {chip_name: value}
353
+ if len(metric_units) > 1:
354
+ raise ValueError('Not all measurements were made with the same units')
355
+ return metric_datapoints, metric_unit
@@ -0,0 +1,137 @@
1
+ import os
2
+ import time
3
+ import tempfile
4
+ import json
5
+
6
+ from streamlit.web import bootstrap
7
+ from streamlit import config as _config
8
+
9
+ import multiprocessing
10
+ import subprocess
11
+ import atexit
12
+ import shutil
13
+
14
+
15
+ class Dashboard():
16
+ __port = 8501
17
+
18
+ def __init__(self, chip, port=None, graph_chips=None):
19
+ if not port:
20
+ port = Dashboard.__port
21
+
22
+ self.__dashboard = None
23
+ self.__chip = chip
24
+ self.__directory = tempfile.mkdtemp(prefix='sc_dashboard_',
25
+ suffix=f'_{self.__chip.design}')
26
+ self.__manifest = os.path.join(self.__directory, 'manifest.json')
27
+ self.__port = port
28
+ dirname = os.path.dirname(__file__)
29
+ self.__streamlit_file = os.path.join(dirname, 'streamlit_viewer.py')
30
+
31
+ self.__streamlit_args = [
32
+ ("browser.gatherUsageStats", False),
33
+ ("browser.serverPort", self.__port),
34
+ ("logger.level", 'error'),
35
+ ("runner.fastReruns", True),
36
+ ("server.port", self.__port)
37
+ ]
38
+
39
+ # pass in a json object called __graph_chips
40
+ # the key is the chip_name and value is the filepath
41
+ # if another argument is passed
42
+
43
+ # use of list is to preserve order
44
+ self.__graph_chips = []
45
+ self.__graph_chips_names = []
46
+ if graph_chips:
47
+ for chip_object_and_name in graph_chips:
48
+ chip_file_path = \
49
+ os.path.join(self.__directory,
50
+ f"{chip_object_and_name['name']}.json")
51
+ self.__graph_chips.append({'chip': chip_object_and_name['chip'],
52
+ 'name': chip_file_path})
53
+ self.__graph_chips_names.append(chip_file_path)
54
+
55
+ self.__config = {"manifest": self.__manifest,
56
+ "graph_chips": self.__graph_chips_names}
57
+
58
+ self.__sleep_time = 0.5
59
+
60
+ atexit.register(self.__cleanup)
61
+
62
+ def open_dashboard(self):
63
+ with open(self.__get_config_file(), 'w') as f:
64
+ json.dump(self.__config, f, indent=4)
65
+
66
+ self.update_manifest()
67
+
68
+ self.update_graph_manifests()
69
+
70
+ self.__dashboard = multiprocessing.Process(
71
+ target=self._run_streamlit_bootstrap)
72
+
73
+ self.__dashboard.start()
74
+
75
+ def update_manifest(self):
76
+ self.__chip.write_manifest(self.__manifest)
77
+
78
+ def update_graph_manifests(self):
79
+ for chip_object_and_name in self.__graph_chips:
80
+ chip = chip_object_and_name['chip']
81
+ file_path = chip_object_and_name['name']
82
+ chip.write_manifest(file_path)
83
+
84
+ def __get_config_file(self):
85
+ return os.path.join(self.__directory, 'config.json')
86
+
87
+ def is_running(self):
88
+ if self.__dashboard is None:
89
+ return False
90
+
91
+ if self.__dashboard.is_alive():
92
+ return True
93
+
94
+ self.__dashboard = None
95
+ self.__manifest = None
96
+ return False
97
+
98
+ def stop(self):
99
+ if not self.is_running():
100
+ return
101
+
102
+ while self.__dashboard.is_alive():
103
+ self.__dashboard.terminate()
104
+ self._sleep()
105
+
106
+ self.__dashboard = None
107
+ self.__manifest = None
108
+
109
+ def wait(self):
110
+ self.__dashboard.join()
111
+
112
+ def _sleep(self):
113
+ time.sleep(self.__sleep_time)
114
+
115
+ def _run_streamlit_bootstrap(self):
116
+ for config, val in self.__streamlit_args:
117
+ _config.set_option(config, val)
118
+
119
+ bootstrap.run(self.__streamlit_file,
120
+ False,
121
+ [self.__get_config_file()],
122
+ flag_options={})
123
+
124
+ def __run_streamlit_subproc(self):
125
+ cmd = ['streamlit', 'run',
126
+ self.__streamlit_file, self.__get_config_file()]
127
+ for config, val in self.__streamlit_args:
128
+ cmd.append(f'--{config}')
129
+ cmd.append(val)
130
+
131
+ subprocess.Popen(cmd)
132
+
133
+ def __cleanup(self):
134
+ self.stop()
135
+
136
+ if os.path.exists(self.__directory):
137
+ shutil.rmtree(self.__directory)