stream-dse 2.2.0__tar.gz → 2.3.0__tar.gz

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 (278) hide show
  1. {stream_dse-2.2.0/stream_dse.egg-info → stream_dse-2.3.0}/PKG-INFO +20 -3
  2. {stream_dse-2.2.0 → stream_dse-2.3.0}/pyproject.toml +28 -5
  3. stream_dse-2.3.0/stream/__init__.py +1 -0
  4. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/traffic.py +4 -4
  5. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/layouts.py +3 -2
  6. stream_dse-2.3.0/stream/stages/estimation/accelforge/__init__.py +1 -0
  7. stream_dse-2.3.0/stream/stages/estimation/accelforge/arch.py +140 -0
  8. stream_dse-2.3.0/stream/stages/estimation/accelforge/backend.py +220 -0
  9. stream_dse-2.3.0/stream/stages/estimation/accelforge/library.py +32 -0
  10. stream_dse-2.3.0/stream/stages/estimation/accelforge/mapper.py +191 -0
  11. stream_dse-2.3.0/stream/stages/estimation/accelforge/tree.py +148 -0
  12. stream_dse-2.3.0/stream/stages/estimation/accelforge/workload.py +170 -0
  13. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/estimation/core_cost_backends.py +78 -7
  14. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/estimation/core_cost_estimation.py +57 -17
  15. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/estimation/zigzag_cost_estimator.py +69 -11
  16. {stream_dse-2.2.0 → stream_dse-2.3.0/stream_dse.egg-info}/PKG-INFO +20 -3
  17. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream_dse.egg-info/SOURCES.txt +7 -0
  18. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream_dse.egg-info/entry_points.txt +1 -0
  19. stream_dse-2.3.0/stream_dse.egg-info/requires.txt +46 -0
  20. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_data_layout.py +26 -6
  21. stream_dse-2.2.0/stream/__init__.py +0 -1
  22. stream_dse-2.2.0/stream_dse.egg-info/requires.txt +0 -28
  23. {stream_dse-2.2.0 → stream_dse-2.3.0}/LICENSE +0 -0
  24. {stream_dse-2.2.0 → stream_dse-2.3.0}/README.md +0 -0
  25. {stream_dse-2.2.0 → stream_dse-2.3.0}/setup.cfg +0 -0
  26. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/aie_setup.py +0 -0
  27. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/allocation/__init__.py +0 -0
  28. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/allocation/allocation.py +0 -0
  29. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/allocation/artifacts.py +0 -0
  30. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/allocation/lowering.py +0 -0
  31. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/allocation/problem.py +0 -0
  32. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/allocation/solution.py +0 -0
  33. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/allocation/steady_state.py +0 -0
  34. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/api.py +0 -0
  35. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/context/aie_context.py +0 -0
  36. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/dialects/__init__.py +0 -0
  37. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/dialects/stream.py +0 -0
  38. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/fifo_depths.py +0 -0
  39. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/__init__.py +0 -0
  40. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/aie_kernel.py +0 -0
  41. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/binding.py +0 -0
  42. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/eltwise_mul.py +0 -0
  43. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/flash.py +0 -0
  44. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/gemm.py +0 -0
  45. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/library.py +0 -0
  46. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/mlir_aie.py +0 -0
  47. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/registry.py +0 -0
  48. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/silu.py +0 -0
  49. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/kernels/softmax.py +0 -0
  50. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/__init__.py +0 -0
  51. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/aie_add_tracing_script.py +0 -0
  52. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/aie_convert_ofs.py +0 -0
  53. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/aie_dispatch.py +0 -0
  54. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/aie_move_tile_ops_up.py +0 -0
  55. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/aie_tiles.py +0 -0
  56. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/clear_memory_space.py +0 -0
  57. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/convert_aie_kernels.py +0 -0
  58. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/convert_stream_to_aie.py +0 -0
  59. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/hoist_scale_acquires.py +0 -0
  60. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/iteration_space_to_for.py +0 -0
  61. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/compiler/transforms/unroll.py +0 -0
  62. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/cost_model/bandwidth.py +0 -0
  63. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/cost_model/communication_manager.py +0 -0
  64. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/cost_model/core_cost.py +0 -0
  65. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/cost_model/core_cost_lut.py +0 -0
  66. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/cost_model/layout.py +0 -0
  67. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/cost_model/memory_accesses.py +0 -0
  68. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/cost_model/roofline.py +0 -0
  69. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/datatypes.py +0 -0
  70. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/frontends/__init__.py +0 -0
  71. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/frontends/onnx.py +0 -0
  72. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/frontends/torch_export.py +0 -0
  73. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/architecture/accelerator.py +0 -0
  74. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/architecture/backends/__init__.py +0 -0
  75. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/architecture/backends/aie2.py +0 -0
  76. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/architecture/backends/zigzag.py +0 -0
  77. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/architecture/core.py +0 -0
  78. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/architecture/memory.py +0 -0
  79. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/architecture/noc/communication_link.py +0 -0
  80. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/bundle.py +0 -0
  81. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/cost.py +0 -0
  82. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/hardware/ports.py +0 -0
  83. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/hardware/cores/aie_tile.yaml +0 -0
  84. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/hardware/cores/mem_tile_256KB.yaml +0 -0
  85. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/hardware/cores/mem_tile_512KB.yaml +0 -0
  86. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/hardware/single_col.yaml +0 -0
  87. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/hardware/single_core.yaml +0 -0
  88. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/hardware/whole_array.yaml +0 -0
  89. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/hardware/whole_array_strix.yaml +0 -0
  90. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/kernels/aie2p.toml +0 -0
  91. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/mapping/make_gemm_mapping.py +0 -0
  92. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/mapping/make_swiglu_mapping.py +0 -0
  93. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/workload/make_onnx_gemm.py +0 -0
  94. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/aie/workload/make_onnx_swiglu.py +0 -0
  95. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/eyeriss_like.yaml +0 -0
  96. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/fusemax_array.yaml +0 -0
  97. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/fusemax_vec.yaml +0 -0
  98. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/meta_prototype.yaml +0 -0
  99. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/pooling.yaml +0 -0
  100. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/simba_chiplet.yaml +0 -0
  101. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/simd.yaml +0 -0
  102. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/tpu_like.yaml +0 -0
  103. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/tpu_v7_mxu.yaml +0 -0
  104. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/tpu_v7_vmem.yaml +0 -0
  105. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/cores/tpu_v7_vpu.yaml +0 -0
  106. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/eyeriss_like_dual_core.yaml +0 -0
  107. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/eyeriss_like_quad_core.yaml +0 -0
  108. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/eyeriss_like_single_core.yaml +0 -0
  109. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/fusemax.yaml +0 -0
  110. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/meta_prototype_dual_core_simd_offchip.yaml +0 -0
  111. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/simba.yaml +0 -0
  112. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/simba_small.yaml +0 -0
  113. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/tpu_like_quad_core.yaml +0 -0
  114. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/examples/hardware/tpu_v7_ironwood.yaml +0 -0
  115. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/cores/pooling.yaml +0 -0
  116. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/cores/shared_testing_core1.yaml +0 -0
  117. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/cores/shared_testing_core2.yaml +0 -0
  118. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/cores/simd.yaml +0 -0
  119. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/cores/testing_core1.yaml +0 -0
  120. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/cores/testing_core2.yaml +0 -0
  121. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/cores/tpu_like.yaml +0 -0
  122. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/tpu_like_quad_core.yaml +0 -0
  123. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/tpu_like_ring_hbm.yaml +0 -0
  124. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/hardware/tpu_v7_ironwood_hbm_per_chiplet.yaml +0 -0
  125. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/mapping/make_2_conv_mapping.py +0 -0
  126. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/workload/make_2_conv.py +0 -0
  127. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/workload/make_attention_head.py +0 -0
  128. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/workload/make_conv_relu_flatten_gemm.py +0 -0
  129. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/workload/make_decode_attention.py +0 -0
  130. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/workload/make_resnet_subgraph.py +0 -0
  131. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/workload/make_scan.py +0 -0
  132. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/inputs/testing/workload/make_swiglu.py +0 -0
  133. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/instrumentation.py +0 -0
  134. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/ir/__init__.py +0 -0
  135. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/ir/accelerator.py +0 -0
  136. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/ir/allocation.py +0 -0
  137. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/ir/graph_view.py +0 -0
  138. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/ir/infeasibility.py +0 -0
  139. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/ir/roofline.py +0 -0
  140. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/ir/workload.py +0 -0
  141. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/mapping/blocks.py +0 -0
  142. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/mapping/capacity_tiler.py +0 -0
  143. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/mapping/chain_placement.py +0 -0
  144. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/mapping/generic_generator.py +0 -0
  145. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/mapping/mapping.py +0 -0
  146. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/mapping/work_share.py +0 -0
  147. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/mcp/__init__.py +0 -0
  148. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/mcp/jobs.py +0 -0
  149. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/mcp/server.py +0 -0
  150. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/__init__.py +0 -0
  151. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/__init__.py +0 -0
  152. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/__init__.py +0 -0
  153. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/allocation_model.py +0 -0
  154. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/diagnosis.py +0 -0
  155. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/__init__.py +0 -0
  156. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/aie2.py +0 -0
  157. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/dma.py +0 -0
  158. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/energy.py +0 -0
  159. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/latency.py +0 -0
  160. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/memory.py +0 -0
  161. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/memory_ports.py +0 -0
  162. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/offchip.py +0 -0
  163. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/overlap.py +0 -0
  164. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/reuse.py +0 -0
  165. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/families/routing.py +0 -0
  166. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/formulation.py +0 -0
  167. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/hardware.py +0 -0
  168. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/quantities.py +0 -0
  169. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/report.py +0 -0
  170. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/space.py +0 -0
  171. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/allocation/constraint_optimization/utils.py +0 -0
  172. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/solver/__init__.py +0 -0
  173. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/opt/solver/solver.py +0 -0
  174. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/accelerator_factory.py +0 -0
  175. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/accelerator_validator.py +0 -0
  176. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/core_validator.py +0 -0
  177. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/mapping_factory.py +0 -0
  178. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/mapping_parser.py +0 -0
  179. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/mapping_validator.py +0 -0
  180. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/batch_norm.py +0 -0
  181. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/conv.py +0 -0
  182. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/einsum.py +0 -0
  183. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/elementwise.py +0 -0
  184. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/gemm.py +0 -0
  185. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/global_average_pool.py +0 -0
  186. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/layout.py +0 -0
  187. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/matmul.py +0 -0
  188. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/max_pool.py +0 -0
  189. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/model.py +0 -0
  190. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/normalization.py +0 -0
  191. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/operator_parser.py +0 -0
  192. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/reduce.py +0 -0
  193. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/slice_gather.py +0 -0
  194. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/parser/onnx/utils.py +0 -0
  195. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/plugins.py +0 -0
  196. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/profiling.py +0 -0
  197. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/__init__.py +0 -0
  198. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/allocation/steady_state_allocation.py +0 -0
  199. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/allocation/steady_state_lowering.py +0 -0
  200. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/codegen/aie_code_generation.py +0 -0
  201. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/codegen/backends.py +0 -0
  202. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/context.py +0 -0
  203. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/estimation/aie_cost_estimator.py +0 -0
  204. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/estimation/memory_accesses_estimation.py +0 -0
  205. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/fixed_mapping_generation.py +0 -0
  206. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/flash_decoding.py +0 -0
  207. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/fusion_analysis.py +0 -0
  208. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/fusion_group_iteration.py +0 -0
  209. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/fusion_proposal.py +0 -0
  210. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/generic_mapping_generation.py +0 -0
  211. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/kernel_state.py +0 -0
  212. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/mapping_generators.py +0 -0
  213. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/normalization_expansion.py +0 -0
  214. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/placement_generation.py +0 -0
  215. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/structural_dedup.py +0 -0
  216. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/tile_search.py +0 -0
  217. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/generation/tiling_generation.py +0 -0
  218. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/parsing/accelerator_parser.py +0 -0
  219. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/parsing/onnx_model_parser.py +0 -0
  220. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/stages/stage.py +0 -0
  221. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/visualization/hardware_graph.py +0 -0
  222. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/visualization/steady_state_trace.py +0 -0
  223. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/_svg.py +0 -0
  224. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/access_relation.py +0 -0
  225. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/affine_access.py +0 -0
  226. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/affine_exact.py +0 -0
  227. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/affine_transform.py +0 -0
  228. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/blocks/__init__.py +0 -0
  229. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/blocks/library.py +0 -0
  230. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/data_movement.py +0 -0
  231. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/decompose.py +0 -0
  232. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/fusion/__init__.py +0 -0
  233. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/fusion/analysis.py +0 -0
  234. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/fusion/proposer.py +0 -0
  235. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/iterator_type.py +0 -0
  236. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/models.py +0 -0
  237. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/node.py +0 -0
  238. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/node_key.py +0 -0
  239. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/normalization.py +0 -0
  240. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/rewrites/__init__.py +0 -0
  241. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/rewrites/base.py +0 -0
  242. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/rewrites/flash_attention.py +0 -0
  243. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/rewrites/flash_decoding.py +0 -0
  244. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/rewrites/reference.py +0 -0
  245. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/steady_state/computation.py +0 -0
  246. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/steady_state/iteration_space.py +0 -0
  247. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/steady_state/node.py +0 -0
  248. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/structure/__init__.py +0 -0
  249. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/structure/block_detect.py +0 -0
  250. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/structure/wl.py +0 -0
  251. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/tensor.py +0 -0
  252. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/utils.py +0 -0
  253. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream/workload/workload.py +0 -0
  254. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream_dse.egg-info/dependency_links.txt +0 -0
  255. {stream_dse-2.2.0 → stream_dse-2.3.0}/stream_dse.egg-info/top_level.txt +0 -0
  256. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_accelerator_ir.py +0 -0
  257. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_ci_workflow.py +0 -0
  258. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_co.py +0 -0
  259. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_conv_windows.py +0 -0
  260. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_core_cost_lut_caching.py +0 -0
  261. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_core_validation.py +0 -0
  262. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_decode_attention.py +0 -0
  263. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_decode_kv.py +0 -0
  264. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_edge_placements.py +0 -0
  265. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_generic_mapping.py +0 -0
  266. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_hardware_bundle.py +0 -0
  267. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_hardware_combinations.py +0 -0
  268. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_layout_einsum_reduce.py +0 -0
  269. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_metrics_capture.py +0 -0
  270. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_on_chip_placement.py +0 -0
  271. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_precision.py +0 -0
  272. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_render_metrics_comment.py +0 -0
  273. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_resnet_mapping.py +0 -0
  274. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_resnet_patterns.py +0 -0
  275. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_roofline.py +0 -0
  276. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_steady_state_detail.py +0 -0
  277. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_systolic.py +0 -0
  278. {stream_dse-2.2.0 → stream_dse-2.3.0}/tests/test_tpu_v7.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stream-dse
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: Stream - Multi-core accelerator design space exploration with layer-fused scheduling
5
5
  Author-email: Arne Symons <arne.symons@kuleuven.be>, Linyan Mei <linyan.mei@kuleuven.be>
6
6
  License: MIT License
@@ -32,8 +32,7 @@ Classifier: Programming Language :: Python
32
32
  Requires-Python: >=3.12
33
33
  Description-Content-Type: text/markdown
34
34
  License-File: LICENSE
35
- Requires-Dist: zigzag-dse==3.9.1
36
- Requires-Dist: six
35
+ Requires-Dist: zigzag-dse==3.10.0
37
36
  Requires-Dist: cerberus
38
37
  Requires-Dist: ortools>=9.15
39
38
  Requires-Dist: pydantic<2.12,>=2.0
@@ -46,6 +45,24 @@ Provides-Extra: exact
46
45
  Requires-Dist: islpy; extra == "exact"
47
46
  Provides-Extra: torch
48
47
  Requires-Dist: torch>=2.4; extra == "torch"
48
+ Provides-Extra: accelforge
49
+ Requires-Dist: numpy>=2.2.0; extra == "accelforge"
50
+ Requires-Dist: pandas>=2.2.0; extra == "accelforge"
51
+ Requires-Dist: tqdm>=4.67.0; extra == "accelforge"
52
+ Requires-Dist: pydantic_core>=2.33.0; extra == "accelforge"
53
+ Requires-Dist: ruamel.yaml>=0.18.0; extra == "accelforge"
54
+ Requires-Dist: islpy>=2025; extra == "accelforge"
55
+ Requires-Dist: jinja2>=3.1.0; extra == "accelforge"
56
+ Requires-Dist: sympy>=1.14.0; extra == "accelforge"
57
+ Requires-Dist: symengine>=0.14.0; extra == "accelforge"
58
+ Requires-Dist: numba>=0.61.2; extra == "accelforge"
59
+ Requires-Dist: matplotlib>=3.10.0; extra == "accelforge"
60
+ Requires-Dist: plotly>=6.1.0; extra == "accelforge"
61
+ Requires-Dist: pydot>=4.0.0; extra == "accelforge"
62
+ Requires-Dist: platformdirs>=4.3.0; extra == "accelforge"
63
+ Requires-Dist: joblib>=1.5.1; extra == "accelforge"
64
+ Requires-Dist: requests>=2.33.1; extra == "accelforge"
65
+ Requires-Dist: hwcomponents==1.0.114; extra == "accelforge"
49
66
  Provides-Extra: dev
50
67
  Requires-Dist: bumpver; extra == "dev"
51
68
  Requires-Dist: pip-tools; extra == "dev"
@@ -21,7 +21,7 @@ namespaces = true
21
21
 
22
22
  [project]
23
23
  name = "stream-dse"
24
- version = "2.2.0"
24
+ version = "2.3.0"
25
25
  description = "Stream - Multi-core accelerator design space exploration with layer-fused scheduling"
26
26
  readme = "README.md"
27
27
  authors = [{ name = "Arne Symons", email = "arne.symons@kuleuven.be" }, { name = "Linyan Mei", email = "linyan.mei@kuleuven.be" }]
@@ -32,9 +32,7 @@ classifiers = [
32
32
  ]
33
33
  keywords = ["stream", "multi-core", "accelerator", "layer-fused", "scheduling", "zigzag", "dse", "design-space-exploration", "machine-learning", "deep-learning", "mapping"]
34
34
  dependencies = [
35
- "zigzag-dse==3.9.1",
36
- # zigzag's mapping validator imports six without declaring it
37
- "six",
35
+ "zigzag-dse==3.10.0",
38
36
  "cerberus",
39
37
  "ortools>=9.15",
40
38
  "pydantic>=2.0,<2.12",
@@ -60,6 +58,29 @@ exact = ["islpy"]
60
58
  # torch.export frontend (stream/frontends/torch_export.py). Optional: the conversion is torch-free and
61
59
  # unit-tested without it; torch is only needed to lower a real ExportedProgram. Heavy, so opt-in.
62
60
  torch = ["torch>=2.4"]
61
+ # AccelForge core-cost backend (stream/stages/estimation/accelforge/). AccelForge itself cannot be listed: its own
62
+ # requirements include hwcomponents-cacti (HP CACTI licence, no sale for compensation), -neurosim (CC BY-NC 4.0) and
63
+ # -library (needs both), none of which the backend uses. This extra lists what AccelForge imports; AccelForge itself
64
+ # is installed with --no-deps (docs/source/accelforge.md).
65
+ accelforge = [
66
+ "numpy>=2.2.0",
67
+ "pandas>=2.2.0",
68
+ "tqdm>=4.67.0",
69
+ "pydantic_core>=2.33.0",
70
+ "ruamel.yaml>=0.18.0",
71
+ "islpy>=2025",
72
+ "jinja2>=3.1.0",
73
+ "sympy>=1.14.0",
74
+ "symengine>=0.14.0",
75
+ "numba>=0.61.2",
76
+ "matplotlib>=3.10.0",
77
+ "plotly>=6.1.0",
78
+ "pydot>=4.0.0",
79
+ "platformdirs>=4.3.0",
80
+ "joblib>=1.5.1",
81
+ "requests>=2.33.1",
82
+ "hwcomponents==1.0.114",
83
+ ]
63
84
  dev = ["bumpver", "pip-tools", "build", "twine", "pre-commit", "pytest", "pytest-timeout", "hypothesis"]
64
85
  # The AIE codegen dialects (xdsl-aie, snax-mlir) cannot be an extra: they are direct-reference
65
86
  # (git) installs that PyPI forbids in package metadata. Install them after `pip install stream-dse`
@@ -89,6 +110,8 @@ timing = "stream.profiling:TimingInstrumentation"
89
110
  [project.entry-points."stream.core_cost_backends"]
90
111
  aie = "stream.stages.estimation.core_cost_backends:AIE_BACKEND"
91
112
  zigzag = "stream.stages.estimation.core_cost_backends:ZIGZAG_BACKEND"
113
+ # Never chosen by the priority rule (priority -10): SolveOptions(stage_options={"core_cost_backend": "accelforge"}).
114
+ accelforge = "stream.stages.estimation.accelforge.backend:ACCELFORGE_BACKEND"
92
115
 
93
116
  # Code generation backends: the entry-point name is the backend's `name`, its object a CodegenBackend
94
117
  # that `claims` the accelerators it emits code for and returns the per-group codegen `stage()`.
@@ -125,7 +148,7 @@ generic = "stream.stages.generation.mapping_generators:GENERIC_MAPPING"
125
148
  Homepage = "https://github.com/KULeuven-MICAS/stream"
126
149
 
127
150
  [tool.bumpver]
128
- current_version = "2.2.0"
151
+ current_version = "2.3.0"
129
152
  version_pattern = "MAJOR.MINOR.PATCH"
130
153
  commit_message = "bump version {old_version} -> {new_version}"
131
154
  commit = true
@@ -0,0 +1 @@
1
+ __version__ = "2.3.0"
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Any
7
7
 
8
8
  from stream.hardware.ports import READ, WRITE, Port, PortKey
9
9
  from stream.opt.allocation.constraint_optimization.utils import active_fraction, get_active_latency
10
- from stream.stages.estimation.core_cost_backends import CoreCostBackend, port_traffic, select_backend
10
+ from stream.stages.estimation.core_cost_backends import discover_backends, entry_backend, port_traffic
11
11
  from stream.workload.workload import ComputationNode, InEdge, TransferNode
12
12
 
13
13
  if TYPE_CHECKING:
@@ -124,13 +124,13 @@ def node_traffic(ctx: FormulationContext) -> list[NodeTraffic]:
124
124
  """The top-level port traffic of each node from its cost backend, on each core it runs on, at a port of the
125
125
  memory that core holds the operand in."""
126
126
  traffic: list[NodeTraffic] = []
127
- backends: dict[Core, CoreCostBackend] = {}
127
+ backends = discover_backends()
128
128
  accelerator = ctx.space.accelerator
129
129
  for node in ctx.space.ssc_nodes:
130
130
  fraction = active_fraction(node, ctx.space.ssis)
131
131
  for core in placed_cores(ctx, node):
132
- backend = backends.setdefault(core, select_backend(core))
133
- for operand, direction, bits in port_traffic(backend, ctx.space.cost_lut.get_cost(node, core)):
132
+ entry = ctx.space.cost_lut.get_cost(node, core)
133
+ for operand, direction, bits in port_traffic(entry_backend(entry, core, backends), entry):
134
134
  port = accelerator.ports.port_for(core, direction, operand, accelerator.memory_holding(core, operand))
135
135
  if port is not None:
136
136
  traffic.append(NodeTraffic(port, bits * fraction, ctx.space.slot_of[node]))
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
6
6
 
7
7
  from stream.cost_model.layout import Layout, Rate, transfer_stream
8
8
  from stream.hardware.ports import READ, WRITE
9
- from stream.stages.estimation.core_cost_backends import contiguous_axes, select_backend
9
+ from stream.stages.estimation.core_cost_backends import contiguous_axes, entry_backend
10
10
  from stream.workload.workload import ComputationNode, InEdge, OutEdge, Tensor, TransferNode
11
11
 
12
12
  if TYPE_CHECKING:
@@ -68,7 +68,8 @@ class CopyLayouts:
68
68
  if (found := self._needs.get((node, index))) is None:
69
69
  found = frozenset()
70
70
  for core in self.space.cost_lut.get_cores(node):
71
- axes = contiguous_axes(select_backend(core), self.space.cost_lut.get_cost(node, core))
71
+ entry = self.space.cost_lut.get_cost(node, core)
72
+ axes = contiguous_axes(entry_backend(entry, core), entry)
72
73
  if axes:
73
74
  found = axes[index]
74
75
  break
@@ -0,0 +1 @@
1
+ """AccelForge as an optional core-cost backend: Stream nodes as Einsums and ZigZag cores as arches."""
@@ -0,0 +1,140 @@
1
+ """ZigZag compute cores as AccelForge arches, with Stream's own energies and a 1 Hz clock so AccelForge's seconds are
2
+ Stream's cycles; a memory operand maps to a rename (``I1``: ``input``, ``I2``: ``weight``, ``O``: ``output``). See
3
+ ``docs/source/accelforge.md`` for what does not carry over."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import math
8
+ from collections.abc import Mapping
9
+ from typing import TYPE_CHECKING
10
+
11
+ import stream.stages.estimation.accelforge.library # noqa: F401
12
+
13
+ # isort: split
14
+ from accelforge import Spec
15
+ from accelforge.frontend.arch import Action, Arch, Compute, Container, Memory, Spatial, TensorHolderAction, Tensors
16
+ from stream.datatypes import ELEMENT_BITS
17
+ from stream.stages.estimation.accelforge.tree import (
18
+ CLOCK_HZ,
19
+ COMPUTE,
20
+ PJ,
21
+ UNBOUNDED_SIZE_BITS,
22
+ Port,
23
+ component_name,
24
+ depth,
25
+ layout,
26
+ one_value_periods,
27
+ ports,
28
+ zigzag_core,
29
+ )
30
+ from stream.stages.estimation.accelforge.workload import NOTHING, PARTIAL_SUMS, ROLE_OF_OPERAND
31
+
32
+ if TYPE_CHECKING:
33
+ from zigzag.hardware.architecture.memory_level import MemoryLevel
34
+
35
+ from accelforge.frontend.workload import Workload
36
+ from stream.hardware.architecture.backends import ZigZagCoreBackend
37
+ from stream.hardware.architecture.core import Core
38
+
39
+ ROLES = " | ".join(ROLE_OF_OPERAND.values())
40
+
41
+
42
+ def explicit_spec(arch: Arch, workload: Workload) -> Spec:
43
+ """A spec of ``arch`` and ``workload`` that uses only the arch's explicit values, never a component model."""
44
+ spec = Spec(arch=arch, workload=workload)
45
+ spec.config.component_models = []
46
+ spec.config.use_installed_component_models = False
47
+ return spec
48
+
49
+
50
+ def core_to_arch(core: Core, *, free_memory_order: bool = False) -> Arch:
51
+ """The AccelForge arch of a ZigZag compute core: memories outermost first, a fanout per array dimension below the
52
+ memories serving it, a MAC compute leaf. An operand's top memory is unbounded, as ZigZag's LOMA treats it;
53
+ ``free_memory_order`` lets different tensors' storage nest in any order, as ZigZag does."""
54
+ zigzag = zigzag_core(core)
55
+ array = zigzag.operational_array
56
+ dims, order, placed = layout(zigzag)
57
+ accumulator = (getattr(core, "operand_precision", None) or {}).get("accumulator")
58
+ nodes: list[Memory | Container | Compute] = []
59
+ memories: list[Memory] = [] # root first
60
+ for fanouts_above in range(len(order) + 1):
61
+ for level in (level for level in placed if depth(level, order) == fanouts_above):
62
+ copies = math.prod(size for dim, size in order[:fanouts_above] if dim in level.served_dimensions)
63
+ units = math.prod(size for dim, size in dims if dim in level.served_dimensions)
64
+ memory = _memory(zigzag, level, copies, units, accumulator)
65
+ memory.tensors.force_memory_hierarchy_order = not free_memory_order
66
+ nodes.append(memory)
67
+ memories.append(memory)
68
+ if fanouts_above < len(order):
69
+ nodes.append(_fanout(*order[fanouts_above]))
70
+ outermost = memories[0] # it keeps every tensor no rename names too, such as a third input
71
+ outermost.tensors.keep = f"{outermost.tensors.keep} | ~({ROLES})"
72
+ nodes.append(_compute(COMPUTE, array.unit.energy_cost * PJ, CLOCK_HZ))
73
+ return Arch(nodes=nodes)
74
+
75
+
76
+ def _memory(zigzag: ZigZagCoreBackend, level: MemoryLevel, copies: int, units: int, accumulator: str | None) -> Memory:
77
+ """A memory serving ``units`` array units per instance, ``copies`` times over dimensions it should serve."""
78
+ hierarchy = zigzag.memory_hierarchy
79
+ operands = [str(operand) for operand in level.operands]
80
+ tops = {str(op) for op in level.operands if hierarchy.get_memory_levels(op)[-1] is level}
81
+ instance = level.memory_instance
82
+ read, write, separate = ports(level, instance.r_cost, instance.w_cost)
83
+ size = math.inf if tops or instance.size >= UNBOUNDED_SIZE_BITS else instance.size
84
+ if copies > 1:
85
+ size = size // copies if math.isfinite(size) else size
86
+ read, write = (
87
+ Port(p.bits_per_action, p.pj_per_action, p.actions_per_cycle / copies, p.word_bits) for p in (read, write)
88
+ )
89
+ bits_per_value = {}
90
+ if accumulator and "O" in operands and "O" not in tops:
91
+ bits_per_value = {PARTIAL_SUMS: ELEMENT_BITS[accumulator]}
92
+ roles = [ROLE_OF_OPERAND[op] for op in operands]
93
+ innermost = {str(op) for op in level.operands if hierarchy.get_memory_levels(op)[0] is level}
94
+ one_value = [ROLE_OF_OPERAND[op] for op in operands if units == 1 and op in innermost]
95
+ partial_sum_bits = bits_per_value.get(PARTIAL_SUMS)
96
+ return Memory(
97
+ name=component_name(level.name),
98
+ size=size,
99
+ leak_power=0,
100
+ area=0,
101
+ separate_read_write_ports=separate,
102
+ bits_per_value=bits_per_value,
103
+ actions=[
104
+ _memory_action(name, port, *one_value_periods(port, roles, one_value, partial_sum_bits))
105
+ for name, port in (("read", read), ("write", write))
106
+ ],
107
+ tensors=Tensors(
108
+ keep=" | ".join(roles) or NOTHING,
109
+ may_keep=NOTHING,
110
+ ),
111
+ )
112
+
113
+
114
+ def _memory_action(
115
+ name: str, port: Port, values_per_action: Mapping[str, str] | None = None, throughput_scale: str | float = 1
116
+ ) -> TensorHolderAction:
117
+ return TensorHolderAction(
118
+ name=name,
119
+ energy=port.pj_per_action * PJ,
120
+ throughput=port.actions_per_cycle * CLOCK_HZ,
121
+ throughput_scale=throughput_scale,
122
+ latency=0,
123
+ bits_per_action=port.bits_per_action,
124
+ values_per_action=dict(values_per_action or {}),
125
+ )
126
+
127
+
128
+ def _fanout(dim: object, size: int) -> Container:
129
+ """A fanout of ``size`` along the operational-array dimension ``dim``."""
130
+ spatial = Spatial(name=str(dim), fanout=size)
131
+ return Container(name=f"array_{dim}", spatial=[spatial])
132
+
133
+
134
+ def _compute(name: str, energy_j: float, throughput: float) -> Compute:
135
+ return Compute(
136
+ name=name,
137
+ leak_power=0,
138
+ area=0,
139
+ actions=[Action(name="compute", energy=energy_j, throughput=throughput, latency=0)],
140
+ )
@@ -0,0 +1,220 @@
1
+ """The ``accelforge`` core-cost backend: AccelForge's single-Einsum mapper costs a node on a ZigZag compute core at the
2
+ extent and with the work per point Stream's ZigZag estimator costs it. At priority -10 it is chosen only by name, with
3
+ the ``core_cost_backend`` stage option; ``core_cost_options["accelforge"]`` gives it :class:`AccelForgeOptions`. See
4
+ ``docs/source/accelforge.md``."""
5
+
6
+ from __future__ import annotations
7
+
8
+ import dataclasses
9
+ import functools
10
+ import importlib.metadata
11
+ import importlib.util
12
+ import logging
13
+ import math
14
+ from collections.abc import Mapping
15
+ from dataclasses import dataclass
16
+ from typing import TYPE_CHECKING, Any
17
+
18
+ from xdsl.ir.affine import AffineDimExpr
19
+
20
+ from stream.cost_model.core_cost import CoreCostEntry
21
+ from stream.datatypes import ELEMENT_BITS
22
+ from stream.hardware.ports import OUTPUT, READ_BY_DATAPATH, WRITE_BY_DATAPATH, input_role
23
+ from stream.stages.estimation.accelforge.tree import COMPUTE, PJ, zigzag_core
24
+ from stream.stages.estimation.accelforge.workload import (
25
+ ZIGZAG_INPUTS,
26
+ UnsupportedConversion,
27
+ describe,
28
+ tensor_name,
29
+ )
30
+ from stream.stages.estimation.core_cost_backends import ZIGZAG_BACKEND
31
+ from stream.workload.utils import is_mac_operator_type, operand_inputs
32
+
33
+ if TYPE_CHECKING:
34
+ from stream.hardware.architecture.core import Core
35
+ from stream.stages.estimation.core_cost_backends import ContiguousAxes, CoreCostContext, PortTraffic
36
+ from stream.stages.estimation.zigzag_cost_estimator import ZigZagCostEstimator
37
+ from stream.workload.node import ComputationNode
38
+
39
+ logger = logging.getLogger(__name__)
40
+
41
+ NAME = "accelforge"
42
+ MODEL_REVISION = 1
43
+ """Bumped whenever a change here or in the converters changes what an entry holds, so cached entries are recomputed."""
44
+
45
+
46
+ class AccelForgeEstimationError(RuntimeError):
47
+ """AccelForge could not cost a node it can express on a core it claims."""
48
+
49
+
50
+ @dataclass(frozen=True)
51
+ class AccelForgeOptions:
52
+ """``memory_order``: ``free`` (falling back to ``forced`` where AccelForge rejects its own template) or ``forced``;
53
+ ``imperfect_spatial_loops``: let a fanout unroll part of a dim it does not divide."""
54
+
55
+ memory_order: str = "free"
56
+ imperfect_spatial_loops: bool = False
57
+
58
+ @classmethod
59
+ def parse(cls, options: Mapping[str, Any]) -> AccelForgeOptions:
60
+ try:
61
+ parsed = cls(**options)
62
+ except TypeError as error:
63
+ raise ValueError(f"core_cost_options[{NAME!r}]: {error}") from None
64
+ if parsed.memory_order not in ("free", "forced"):
65
+ raise ValueError(f"core_cost_options[{NAME!r}]: memory_order must be 'free' or 'forced'")
66
+ return parsed
67
+
68
+
69
+ @dataclass(frozen=True)
70
+ class MappedNode:
71
+ """AccelForge's best mapping of a node, in its units (cycles, J, actions), and how the search went."""
72
+
73
+ latency: float
74
+ energy_j: float
75
+ actions: Mapping[tuple[str, str, str], float]
76
+ """Action counts by (component, tensor, action); compute has tensor ``"None"``."""
77
+ bits_per_action: Mapping[tuple[str, str], float]
78
+ spatial_unrolling: Mapping[int, int]
79
+ temporal_cycles: int
80
+ top_storage: Mapping[str, str]
81
+ """Per tensor, the outermost component storing it in the mapping."""
82
+ units: int
83
+ mapping: tuple[str, ...]
84
+ memory_order: str
85
+ fallback: str | None
86
+ wall_s: float
87
+
88
+
89
+ @functools.cache
90
+ def accelforge_installed() -> bool:
91
+ """Whether accelforge can be imported, found without importing it."""
92
+ return importlib.util.find_spec("accelforge") is not None
93
+
94
+
95
+ class AccelForgeBackend:
96
+ """Claims the ZigZag compute cores the arch converter accepts, when accelforge is installed."""
97
+
98
+ name = NAME
99
+ priority = -10
100
+
101
+ def claims(self, core: Core) -> bool:
102
+ if not accelforge_installed():
103
+ return False
104
+ try:
105
+ zigzag_core(core)
106
+ except UnsupportedConversion:
107
+ return False
108
+ return True
109
+
110
+ def make(self, context: CoreCostContext) -> AccelForgeEstimator:
111
+ options = AccelForgeOptions.parse(context.core_cost_options.get(NAME, {}))
112
+ return AccelForgeEstimator(ZIGZAG_BACKEND.make(context), options)
113
+
114
+ def cache_identity(self, options: Mapping[str, Any]) -> dict[str, Any]:
115
+ """The options, the converters' revision and AccelForge's version."""
116
+ version = importlib.metadata.version(NAME) if accelforge_installed() else None
117
+ return {**dataclasses.asdict(AccelForgeOptions.parse(options)), "model_revision": MODEL_REVISION, NAME: version}
118
+
119
+ def port_traffic(self, entry: CoreCostEntry) -> PortTraffic:
120
+ return tuple(entry.metadata.get("port_traffic", ()))
121
+
122
+ def contiguous_axes(self, entry: CoreCostEntry) -> ContiguousAxes:
123
+ """Per operand, the axes AccelForge's spatial loops unroll widest over the array, as ZigZag's rule reads its
124
+ own spatial mapping."""
125
+ unrolled: dict[int, int] = entry.metadata.get("spatial_unrolling", {})
126
+ if entry.layer is None:
127
+ return ()
128
+ needs: list[frozenset[int]] = []
129
+ for access in entry.layer.operand_mapping:
130
+ factors = {
131
+ axis: unrolled.get(result.position, 1)
132
+ for axis, result in enumerate(access.results)
133
+ if isinstance(result, AffineDimExpr)
134
+ }
135
+ widest = max(factors.values(), default=1)
136
+ needs.append(frozenset(axis for axis, f in factors.items() if f == widest and f > 1))
137
+ return tuple(needs)
138
+
139
+
140
+ @dataclass
141
+ class AccelForgeEstimator:
142
+ zigzag: ZigZagCostEstimator
143
+ """The run's ZigZag estimator: it sizes the nodes and costs those no Einsum can express."""
144
+ options: AccelForgeOptions
145
+
146
+ def estimate(self, node: ComputationNode, core: Core) -> CoreCostEntry:
147
+ """AccelForge's cost of ``node`` on ``core``; ZigZag's, recording why, for a node no Einsum can express."""
148
+ try:
149
+ einsum = describe(node, tuple(self.zigzag.create_layer_dim_sizes(node).data.values()))
150
+ except UnsupportedConversion as refusal:
151
+ logger.warning(
152
+ "AccelForge cannot express %s, so ZigZag costs it on core %s: %s", node.name, core.id, refusal
153
+ )
154
+ entry = self.zigzag.estimate(node, core)
155
+ return dataclasses.replace(entry, metadata={**entry.metadata, "accelforge_refused": str(refusal)})
156
+ from stream.stages.estimation.accelforge.mapper import map_node # noqa: PLC0415 -- accelforge is optional
157
+
158
+ try:
159
+ mapped = map_node(einsum, core, self.options.memory_order, self.options.imperfect_spatial_loops)
160
+ except Exception as error:
161
+ raise AccelForgeEstimationError(
162
+ f"AccelForge could not cost node {node.name} on core {core.id} ({core.core_type}): "
163
+ f"{type(error).__name__}: {error}"
164
+ ) from error
165
+ return self.entry(node, core, mapped)
166
+
167
+ def entry(self, node: ComputationNode, core: Core, mapped: MappedNode) -> CoreCostEntry:
168
+ """The entry of ``mapped``, with each point of ``node`` costing the operations and cycles of the operators it
169
+ expands into, as Stream's ZigZag estimator charges them."""
170
+ ops, cycles_per_point = self.zigzag.work_per_op(node)
171
+ macs = mapped.actions.get((COMPUTE, "None", "compute"), 0.0)
172
+ compute = mapped.temporal_cycles * cycles_per_point
173
+ metadata = {
174
+ "backend": NAME,
175
+ "mapping": mapped.mapping,
176
+ "mapper_wall_s": mapped.wall_s,
177
+ "memory_order": mapped.memory_order,
178
+ "spatial_unrolling": dict(mapped.spatial_unrolling),
179
+ "port_traffic": port_traffic(node, core, mapped),
180
+ }
181
+ if mapped.fallback:
182
+ metadata["memory_order_fallback"] = mapped.fallback
183
+ return CoreCostEntry(
184
+ energy_total=mapped.energy_j / PJ + macs * core.operational_array.unit.energy_cost * (ops - 1),
185
+ latency_total=max(mapped.latency, compute),
186
+ ideal_cycle=float(math.ceil(math.ceil(macs / mapped.units) * cycles_per_point)),
187
+ ideal_temporal_cycle=float(compute),
188
+ layer=node,
189
+ metadata=metadata,
190
+ )
191
+
192
+
193
+ def port_traffic(node: ComputationNode, core: Core, mapped: MappedNode) -> PortTraffic:
194
+ """Bits each operand a ZigZag core serves moves between its top memory, its outermost storage in the mapping,
195
+ and the datapath below. Partial sums, which AccelForge keeps there at the output's precision, move at the core's
196
+ accumulator precision, as ZigZag prices them."""
197
+ operands = [(tensor, input_role(k)) for k, tensor in enumerate(operand_inputs(node)[:ZIGZAG_INPUTS], start=1)]
198
+ operands.append((node.outputs[0], OUTPUT))
199
+ accumulator = (getattr(core, "operand_precision", None) or {}).get("accumulator")
200
+ traffic: list[tuple[str, str, float]] = []
201
+ for tensor, role in operands:
202
+ name = tensor_name(tensor)
203
+ if (top := mapped.top_storage.get(name)) is None:
204
+ continue
205
+ reads, writes = (
206
+ mapped.actions.get((top, name, a), 0.0) * mapped.bits_per_action[top, a] for a in ("read", "write")
207
+ )
208
+ if role == OUTPUT and accumulator and is_mac_operator_type(node.type) and reads:
209
+ ratio = ELEMENT_BITS[accumulator] / tensor.operand_type.bitwidth
210
+ # Every partial sum read back was written by an earlier pass: those writes, not the last pass's, widen too
211
+ reads, writes = reads * ratio, writes + min(reads, writes) * (ratio - 1)
212
+ traffic.extend(
213
+ (role, direction, bits)
214
+ for direction, bits in ((READ_BY_DATAPATH, reads), (WRITE_BY_DATAPATH, writes))
215
+ if bits
216
+ )
217
+ return tuple(traffic)
218
+
219
+
220
+ ACCELFORGE_BACKEND = AccelForgeBackend()
@@ -0,0 +1,32 @@
1
+ """AccelForge, imported and run without changing the process: :func:`contained` undoes what its code does to the root
2
+ logger (its dependency ``hwcomponents`` calls ``logging.basicConfig`` and its root-level ``logging.info`` calls add a
3
+ handler), the warning filters and the environment. It searches in one process, so ties between equally good mappings
4
+ break the same way every run. The modules that build or run AccelForge objects import this first."""
5
+
6
+ import logging
7
+ import os
8
+ import warnings
9
+ from collections.abc import Iterator
10
+ from contextlib import contextmanager
11
+
12
+
13
+ @contextmanager
14
+ def contained() -> Iterator[None]:
15
+ """Run AccelForge code, its own dependencies' deprecation warnings silenced, then restore the root logger's
16
+ handlers and level and remove the environment variables it set."""
17
+ handlers, level, environment = list(logging.root.handlers), logging.root.level, set(os.environ)
18
+ with warnings.catch_warnings():
19
+ warnings.filterwarnings("ignore", module=r"accelforge\.")
20
+ try:
21
+ yield
22
+ finally:
23
+ logging.root.handlers[:] = handlers
24
+ logging.root.setLevel(level)
25
+ for name in set(os.environ) - environment:
26
+ del os.environ[name]
27
+
28
+
29
+ with contained():
30
+ from accelforge.util.parallel import set_n_parallel_jobs
31
+
32
+ set_n_parallel_jobs(1)