accelforge 0.0.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 (258) hide show
  1. accelforge/__init__.py +21 -0
  2. accelforge/_accelerated_imports.py +16 -0
  3. accelforge/_deprecate/_simanneal/evalmapping.py +271 -0
  4. accelforge/_deprecate/_simanneal/mapspaceglobals.py +298 -0
  5. accelforge/_deprecate/_simanneal/simanneal.py +666 -0
  6. accelforge/_deprecate/_simanneal/tracking.py +105 -0
  7. accelforge/_deprecate/_simanneal/wrappers.py +218 -0
  8. accelforge/_deprecate/_simanneal2/__init__.py +7 -0
  9. accelforge/_deprecate/_simanneal2/simanneal.py +493 -0
  10. accelforge/_deprecate/_simanneal2/tracking.py +116 -0
  11. accelforge/_deprecate/compatibility_util.py +181 -0
  12. accelforge/_deprecate/layerdeduplication/__init__.py +2 -0
  13. accelforge/_deprecate/layerdeduplication/group_similar_einsums.py +160 -0
  14. accelforge/_deprecate/layerdeduplication/grouped_einsums.py +84 -0
  15. accelforge/_deprecate/mapping_filter_tags/__init__.py +2 -0
  16. accelforge/_deprecate/mapping_filter_tags/ffmt.py +212 -0
  17. accelforge/_deprecate/mapping_filter_tags/onesplit.py +24 -0
  18. accelforge/_deprecate/mapping_filter_tags/util.py +24 -0
  19. accelforge/_deprecate/tags.py +69 -0
  20. accelforge/_deprecate/viz/__init__.py +0 -0
  21. accelforge/_deprecate/viz/interactive.py +159 -0
  22. accelforge/_deprecate/viz/reservationtree.py +307 -0
  23. accelforge/_deprecate/viz/ski_slope.py +88 -0
  24. accelforge/_version.py +15 -0
  25. accelforge/examples.py +39 -0
  26. accelforge/frontend/__init__.py +10 -0
  27. accelforge/frontend/_binding.py +129 -0
  28. accelforge/frontend/_workload_isl/__init__.py +2 -0
  29. accelforge/frontend/_workload_isl/_isl.py +149 -0
  30. accelforge/frontend/_workload_isl/_symbolic.py +141 -0
  31. accelforge/frontend/arch copy.py +1544 -0
  32. accelforge/frontend/arch.py +1642 -0
  33. accelforge/frontend/config.py +63 -0
  34. accelforge/frontend/mapper/__init__.py +5 -0
  35. accelforge/frontend/mapper/ffm.py +126 -0
  36. accelforge/frontend/mapper/mapper.py +7 -0
  37. accelforge/frontend/mapper/metrics.py +30 -0
  38. accelforge/frontend/mapping/__init__.py +1 -0
  39. accelforge/frontend/mapping/mapping.py +1736 -0
  40. accelforge/frontend/model.py +14 -0
  41. accelforge/frontend/renames.py +150 -0
  42. accelforge/frontend/spec copy.py +230 -0
  43. accelforge/frontend/spec.py +301 -0
  44. accelforge/frontend/variables.py +12 -0
  45. accelforge/frontend/workload.py +952 -0
  46. accelforge/mapper/FFM/__init__.py +9 -0
  47. accelforge/mapper/FFM/_join_pmappings/__init__.py +0 -0
  48. accelforge/mapper/FFM/_join_pmappings/compatibility.py +653 -0
  49. accelforge/mapper/FFM/_join_pmappings/compress_pmappings.py +140 -0
  50. accelforge/mapper/FFM/_join_pmappings/join_pmappings.py +703 -0
  51. accelforge/mapper/FFM/_join_pmappings/pmapping_dataframe.py +901 -0
  52. accelforge/mapper/FFM/_join_pmappings/pmapping_group.py +337 -0
  53. accelforge/mapper/FFM/_make_pmappings/contraints/__init__.py +0 -0
  54. accelforge/mapper/FFM/_make_pmappings/contraints/constraints.py +360 -0
  55. accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/__init__.py +1 -0
  56. accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_loops.py +373 -0
  57. accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_pmapping_templates.py +463 -0
  58. accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_reservations.py +95 -0
  59. accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_storage_order.py +382 -0
  60. accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_storages.py +155 -0
  61. accelforge/mapper/FFM/_make_pmappings/make_pmappings.py +411 -0
  62. accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/__init__.py +1 -0
  63. accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/make_pmappings_from_templates.py +407 -0
  64. accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/make_tile_shapes.py +1681 -0
  65. accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/run_model.py +170 -0
  66. accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/symbol_relations.py +174 -0
  67. accelforge/mapper/FFM/_make_pmappings/pmapper_job.py +282 -0
  68. accelforge/mapper/FFM/_pareto_df/df_convention.py +273 -0
  69. accelforge/mapper/FFM/_pareto_df/pareto copy.py +836 -0
  70. accelforge/mapper/FFM/_pareto_df/pareto.py +508 -0
  71. accelforge/mapper/FFM/data.py +61 -0
  72. accelforge/mapper/FFM/main copy.py +236 -0
  73. accelforge/mapper/FFM/main.py +208 -0
  74. accelforge/mapper/FFM/mappings.py +510 -0
  75. accelforge/mapper/FFM/pmappings.py +310 -0
  76. accelforge/mapper/__init__.py +4 -0
  77. accelforge/mapper.py +0 -0
  78. accelforge/model/__init__.py +1 -0
  79. accelforge/model/_looptree/__init__.py +0 -0
  80. accelforge/model/_looptree/accesses.py +335 -0
  81. accelforge/model/_looptree/capacity/__init__.py +1 -0
  82. accelforge/model/_looptree/capacity/aggregators.py +36 -0
  83. accelforge/model/_looptree/capacity/capacity.py +47 -0
  84. accelforge/model/_looptree/energy.py +150 -0
  85. accelforge/model/_looptree/equivalent_ranks.py +29 -0
  86. accelforge/model/_looptree/latency/__init__.py +1 -0
  87. accelforge/model/_looptree/latency/latency.py +98 -0
  88. accelforge/model/_looptree/latency/memory.py +120 -0
  89. accelforge/model/_looptree/latency/processors.py +92 -0
  90. accelforge/model/_looptree/mapping_utilities.py +71 -0
  91. accelforge/model/_looptree/reuse/__init__.py +4 -0
  92. accelforge/model/_looptree/reuse/isl/__init__.py +1 -0
  93. accelforge/model/_looptree/reuse/isl/des.py +59 -0
  94. accelforge/model/_looptree/reuse/isl/isl_functions.py +374 -0
  95. accelforge/model/_looptree/reuse/isl/mapping_to_isl/__init__.py +4 -0
  96. accelforge/model/_looptree/reuse/isl/mapping_to_isl/analyze_mapping.py +297 -0
  97. accelforge/model/_looptree/reuse/isl/mapping_to_isl/skews_from_mapping.py +236 -0
  98. accelforge/model/_looptree/reuse/isl/mapping_to_isl/tiling.py +685 -0
  99. accelforge/model/_looptree/reuse/isl/mapping_to_isl/types.py +188 -0
  100. accelforge/model/_looptree/reuse/isl/spatial.py +260 -0
  101. accelforge/model/_looptree/reuse/isl/temporal.py +182 -0
  102. accelforge/model/_looptree/reuse/symbolic/__init__.py +1 -0
  103. accelforge/model/_looptree/reuse/symbolic/symbolic copy 2.py +1346 -0
  104. accelforge/model/_looptree/reuse/symbolic/symbolic copy.py +1408 -0
  105. accelforge/model/_looptree/reuse/symbolic/symbolic.py +1396 -0
  106. accelforge/model/_looptree/run.py +122 -0
  107. accelforge/model/_looptree/types.py +26 -0
  108. accelforge/model/_looptree/visualization/__init__.py +0 -0
  109. accelforge/model/_looptree/visualization/occupancy.py +11 -0
  110. accelforge/model/main.py +222 -0
  111. accelforge/plotting/__init__.py +2 -0
  112. accelforge/plotting/mappings.py +219 -0
  113. accelforge/plotting/specs.py +57 -0
  114. accelforge/util/__init__.py +4 -0
  115. accelforge/util/_base_analysis_types.py +24 -0
  116. accelforge/util/_basetypes.py +1089 -0
  117. accelforge/util/_frozenset.py +36 -0
  118. accelforge/util/_isl.py +29 -0
  119. accelforge/util/_itertools.py +14 -0
  120. accelforge/util/_mathfuncs.py +57 -0
  121. accelforge/util/_parse_expressions.py +339 -0
  122. accelforge/util/_picklecache.py +32 -0
  123. accelforge/util/_setexpressions.py +268 -0
  124. accelforge/util/_sympy/__init__.py +0 -0
  125. accelforge/util/_sympy/broadcast_max.py +18 -0
  126. accelforge/util/_visualization.py +112 -0
  127. accelforge/util/_yaml.py +579 -0
  128. accelforge/util/parallel.py +193 -0
  129. accelforge-0.0.1.dist-info/METADATA +64 -0
  130. accelforge-0.0.1.dist-info/RECORD +258 -0
  131. accelforge-0.0.1.dist-info/WHEEL +5 -0
  132. accelforge-0.0.1.dist-info/licenses/LICENSE +19 -0
  133. accelforge-0.0.1.dist-info/top_level.txt +5 -0
  134. docs/_build/html/_sources/fastfusion.frontend.mapper.rst.txt +37 -0
  135. docs/_build/html/_sources/fastfusion.frontend.rst.txt +70 -0
  136. docs/_build/html/_sources/fastfusion.frontend.workload.rst.txt +21 -0
  137. docs/_build/html/_sources/fastfusion.mapper.FFM.rst.txt +37 -0
  138. docs/_build/html/_sources/fastfusion.mapper.rst.txt +18 -0
  139. docs/_build/html/_sources/fastfusion.rst.txt +20 -0
  140. docs/_build/html/_sources/fastfusion.util.rst.txt +21 -0
  141. docs/_build/html/_sources/index.rst.txt +87 -0
  142. docs/_build/html/_sources/modules.rst.txt +7 -0
  143. docs/_build/html/_sources/notes/citation.rst.txt +45 -0
  144. docs/_build/html/_sources/notes/definitions.rst.txt +43 -0
  145. docs/_build/html/_sources/notes/faqs.rst.txt +39 -0
  146. docs/_build/html/_sources/notes/modeling/accelerator_energy_latency.rst.txt +72 -0
  147. docs/_build/html/_sources/notes/modeling/component_energy_area.rst.txt +96 -0
  148. docs/_build/html/_sources/notes/modeling/mapping.rst.txt +100 -0
  149. docs/_build/html/_sources/notes/modeling.rst.txt +33 -0
  150. docs/_build/html/_sources/notes/parsing/arithmetic_parsing.rst.txt +136 -0
  151. docs/_build/html/_sources/notes/parsing/setexpressions.rst.txt +63 -0
  152. docs/_build/html/_sources/notes/parsing/yaml_parsing.rst.txt +176 -0
  153. docs/_build/html/_sources/notes/quickstart_and_installation.rst.txt +9 -0
  154. docs/_build/html/_sources/notes/spec/architecture.rst.txt +133 -0
  155. docs/_build/html/_sources/notes/spec/mapping.rst.txt +12 -0
  156. docs/_build/html/_sources/notes/spec/workload.rst.txt +83 -0
  157. docs/_build/html/_sources/notes/spec.rst.txt +36 -0
  158. docs/source/_ext/include_attrs.py +213 -0
  159. docs/source/_ext/include_docstring.py +364 -0
  160. docs/source/_ext/include_functions.py +154 -0
  161. docs/source/_ext/include_notebook.py +131 -0
  162. docs/source/_ext/include_yaml.py +119 -0
  163. docs/source/_ext/inherited_attributes.py +222 -0
  164. docs/source/_ext/paths.py +4 -0
  165. docs/source/conf.py +79 -0
  166. examples/arches/compute_in_memory/_include.yaml +74 -0
  167. examples/arches/compute_in_memory/_include_functions.py +229 -0
  168. examples/arches/compute_in_memory/_load_spec.py +57 -0
  169. examples/arches/compute_in_memory/components/c2c_multiplier.py +181 -0
  170. examples/arches/compute_in_memory/components/dac_c2c_r2r.py +605 -0
  171. examples/arches/compute_in_memory/components/misc.py +195 -0
  172. examples/arches/compute_in_memory/components/util/bit_functions.py +51 -0
  173. examples/arches/compute_in_memory/components/zero_comparator.py +92 -0
  174. examples/arches/compute_in_memory/isaac.yaml +233 -0
  175. examples/arches/compute_in_memory/memory_cells/ecram_demo.yaml +63 -0
  176. examples/arches/compute_in_memory/memory_cells/rram_example.yaml +63 -0
  177. examples/arches/compute_in_memory/memory_cells/rram_isaac_isca_2016.yaml +64 -0
  178. examples/arches/compute_in_memory/memory_cells/rram_neurosim_default.yaml +63 -0
  179. examples/arches/compute_in_memory/memory_cells/rram_raella_isca_2023.yaml +70 -0
  180. examples/arches/compute_in_memory/memory_cells/rram_wan_nature_2022.yaml +63 -0
  181. examples/arches/compute_in_memory/memory_cells/sram_colonnade_jssc_2021.yaml +63 -0
  182. examples/arches/compute_in_memory/memory_cells/sram_example.yaml +63 -0
  183. examples/arches/compute_in_memory/memory_cells/sram_jia_jssc_2020.yaml +63 -0
  184. examples/arches/compute_in_memory/memory_cells/sram_sinangil_jssc_2021.yaml +63 -0
  185. examples/arches/compute_in_memory/memory_cells/sram_wang_vlsi_2022.yaml +63 -0
  186. examples/arches/compute_in_memory/wang_vlsi_2022.yaml +289 -0
  187. examples/arches/eyeriss.yaml +68 -0
  188. examples/arches/fanout_variations/at_glb.yaml +31 -0
  189. examples/arches/fanout_variations/at_glb_with_fanout_node.yaml +34 -0
  190. examples/arches/fanout_variations/at_mac.yaml +31 -0
  191. examples/arches/fanout_variations/at_mac_with_constraints.yaml +38 -0
  192. examples/arches/fanout_variations/at_mac_with_fanout_node.yaml +34 -0
  193. examples/arches/nvdla.yaml +47 -0
  194. examples/arches/simple.yaml +28 -0
  195. examples/arches/tpu_v4i.yaml +67 -0
  196. examples/mappings/unfused_matmuls_to_simple.yaml +33 -0
  197. examples/misc/component_annotated.yaml +33 -0
  198. examples/workloads/gpt3_6.7B.yaml +124 -0
  199. examples/workloads/matmuls.yaml +20 -0
  200. examples/workloads/mobilenet_28.yaml +81 -0
  201. examples/workloads/mobilenet_various_separate.yaml +106 -0
  202. examples/workloads/three_matmuls_annotated.yaml +59 -0
  203. notebooks/.ipynb_checkpoints/fastfusion_arch_study_michael-checkpoint.ipynb +359 -0
  204. notebooks/compute_in_memory/_scripts.py +339 -0
  205. notebooks/compute_in_memory/isaac.guide.ipynb +270 -0
  206. notebooks/compute_in_memory/wang_vlsi_2022.ipynb +602 -0
  207. notebooks/paths.py +4 -0
  208. notebooks/tutorials/.ipynb_checkpoints/1_FFM-checkpoint.ipynb +3110 -0
  209. notebooks/tutorials/FFM.ipynb +3498 -0
  210. notebooks/tutorials/_include.py +48 -0
  211. notebooks/tutorials/component_energy_area.ipynb +363 -0
  212. tests/Q_mapping.yaml +38 -0
  213. tests/__init__.py +0 -0
  214. tests/conv.mapping.yaml +27 -0
  215. tests/conv.workload.yaml +13 -0
  216. tests/conv_sym.mapping.yaml +43 -0
  217. tests/copy.mapping.yaml +35 -0
  218. tests/copy.workload.yaml +15 -0
  219. tests/distribuffers/__init__.py +0 -0
  220. tests/distribuffers/multicast/test_cases.yaml +482 -0
  221. tests/distribuffers/spec/binding/valid_bindings.yaml +97 -0
  222. tests/distribuffers/spec/distributed.yaml +100 -0
  223. tests/distribuffers/spec/logical_arch.yaml +32 -0
  224. tests/distribuffers/spec/physical_arch.yaml +69 -0
  225. tests/distribuffers/test_binding.py +48 -0
  226. tests/frontend/__init__.py +0 -0
  227. tests/frontend/test_mapping_viz.py +52 -0
  228. tests/mapper/__init__.py +0 -0
  229. tests/mapper/configs/conv1d/conv1d.mapping.yaml +31 -0
  230. tests/mapper/configs/conv1d/conv1d.workload.yaml +11 -0
  231. tests/mapper/configs/two_conv1d/two_conv1d.expected.yaml +38 -0
  232. tests/mapper/configs/two_conv1d/two_conv1d.mapping.yaml +54 -0
  233. tests/mapper/configs/two_conv1d/two_conv1d.workload.yaml +19 -0
  234. tests/mapper/test_mapping_to_isl.py +90 -0
  235. tests/mapper/test_spatial_reuse_analysis.py +67 -0
  236. tests/mapper/test_temporal_reuse_analysis.py +56 -0
  237. tests/mapper/util.py +58 -0
  238. tests/matmul.mapping.yaml +29 -0
  239. tests/matmul.workload.yaml +12 -0
  240. tests/matmul_spatial.mapping.yaml +44 -0
  241. tests/mha.renames.yaml +65 -0
  242. tests/mha.workload.yaml +67 -0
  243. tests/mha.yaml +59 -0
  244. tests/mha_full.workload.yaml +67 -0
  245. tests/mobilenet.workload.yaml +35 -0
  246. tests/mobilenet_long.workload.yaml +64 -0
  247. tests/pmappingcache.py +24 -0
  248. tests/processing_stage.arch.yaml +40 -0
  249. tests/snowcat.arch.yaml +36 -0
  250. tests/test_ffm_join_pmappings.py +106 -0
  251. tests/test_ffm_make_pmappings.py +82 -0
  252. tests/test_ffm_make_tile_shapes.py +49 -0
  253. tests/test_mapper.py +100 -0
  254. tests/test_model.py +37 -0
  255. tests/test_plotting.py +72 -0
  256. tests/test_processing_stage.py +46 -0
  257. tests/test_symbolic_model.py +248 -0
  258. tests/test_workload.py +141 -0
@@ -0,0 +1,339 @@
1
+ import sys
2
+ import os
3
+ from IPython.display import display, Markdown
4
+
5
+ THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
6
+ sys.path.append(THIS_SCRIPT_DIR)
7
+ sys.path.append(
8
+ os.path.join(THIS_SCRIPT_DIR, "..", "..", "examples", "arches", "compute_in_memory")
9
+ )
10
+
11
+ from _load_spec import get_spec as _get_spec
12
+ import accelforge as af
13
+
14
+ def display_markdown(markdown):
15
+ display(Markdown(markdown))
16
+
17
+
18
+ def get_spec(name: str, add_dummy_main_memory: bool = False) -> af.Spec:
19
+ return _get_spec(name, add_dummy_main_memory=add_dummy_main_memory)
20
+
21
+ # import difflib
22
+ # import re
23
+ # import svgutils
24
+ # from IPython.display import SVG, display, Markdown
25
+ # from .utils import *
26
+
27
+ # DIAGRAM_DEFAULT_IGNORE = ("system", "macro_in_system", "1bit_x_1bit_mac")
28
+
29
+
30
+ # def grab_from_yaml_file(
31
+ # yaml_file, startfrom=None, same_indent=True, include_lines_before=0
32
+ # ):
33
+ # with open(yaml_file, "r") as f:
34
+ # contents = f.readlines()
35
+ # start, end = 0, len(contents)
36
+ # n_whitespace = 0
37
+ # if startfrom is None:
38
+ # return "".join(contents)
39
+ # for i, line in enumerate(contents):
40
+ # if re.findall(r"\b\s*" + startfrom + r"\b", line):
41
+ # start = i
42
+ # n_whitespace = len(re.findall(r"^\s*", line)[0])
43
+ # break
44
+ # else:
45
+ # raise ValueError(f"{startfrom} not found in {yaml_file}")
46
+ # for i, line in enumerate(contents[start + 1 :]):
47
+ # ws = len(re.findall(r"^\s*", line)[0])
48
+ # if ws < n_whitespace or (not same_indent and ws == n_whitespace):
49
+ # end = start + i + 1
50
+ # break
51
+ # return "".join(
52
+ # c[n_whitespace:] for c in contents[start - include_lines_before : end]
53
+ # )
54
+
55
+
56
+ # def scale_svg(svg, scale=0.5):
57
+ # svg = svgutils.transform.fromstring(svg.decode("ascii"))
58
+ # svg = svgutils.compose.Figure(svg.width, svg.height, svg.getroot())
59
+ # svg = svg.scale(scale)
60
+ # svg.width = svg.width * scale
61
+ # svg.height = svg.height * scale
62
+ # return svg
63
+
64
+
65
+ # def display_diagram(diagram, scale=0.5):
66
+ # display(SVG(scale_svg(diagram.create_svg(), scale).tostr()))
67
+
68
+
69
+ # def display_markdown(markdown):
70
+ # display(Markdown(markdown))
71
+
72
+
73
+ # def display_yaml_file(*args, **kwargs):
74
+ # display_yaml_str(grab_from_yaml_file(*args, **kwargs))
75
+
76
+
77
+ # def display_yaml_str(yaml_str):
78
+ # display_markdown(f"```yaml\n{yaml_str}```")
79
+
80
+
81
+ # def get_yaml_file_markdown(yaml_file, *args, **kwargs):
82
+ # return f"```yaml\n{grab_from_yaml_file(yaml_file, *args, **kwargs)}```"
83
+
84
+
85
+ # def get_yaml_str_markdown(yaml_str):
86
+ # return f"```yaml\n{yaml_str}```"
87
+
88
+
89
+ def display_important_variables(name: str):
90
+ result = []
91
+ result.append(f"Some of the important variables for {name}:\n")
92
+
93
+ def pfmat(key, value, note=""):
94
+ result.append(f"- *{key}*: {value} {note if note else ''}")
95
+
96
+ s: af.Spec = get_spec(name)
97
+ s.calculate_component_area_energy_latency_leak(einsum_name=s.workload.einsums[0].name)
98
+
99
+ def getvalue(key):
100
+ return s.variables.get(key, s.arch.arch_globals_dependent_on_workload.get(key, None))
101
+
102
+ for v in [
103
+ ("array_wordlines", "rows in the array"),
104
+ ("array_bitlines", "columns in the array"),
105
+ (
106
+ "array_parallel_inputs",
107
+ "input slice(s) consumed in each cycle.",
108
+ ),
109
+ (
110
+ "array_parallel_weights",
111
+ "weights slice(s) used for computation in each cycle.",
112
+ ),
113
+ ("array_parallel_outputs", "partial sums produced in each cycle."),
114
+ ("tech_node", "m"),
115
+ ("adc_resolution", "bit(s)"),
116
+ ("dac_resolution", "bit(s)"),
117
+ ("n_adc_per_bank", "ADC(s)"),
118
+ ("supported_input_bits", "bit(s)"),
119
+ ("supported_output_bits", "bit(s)"),
120
+ ("supported_weight_bits", "bit(s)"),
121
+ ("bits_per_cell", "bit(s)"),
122
+ (
123
+ "cim_unit_width_cells",
124
+ "adjacent cell(s) in a wordline store bit(s) in one weight slice and process one input & output slice together",
125
+ ),
126
+ (
127
+ "cim_unit_depth_cells",
128
+ "adjacent cell(s) in a bitline operate in separate cycles",
129
+ ),
130
+ "cell_config",
131
+ ("cycle_period", "second(s)"),
132
+ ]:
133
+ if isinstance(v, tuple):
134
+ pfmat(v[0], getvalue(v[0]), v[1])
135
+ else:
136
+ pfmat(v, s.variables.get(v, None))
137
+
138
+ display_markdown("\n".join(result))
139
+
140
+
141
+ # def clean_old_output_files(max_files=50):
142
+ # out_path = os.path.join(THIS_SCRIPT_DIR, "..", "outputs")
143
+ # files = sorted(
144
+ # list(os.path.join(out_path, f) for f in os.listdir(out_path)),
145
+ # key=lambda x: os.path.getmtime(x),
146
+ # )
147
+ # while len(files) > max_files:
148
+ # shutil.rmtree(
149
+ # files.pop(0),
150
+ # ignore_errors=True,
151
+ # )
152
+
153
+
154
+ # def run_test(
155
+ # macro_name: str,
156
+ # test_name: str,
157
+ # show_doc: bool = True,
158
+ # *args,
159
+ # **kwargs,
160
+ # ):
161
+ # test_func = get_test(macro_name, test_name)
162
+ # if show_doc:
163
+ # doc = test_func.__doc__
164
+ # doc = "\n".join([line[1:] for line in doc.split("\n")])
165
+ # display_markdown(doc)
166
+ # t = test_func(*args, **kwargs)
167
+ # clean_old_output_files()
168
+ # return t
169
+
170
+
171
+ # def diff_str(a, b):
172
+ # new_a, new_b = [], []
173
+ # a = re.findall(r"[\w\.]+|\s+|.", a)
174
+ # b = re.findall(r"[\w\.]+|\s+|.", b)
175
+ # # print(f'Diffing {a} and {b}')
176
+ # matcher = difflib.SequenceMatcher(None, a, b)
177
+ # for tag, i1, i2, j1, j2 in matcher.get_opcodes():
178
+ # if tag == "equal":
179
+ # new_a.extend(a[i1:i2])
180
+ # new_b.extend(b[j1:j2])
181
+ # elif tag == "replace":
182
+ # new_a.extend([f"\033[31m{l}\033[0m" for l in a[i1:i2]])
183
+ # new_b.extend([f"\033[31m{l}\033[0m" for l in b[j1:j2]])
184
+ # elif tag == "delete":
185
+ # new_a.extend([f"\033[31m{l}\033[0m" for l in a[i1:i2]])
186
+ # elif tag == "insert":
187
+ # new_b.extend([f"\033[31m{l}\033[0m" for l in b[j1:j2]])
188
+ # return "".join(new_a), "".join(new_b)
189
+
190
+
191
+ # def print_side_by_side(a, b):
192
+ # a_lines = a.splitlines()
193
+ # b_lines = b.splitlines()
194
+
195
+ # # Use difflib to match up lines
196
+ # matcher = difflib.SequenceMatcher(None, a_lines, b_lines)
197
+ # # Insert blank lines to line up the matches
198
+ # a = []
199
+ # b = []
200
+ # for _, i1, i2, j1, j2 in matcher.get_opcodes():
201
+ # a.extend(a_lines[i1:i2])
202
+ # b.extend(b_lines[j1:j2])
203
+ # a.extend([""] * (len(b) - len(a)))
204
+ # b.extend([""] * (len(a) - len(b)))
205
+
206
+ # max_a_len = max(len(line) for line in a)
207
+ # a = [line.ljust(max_a_len) for line in a]
208
+
209
+ # for i in range(len(a)):
210
+ # a[i], b[i] = diff_str(a[i], b[i])
211
+ # if a[i] and not b[i]:
212
+ # a[i] = f"\033[31m{a[i]}\033[0m"
213
+ # elif not a[i] and b[i]:
214
+ # b[i] = f"\033[31m{b[i]}\033[0m"
215
+
216
+ # for a_line, b_line in zip(a, b):
217
+ # print(f"{a_line} | {b_line}")
218
+
219
+ from math import isclose
220
+ import matplotlib.pyplot as plt
221
+
222
+
223
+ def bar_stacked(
224
+ data: dict[dict[str, float]],
225
+ xlabel: str,
226
+ ylabel: str,
227
+ title: str,
228
+ ax: plt.Axes,
229
+ ):
230
+ """Create a stacked bar chart from nested dictionary data.
231
+
232
+ Args:
233
+ data: Nested dict where outer keys are x-axis categories,
234
+ inner keys are stack categories, values are heights
235
+ xlabel: Label for x-axis
236
+ ylabel: Label for y-axis
237
+ title: Chart title
238
+ ax: Matplotlib axes to plot on
239
+ """
240
+ import numpy as np
241
+
242
+ # Get all categories
243
+ x_categories = list(data.keys())
244
+ stack_categories = list(set(k for inner_dict in data.values() for k in inner_dict.keys()))
245
+
246
+ # Prepare data for stacking
247
+ x_pos = np.arange(len(x_categories))
248
+ bottoms = np.zeros(len(x_categories))
249
+
250
+ # Plot each stack category
251
+ for stack_cat in stack_categories:
252
+ heights = [data[x_cat].get(stack_cat, 0) for x_cat in x_categories]
253
+ ax.bar(x_pos, heights, label=stack_cat, bottom=bottoms)
254
+ bottoms += heights
255
+
256
+ # Set labels and formatting
257
+ ax.set_xlabel(xlabel)
258
+ ax.set_ylabel(ylabel)
259
+ ax.set_title(title)
260
+ ax.set_xticks(x_pos)
261
+ ax.set_xticklabels(x_categories, rotation=45, ha='right')
262
+ ax.legend()
263
+ ax.grid(axis='y', alpha=0.3)
264
+
265
+
266
+ def bar_comparison(
267
+ data_dict: dict[str, dict[str, float]],
268
+ xlabel: str,
269
+ ylabel: str,
270
+ title: str,
271
+ ax: plt.Axes,
272
+ ):
273
+ """Create grouped bar chart comparing multiple datasets.
274
+
275
+ Args:
276
+ data_dict: Dict where keys are series names (e.g., "Modeled", "Expected"),
277
+ values are dicts mapping category to value
278
+ xlabel: Label for x-axis
279
+ ylabel: Label for y-axis
280
+ title: Chart title
281
+ ax: Matplotlib axes to plot on
282
+ """
283
+ import numpy as np
284
+
285
+ # Get categories (use first dataset's keys)
286
+ categories = list(next(iter(data_dict.values())).keys())
287
+ series_names = list(data_dict.keys())
288
+
289
+ # Set up bar positions
290
+ x = np.arange(len(categories))
291
+ width = 0.8 / len(series_names) # Total width divided by number of series
292
+
293
+ # Plot each series
294
+ for i, series_name in enumerate(series_names):
295
+ offset = (i - len(series_names)/2 + 0.5) * width
296
+ values = [data_dict[series_name][cat] for cat in categories]
297
+ ax.bar(x + offset, values, width, label=series_name)
298
+
299
+ # Set labels and formatting
300
+ ax.set_xlabel(xlabel)
301
+ ax.set_ylabel(ylabel)
302
+ ax.set_title(title)
303
+ ax.set_xticks(x)
304
+ ax.set_xticklabels(categories, rotation=45, ha='right')
305
+ ax.legend()
306
+ ax.grid(axis='y', alpha=0.3)
307
+
308
+
309
+ def bar(
310
+ data: dict[str, float],
311
+ xlabel: str,
312
+ ylabel: str,
313
+ title: str,
314
+ ax: plt.Axes,
315
+ ):
316
+ """Create a simple bar chart from a dictionary.
317
+
318
+ Args:
319
+ data: Dict mapping category names to values
320
+ xlabel: Label for x-axis
321
+ ylabel: Label for y-axis
322
+ title: Chart title
323
+ ax: Matplotlib axes to plot on
324
+ """
325
+ import numpy as np
326
+
327
+ categories = list(data.keys())
328
+ values = list(data.values())
329
+
330
+ x = np.arange(len(categories))
331
+ ax.bar(x, values)
332
+
333
+ # Set labels and formatting
334
+ ax.set_xlabel(xlabel)
335
+ ax.set_ylabel(ylabel)
336
+ ax.set_title(title)
337
+ ax.set_xticks(x)
338
+ ax.set_xticklabels(categories, rotation=45, ha='right')
339
+ ax.grid(axis='y', alpha=0.3)
@@ -0,0 +1,270 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "### Model of \"ISAAC: A Convolutional Neural Network Accelerator with In-Situ Analog Arithmetic in Crossbars!\", ISCA 2016\n",
8
+ "\n",
9
+ "Paper by Ali Shafiee, Anirban Nag, Naveen Muralimanohar, Rajeev Balasubramonian,\n",
10
+ "John Paul Strachan, Miao Hu, R. Stanley Williams, and Vivek Srikumar.\n",
11
+ "\n",
12
+ "ISAAC is a ReRAM-based analog CiM accelerator. It explores several concepts in\n",
13
+ "CiM acceleration, including storing different layers in different arrays and\n",
14
+ "pipelining inputs/outputs between."
15
+ ]
16
+ },
17
+ {
18
+ "cell_type": "code",
19
+ "execution_count": null,
20
+ "metadata": {},
21
+ "outputs": [],
22
+ "source": [
23
+ "from _scripts import (\n",
24
+ " display_important_variables,\n",
25
+ " get_spec,\n",
26
+ " bar_comparison,\n",
27
+ " bar_stacked,\n",
28
+ " bar,\n",
29
+ ")\n",
30
+ "display_important_variables('isaac')\n",
31
+ "get_spec('isaac').arch"
32
+ ]
33
+ },
34
+ {
35
+ "cell_type": "markdown",
36
+ "metadata": {},
37
+ "source": [
38
+ "\n",
39
+ "### Tile Level\n",
40
+ "\n",
41
+ "Twelve macros (called IMAs in the paper) are organized into a tile. Each tile\n",
42
+ "includes a 64kB eDRAM buffer storing 16b inputs/outputs and quantization\n",
43
+ "circuits. The original paper included sigmoid units at this level, but we\n",
44
+ "replaced them with quantization circuits to match the other works. ISAAC uses\n",
45
+ "16b fixed-point quantization for all operands.\n",
46
+ "\n",
47
+ "- *Input Path*: Inputs are stored in the eDRAM. An inter-macro network sends\n",
48
+ " inputs to macros in the tile.\n",
49
+ "- *Weight Path*: Weights are kept static in inference and do not move through\n",
50
+ " this level.\n",
51
+ "- *Output Path*: Outputs are gathered from macros via the inter-tile network.\n",
52
+ " They are quantized before being stored in the eDRAM.\n",
53
+ "\n",
54
+ "Next, there are 12 macros in each tile. Inputs and outputs are unicast between\n",
55
+ "macros.\n",
56
+ "\n",
57
+ "### Macro Level\n",
58
+ "\n",
59
+ "Eight arrays are organized into a macro with an input register and output\n",
60
+ "register. An input network sends input vectors to arrays.\n",
61
+ "\n",
62
+ "The eight arrays can process up to 8×128 = 1024 inputs across all rows, so the\n",
63
+ "input register is sized 2kB (2B per input). The output register is sized 256B\n",
64
+ "(2B per output, 128 outputs total (8 arrays × 128 columns × 2b per column / 16b\n",
65
+ "per output)). While the paper does not do this, we double output buffer size to\n",
66
+ "account for higher-precision accumulation that is important for lower-precision\n",
67
+ "quantization.\n",
68
+ "\n",
69
+ "- *Input Path*: Inputs are stored in the input buffer and multicast between\n",
70
+ " arrays.\n",
71
+ "- *Weight Path*: Weights are kept static in inference and do not move through\n",
72
+ " this level.\n",
73
+ "- *Output Path*: Outputs are stored in the output buffer and spatially reduced\n",
74
+ " between arrays. Before the output buffer, a shift+add circuit accumulates\n",
75
+ " outputs and corrects for offsets caused by slicing.\n",
76
+ "\n",
77
+ "Next, there are 8 arrays in each macro. Inputs and outputs can be spatially\n",
78
+ "reused across arrays with a multicast/reduction network.\n",
79
+ "\n",
80
+ "### Array Level\n",
81
+ "\n",
82
+ "Arrays consist of 128 × 128 ReRAMs. Each array is programmed with weights from\n",
83
+ "one DNN layer, and each weight filter uses 8 array columns (16b weights, 2b per\n",
84
+ "column). 1-bit DACs encode inputs across 16 cycles and 8-bit ADCs convert\n",
85
+ "outputs from each column.\n",
86
+ "\n",
87
+ "We note that the original ISAAC paper included a contribution to decrease\n",
88
+ "required ADC precision. Instead of supporting between 0 and the maximum output\n",
89
+ "of a column, ISAAC supported only half of the range. They ensured that all\n",
90
+ "column outputs would be in this range at program time. If the average weight\n",
91
+ "slice value in a column was less than half of the maximum output, the column\n",
92
+ "could not saturate the ADC. If the average weight slice value was greater than\n",
93
+ "half of the maximum output, ISAAC would store the negated value of the weights.\n",
94
+ "To correct for this, ISAAC would need to record sums of the input values, record\n",
95
+ "which weight columns were negated, and perform arithmetic to recover the real\n",
96
+ "sums from the negated sums.\n",
97
+ "\n",
98
+ "When we modeled ISAAC's accuracy, we found that this technique was not helpful\n",
99
+ "across any tested workloads because weights tended to have about half of the\n",
100
+ "maximum value and input bits tended to have >50% sparsity, so on average output\n",
101
+ "of a column was around 25% of the output range anyway and never exceeded 50%. We\n",
102
+ "can therefore just use the lower half of the ADC range to achieve the same\n",
103
+ "result (lower ADC precision) without any of the additional complexity introduced\n",
104
+ "by this strategy. For this reason, we don't model this technique in our ISAAC\n",
105
+ "model.\n",
106
+ "\n",
107
+ "Inputs and weights are both assumed to be 16b unsigned fixed-point numbers.\n",
108
+ "Signed inputs and weights are converted by adding a bias to the inputs and\n",
109
+ "weights.\n",
110
+ "\n",
111
+ "- *Input Path*: Inputs pass through a 1-bit DACs and appear on the rows of the\n",
112
+ " array.\n",
113
+ "- *Weight Path*: Weights are stored in the array and are not moved during\n",
114
+ " inference.\n",
115
+ "- *Output Path*: Outputs are read from the columns of the array with 8-bit ADCs.\n",
116
+ "\n",
117
+ "Next, there are 128 columns in each array. Inputs are reused between columns\n",
118
+ "(*i.e.,* each input-carrying wire connects to all columns), while outputs and\n",
119
+ "weights are not reused.\n",
120
+ "\n",
121
+ "### Column Level\n",
122
+ "\n",
123
+ "Each column consists of 128 ReRAM devices. Columns store 2b weight slices.\n",
124
+ "\n",
125
+ "- *Input Path*: Each input is passed directly to a row in the column.\n",
126
+ "- *Weight Path*: Weights are not moved during inference.\n",
127
+ "- *Output Path*: Outputs pass through a current mirror to buffer their values\n",
128
+ " before exiting the column.\n",
129
+ "\n",
130
+ "### Row Level\n",
131
+ "\n",
132
+ "Each row in a column has one ReRAM device which stores an offset-encoded 2b\n",
133
+ "weight slice.\n",
134
+ "\n",
135
+ "- *Input Path*: The input is used for a MAC operation.\n",
136
+ "- *Weight Path*: A 2b weight is stored in the ReRAM device and is used for a MAC\n",
137
+ " operation.\n",
138
+ "- *Output Path*: The output is supplied by a MAC operation."
139
+ ]
140
+ },
141
+ {
142
+ "cell_type": "code",
143
+ "execution_count": null,
144
+ "metadata": {},
145
+ "outputs": [],
146
+ "source": [
147
+ "import accelforge as af\n",
148
+ "import matplotlib.pyplot as plt"
149
+ ]
150
+ },
151
+ {
152
+ "cell_type": "markdown",
153
+ "metadata": {},
154
+ "source": [
155
+ "#### Energy Breakdown\n",
156
+ "This test explores the energy, area, and latency of the accelerator\n",
157
+ "computing MVM operations. We note a few differences from the original ISAAC\n",
158
+ "paper. Notably, we made a few changes to the quantization, and we use\n",
159
+ "data-value-dependent models while ISAAC used a simple fixed-power model.\n",
160
+ "\n",
161
+ "We note:\n",
162
+ "- Energy is dominated by the ADC and memory cells due to the high ADC precision\n",
163
+ " and large number of slices.\n",
164
+ "- Area is dominated by ADC.\n"
165
+ ]
166
+ },
167
+ {
168
+ "cell_type": "code",
169
+ "execution_count": null,
170
+ "metadata": {},
171
+ "outputs": [],
172
+ "source": [
173
+ "af.set_n_parallel_jobs(1)\n",
174
+ "spec = get_spec('isaac', add_dummy_main_memory=True)\n",
175
+ "spec.mapper.afm.metrics = af.mapper.FFM.Metrics.ENERGY\n",
176
+ "results = af.mapper.FFM.map_workload_to_arch(spec)\n",
177
+ "energy = results.per_compute().energy(per_component=True)\n",
178
+ "\n",
179
+ "spec_energy_area = spec.calculate_component_area_energy_latency_leak()\n",
180
+ "area = spec_energy_area.arch.per_component_total_area\n",
181
+ "\n",
182
+ "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n",
183
+ "bar(\n",
184
+ " energy,\n",
185
+ " \"Component\",\n",
186
+ " \"Energy/Compute (J)\",\n",
187
+ " \"Energy Breakdown\",\n",
188
+ " ax,\n",
189
+ ")\n",
190
+ "\n",
191
+ "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n",
192
+ "bar(\n",
193
+ " area,\n",
194
+ " \"Component\",\n",
195
+ " \"Area (m^2)\",\n",
196
+ " \"Area Breakdown\",\n",
197
+ " ax,\n",
198
+ ")"
199
+ ]
200
+ },
201
+ {
202
+ "cell_type": "code",
203
+ "execution_count": null,
204
+ "metadata": {},
205
+ "outputs": [],
206
+ "source": [
207
+ "# import sys\n",
208
+ "# import os\n",
209
+ "\n",
210
+ "# # fmt: oaf\n",
211
+ "# THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))\n",
212
+ "# MACRO_NAME = os.path.basename(THIS_SCRIPT_DIR)\n",
213
+ "# sys.path.append(os.path.abspath(os.path.join(THIS_SCRIPT_DIR, '..', '..', '..', '..')))\n",
214
+ "# from scripts import utils as utl\n",
215
+ "# import scripts\n",
216
+ "# # fmt: on\n",
217
+ "\n",
218
+ "# def test_full_dnn(dnn_name: str):\n",
219
+ "# \"\"\"\n",
220
+ "# This test explores the energy, area, and latency of the accelerator when\n",
221
+ "# running full DNN workloads.\n",
222
+ "# \"\"\"\n",
223
+ "# dnn_dir = utl.path_from_model_dir(f\"workloads/{dnn_name}\")\n",
224
+ "# layer_paths = [\n",
225
+ "# os.path.join(dnn_dir, l) for l in os.listdir(dnn_dir) if l.endswith(\".yaml\")\n",
226
+ "# ]\n",
227
+ "\n",
228
+ "# layer_paths = [l for l in layer_paths if \"From einsum\" not in open(l, \"r\").read()]\n",
229
+ "\n",
230
+ "# results = utl.parallel_test(\n",
231
+ "# utl.delayed(utl.run_layer)(\n",
232
+ "# macro=MACRO_NAME,\n",
233
+ "# layer=l,\n",
234
+ "# tile=\"isaac\",\n",
235
+ "# chip=\"large_router\",\n",
236
+ "# )\n",
237
+ "# for l in layer_paths\n",
238
+ "# )\n",
239
+ "# results.clear_zero_energies()\n",
240
+ "# return results\n",
241
+ "\n",
242
+ "\n",
243
+ "# if __name__ == \"__main__\":\n",
244
+ "# test_energy_breakdown()\n",
245
+ "# test_full_dnn(\"resnet18\")\n"
246
+ ]
247
+ }
248
+ ],
249
+ "metadata": {
250
+ "kernelspec": {
251
+ "display_name": "Python 3",
252
+ "language": "python",
253
+ "name": "python3"
254
+ },
255
+ "language_info": {
256
+ "codemirror_mode": {
257
+ "name": "ipython",
258
+ "version": 3
259
+ },
260
+ "file_extension": ".py",
261
+ "mimetype": "text/x-python",
262
+ "name": "python",
263
+ "nbconvert_exporter": "python",
264
+ "pygments_lexer": "ipython3",
265
+ "version": "3.12.11"
266
+ }
267
+ },
268
+ "nbformat": 4,
269
+ "nbformat_minor": 4
270
+ }