stream-dse 2.3.0__tar.gz → 2.4.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 (299) hide show
  1. {stream_dse-2.3.0 → stream_dse-2.4.0}/PKG-INFO +1 -1
  2. {stream_dse-2.3.0 → stream_dse-2.4.0}/pyproject.toml +2 -2
  3. stream_dse-2.4.0/stream/__init__.py +1 -0
  4. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/aie_setup.py +3 -3
  5. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/allocation/allocation.py +17 -11
  6. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/allocation/lowering.py +60 -35
  7. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/allocation/solution.py +2 -2
  8. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/allocation/steady_state.py +98 -18
  9. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/api.py +2 -2
  10. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/kernels/aie_kernel.py +26 -7
  11. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/kernels/flash.py +141 -62
  12. stream_dse-2.4.0/stream/compiler/kernels/gemm.py +360 -0
  13. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/kernels/library.py +8 -1
  14. stream_dse-2.4.0/stream/compiler/kernels/mlir_aie.py +123 -0
  15. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/kernels/registry.py +8 -2
  16. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_convert_ofs.py +250 -109
  17. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/convert_stream_to_aie.py +36 -6
  18. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/cost_model/bandwidth.py +37 -7
  19. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/cost_model/communication_manager.py +191 -89
  20. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/cost_model/core_cost_lut.py +1 -1
  21. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/cost_model/layout.py +31 -16
  22. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/cost_model/roofline.py +20 -4
  23. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/architecture/backends/__init__.py +2 -2
  24. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/architecture/backends/aie2.py +4 -0
  25. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/architecture/backends/zigzag.py +48 -1
  26. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/architecture/core.py +11 -1
  27. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/cost.py +130 -1
  28. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/whole_array_strix.yaml +13 -8
  29. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/ir/allocation.py +39 -17
  30. stream_dse-2.4.0/stream/mapping/blocks.py +163 -0
  31. stream_dse-2.4.0/stream/mapping/capacity_tiler.py +1370 -0
  32. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/mapping/generic_generator.py +80 -16
  33. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/mapping/work_share.py +60 -1
  34. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/allocation_model.py +22 -11
  35. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/__init__.py +11 -2
  36. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/aie2.py +30 -2
  37. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/dma.py +8 -0
  38. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/energy.py +16 -2
  39. stream_dse-2.4.0/stream/opt/allocation/constraint_optimization/families/latency.py +247 -0
  40. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/memory.py +62 -24
  41. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/memory_ports.py +83 -25
  42. stream_dse-2.4.0/stream/opt/allocation/constraint_optimization/families/offchip.py +111 -0
  43. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/overlap.py +281 -42
  44. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/reuse.py +116 -18
  45. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/routing.py +18 -9
  46. stream_dse-2.4.0/stream/opt/allocation/constraint_optimization/families/traffic.py +302 -0
  47. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/hardware.py +60 -16
  48. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/layouts.py +67 -4
  49. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/report.py +44 -22
  50. stream_dse-2.4.0/stream/opt/allocation/constraint_optimization/space.py +1088 -0
  51. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/utils.py +5 -0
  52. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/solver/solver.py +30 -17
  53. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/accelerator_validator.py +19 -7
  54. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/mapping_factory.py +4 -2
  55. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/mapping_validator.py +1 -0
  56. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/codegen/aie_code_generation.py +46 -27
  57. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/aie_cost_estimator.py +17 -5
  58. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/core_cost_backends.py +1 -0
  59. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/core_cost_estimation.py +2 -2
  60. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/memory_accesses_estimation.py +47 -22
  61. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/zigzag_cost_estimator.py +94 -16
  62. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/fixed_mapping_generation.py +48 -0
  63. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/fusion_group_iteration.py +9 -11
  64. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/kernel_state.py +2 -1
  65. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/placement_generation.py +91 -0
  66. stream_dse-2.4.0/stream/stages/generation/tile_search.py +271 -0
  67. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/tiling_generation.py +5 -2
  68. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/visualization/steady_state_trace.py +12 -4
  69. stream_dse-2.4.0/stream/workload/demand.py +123 -0
  70. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/node_key.py +2 -0
  71. stream_dse-2.4.0/stream/workload/post_ops.py +72 -0
  72. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/utils.py +187 -53
  73. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/workload.py +948 -200
  74. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream_dse.egg-info/PKG-INFO +1 -1
  75. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream_dse.egg-info/SOURCES.txt +13 -2
  76. stream_dse-2.4.0/tests/test_absent_latency.py +152 -0
  77. stream_dse-2.4.0/tests/test_boundary_coupling.py +318 -0
  78. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_conv_windows.py +26 -16
  79. stream_dse-2.4.0/tests/test_copy_sets.py +512 -0
  80. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_data_layout.py +2 -2
  81. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_decode_kv.py +115 -24
  82. stream_dse-2.4.0/tests/test_epilogue_latency.py +68 -0
  83. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_hardware_combinations.py +34 -22
  84. stream_dse-2.4.0/tests/test_mapping_validation.py +160 -0
  85. stream_dse-2.4.0/tests/test_precision.py +470 -0
  86. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_roofline.py +37 -1
  87. stream_dse-2.4.0/tests/test_sliding_halos.py +127 -0
  88. stream_dse-2.4.0/tests/test_split_sliding_step.py +103 -0
  89. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_steady_state_detail.py +12 -12
  90. stream_dse-2.4.0/tests/test_steady_state_ir.py +132 -0
  91. stream_dse-2.4.0/tests/test_strided_gather.py +254 -0
  92. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_tpu_v7.py +166 -12
  93. stream_dse-2.4.0/tests/test_transfer_demand.py +107 -0
  94. stream_dse-2.3.0/stream/__init__.py +0 -1
  95. stream_dse-2.3.0/stream/compiler/fifo_depths.py +0 -84
  96. stream_dse-2.3.0/stream/compiler/kernels/gemm.py +0 -57
  97. stream_dse-2.3.0/stream/compiler/kernels/mlir_aie.py +0 -105
  98. stream_dse-2.3.0/stream/mapping/blocks.py +0 -58
  99. stream_dse-2.3.0/stream/mapping/capacity_tiler.py +0 -625
  100. stream_dse-2.3.0/stream/opt/allocation/constraint_optimization/families/latency.py +0 -78
  101. stream_dse-2.3.0/stream/opt/allocation/constraint_optimization/families/offchip.py +0 -50
  102. stream_dse-2.3.0/stream/opt/allocation/constraint_optimization/families/traffic.py +0 -156
  103. stream_dse-2.3.0/stream/opt/allocation/constraint_optimization/space.py +0 -627
  104. stream_dse-2.3.0/stream/stages/generation/tile_search.py +0 -156
  105. stream_dse-2.3.0/tests/test_precision.py +0 -198
  106. {stream_dse-2.3.0 → stream_dse-2.4.0}/LICENSE +0 -0
  107. {stream_dse-2.3.0 → stream_dse-2.4.0}/README.md +0 -0
  108. {stream_dse-2.3.0 → stream_dse-2.4.0}/setup.cfg +0 -0
  109. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/allocation/__init__.py +0 -0
  110. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/allocation/artifacts.py +0 -0
  111. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/allocation/problem.py +0 -0
  112. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/context/aie_context.py +0 -0
  113. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/dialects/__init__.py +0 -0
  114. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/dialects/stream.py +0 -0
  115. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/kernels/__init__.py +0 -0
  116. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/kernels/binding.py +0 -0
  117. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/kernels/eltwise_mul.py +0 -0
  118. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/kernels/silu.py +0 -0
  119. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/kernels/softmax.py +0 -0
  120. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/__init__.py +0 -0
  121. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_add_tracing_script.py +0 -0
  122. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_dispatch.py +0 -0
  123. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_move_tile_ops_up.py +0 -0
  124. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_tiles.py +0 -0
  125. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/clear_memory_space.py +0 -0
  126. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/convert_aie_kernels.py +0 -0
  127. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/hoist_scale_acquires.py +0 -0
  128. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/iteration_space_to_for.py +0 -0
  129. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/compiler/transforms/unroll.py +0 -0
  130. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/cost_model/core_cost.py +0 -0
  131. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/cost_model/memory_accesses.py +0 -0
  132. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/datatypes.py +0 -0
  133. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/frontends/__init__.py +0 -0
  134. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/frontends/onnx.py +0 -0
  135. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/frontends/torch_export.py +0 -0
  136. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/architecture/accelerator.py +0 -0
  137. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/architecture/memory.py +0 -0
  138. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/architecture/noc/communication_link.py +0 -0
  139. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/bundle.py +0 -0
  140. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/hardware/ports.py +0 -0
  141. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/cores/aie_tile.yaml +0 -0
  142. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/cores/mem_tile_256KB.yaml +0 -0
  143. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/cores/mem_tile_512KB.yaml +0 -0
  144. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/single_col.yaml +0 -0
  145. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/single_core.yaml +0 -0
  146. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/whole_array.yaml +0 -0
  147. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/kernels/aie2p.toml +0 -0
  148. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/mapping/make_gemm_mapping.py +0 -0
  149. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/mapping/make_swiglu_mapping.py +0 -0
  150. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/workload/make_onnx_gemm.py +0 -0
  151. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/aie/workload/make_onnx_swiglu.py +0 -0
  152. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/eyeriss_like.yaml +0 -0
  153. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/fusemax_array.yaml +0 -0
  154. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/fusemax_vec.yaml +0 -0
  155. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/meta_prototype.yaml +0 -0
  156. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/pooling.yaml +0 -0
  157. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/simba_chiplet.yaml +0 -0
  158. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/simd.yaml +0 -0
  159. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/tpu_like.yaml +0 -0
  160. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/tpu_v7_mxu.yaml +0 -0
  161. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/tpu_v7_vmem.yaml +0 -0
  162. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/tpu_v7_vpu.yaml +0 -0
  163. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/eyeriss_like_dual_core.yaml +0 -0
  164. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/eyeriss_like_quad_core.yaml +0 -0
  165. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/eyeriss_like_single_core.yaml +0 -0
  166. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/fusemax.yaml +0 -0
  167. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/meta_prototype_dual_core_simd_offchip.yaml +0 -0
  168. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/simba.yaml +0 -0
  169. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/simba_small.yaml +0 -0
  170. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/tpu_like_quad_core.yaml +0 -0
  171. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/tpu_v7_ironwood.yaml +0 -0
  172. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/pooling.yaml +0 -0
  173. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/shared_testing_core1.yaml +0 -0
  174. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/shared_testing_core2.yaml +0 -0
  175. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/simd.yaml +0 -0
  176. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/testing_core1.yaml +0 -0
  177. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/testing_core2.yaml +0 -0
  178. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/tpu_like.yaml +0 -0
  179. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/tpu_like_quad_core.yaml +0 -0
  180. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/tpu_like_ring_hbm.yaml +0 -0
  181. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/tpu_v7_ironwood_hbm_per_chiplet.yaml +0 -0
  182. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/mapping/make_2_conv_mapping.py +0 -0
  183. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_2_conv.py +0 -0
  184. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_attention_head.py +0 -0
  185. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_conv_relu_flatten_gemm.py +0 -0
  186. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_decode_attention.py +0 -0
  187. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_resnet_subgraph.py +0 -0
  188. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_scan.py +0 -0
  189. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_swiglu.py +0 -0
  190. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/instrumentation.py +0 -0
  191. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/ir/__init__.py +0 -0
  192. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/ir/accelerator.py +0 -0
  193. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/ir/graph_view.py +0 -0
  194. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/ir/infeasibility.py +0 -0
  195. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/ir/roofline.py +0 -0
  196. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/ir/workload.py +0 -0
  197. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/mapping/chain_placement.py +0 -0
  198. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/mapping/mapping.py +0 -0
  199. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/mcp/__init__.py +0 -0
  200. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/mcp/jobs.py +0 -0
  201. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/mcp/server.py +0 -0
  202. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/__init__.py +0 -0
  203. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/__init__.py +0 -0
  204. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/__init__.py +0 -0
  205. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/diagnosis.py +0 -0
  206. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/formulation.py +0 -0
  207. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/quantities.py +0 -0
  208. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/opt/solver/__init__.py +0 -0
  209. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/accelerator_factory.py +0 -0
  210. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/core_validator.py +0 -0
  211. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/mapping_parser.py +0 -0
  212. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/batch_norm.py +0 -0
  213. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/conv.py +0 -0
  214. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/einsum.py +0 -0
  215. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/elementwise.py +0 -0
  216. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/gemm.py +0 -0
  217. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/global_average_pool.py +0 -0
  218. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/layout.py +0 -0
  219. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/matmul.py +0 -0
  220. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/max_pool.py +0 -0
  221. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/model.py +0 -0
  222. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/normalization.py +0 -0
  223. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/operator_parser.py +0 -0
  224. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/reduce.py +0 -0
  225. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/slice_gather.py +0 -0
  226. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/parser/onnx/utils.py +0 -0
  227. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/plugins.py +0 -0
  228. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/profiling.py +0 -0
  229. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/__init__.py +0 -0
  230. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/allocation/steady_state_allocation.py +0 -0
  231. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/allocation/steady_state_lowering.py +0 -0
  232. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/codegen/backends.py +0 -0
  233. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/context.py +0 -0
  234. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/accelforge/__init__.py +0 -0
  235. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/accelforge/arch.py +0 -0
  236. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/accelforge/backend.py +0 -0
  237. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/accelforge/library.py +0 -0
  238. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/accelforge/mapper.py +0 -0
  239. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/accelforge/tree.py +0 -0
  240. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/estimation/accelforge/workload.py +0 -0
  241. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/flash_decoding.py +0 -0
  242. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/fusion_analysis.py +0 -0
  243. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/fusion_proposal.py +0 -0
  244. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/generic_mapping_generation.py +0 -0
  245. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/mapping_generators.py +0 -0
  246. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/normalization_expansion.py +0 -0
  247. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/generation/structural_dedup.py +0 -0
  248. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/parsing/accelerator_parser.py +0 -0
  249. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/parsing/onnx_model_parser.py +0 -0
  250. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/stages/stage.py +0 -0
  251. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/visualization/hardware_graph.py +0 -0
  252. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/_svg.py +0 -0
  253. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/access_relation.py +0 -0
  254. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/affine_access.py +0 -0
  255. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/affine_exact.py +0 -0
  256. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/affine_transform.py +0 -0
  257. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/blocks/__init__.py +0 -0
  258. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/blocks/library.py +0 -0
  259. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/data_movement.py +0 -0
  260. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/decompose.py +0 -0
  261. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/fusion/__init__.py +0 -0
  262. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/fusion/analysis.py +0 -0
  263. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/fusion/proposer.py +0 -0
  264. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/iterator_type.py +0 -0
  265. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/models.py +0 -0
  266. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/node.py +0 -0
  267. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/normalization.py +0 -0
  268. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/rewrites/__init__.py +0 -0
  269. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/rewrites/base.py +0 -0
  270. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/rewrites/flash_attention.py +0 -0
  271. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/rewrites/flash_decoding.py +0 -0
  272. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/rewrites/reference.py +0 -0
  273. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/steady_state/computation.py +0 -0
  274. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/steady_state/iteration_space.py +0 -0
  275. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/steady_state/node.py +0 -0
  276. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/structure/__init__.py +0 -0
  277. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/structure/block_detect.py +0 -0
  278. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/structure/wl.py +0 -0
  279. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream/workload/tensor.py +0 -0
  280. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream_dse.egg-info/dependency_links.txt +0 -0
  281. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream_dse.egg-info/entry_points.txt +0 -0
  282. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream_dse.egg-info/requires.txt +0 -0
  283. {stream_dse-2.3.0 → stream_dse-2.4.0}/stream_dse.egg-info/top_level.txt +0 -0
  284. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_accelerator_ir.py +0 -0
  285. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_ci_workflow.py +0 -0
  286. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_co.py +0 -0
  287. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_core_cost_lut_caching.py +0 -0
  288. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_core_validation.py +0 -0
  289. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_decode_attention.py +0 -0
  290. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_edge_placements.py +0 -0
  291. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_generic_mapping.py +0 -0
  292. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_hardware_bundle.py +0 -0
  293. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_layout_einsum_reduce.py +0 -0
  294. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_metrics_capture.py +0 -0
  295. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_on_chip_placement.py +0 -0
  296. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_render_metrics_comment.py +0 -0
  297. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_resnet_mapping.py +0 -0
  298. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_resnet_patterns.py +0 -0
  299. {stream_dse-2.3.0 → stream_dse-2.4.0}/tests/test_systolic.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stream-dse
3
- Version: 2.3.0
3
+ Version: 2.4.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
@@ -21,7 +21,7 @@ namespaces = true
21
21
 
22
22
  [project]
23
23
  name = "stream-dse"
24
- version = "2.3.0"
24
+ version = "2.4.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" }]
@@ -148,7 +148,7 @@ generic = "stream.stages.generation.mapping_generators:GENERIC_MAPPING"
148
148
  Homepage = "https://github.com/KULeuven-MICAS/stream"
149
149
 
150
150
  [tool.bumpver]
151
- current_version = "2.3.0"
151
+ current_version = "2.4.0"
152
152
  version_pattern = "MAJOR.MINOR.PATCH"
153
153
  commit_message = "bump version {old_version} -> {new_version}"
154
154
  commit = true
@@ -0,0 +1 @@
1
+ __version__ = "2.4.0"
@@ -31,11 +31,11 @@ from pathlib import Path
31
31
  _XDSL_AIE = "git+https://github.com/xdslproject/xdsl-aie.git@f2540442628aa782847ababd1dc76c0e323ba459"
32
32
  _SNAX_MLIR = "git+https://github.com/kuleuven-micas/snax-mlir.git@1c01c5d100df128c9fa01d3336ebea98e19b20cf"
33
33
 
34
- _MLIR_AIE_PIN = "mlir_aie==1.4.4"
35
- _LLVM_AIE_PIN = "llvm-aie==22.0.0.2026092101+0006955e"
34
+ _MLIR_AIE_PIN = "mlir_aie==1.4.6.dev15+ge5a3fa1"
35
+ _LLVM_AIE_PIN = "llvm-aie==22.0.0.2026102001+4f5df13d"
36
36
  _AIE_WHEEL_INDICES = [
37
37
  "--extra-index-url",
38
- "https://github.com/Xilinx/mlir-aie/releases/expanded_assets/v1.4.4",
38
+ "https://github.com/Xilinx/mlir-aie/releases/expanded_assets/latest-wheels-4",
39
39
  "--extra-index-url",
40
40
  "https://github.com/Xilinx/llvm-aie/releases/expanded_assets/nightly",
41
41
  "--extra-index-url",
@@ -13,7 +13,6 @@ from stream.opt.allocation.constraint_optimization.report import guarded
13
13
  from stream.workload.node import InEdge, OutEdge, Tensor, declared_of, edge_tensor
14
14
  from stream.workload.steady_state.iteration_space import (
15
15
  IterationVariableType,
16
- LoopEffect,
17
16
  Reuse,
18
17
  SteadyStateIterationSpace,
19
18
  )
@@ -164,6 +163,22 @@ class Allocation:
164
163
  add(str(layer_dim), size, "core_temporal")
165
164
  return loops
166
165
 
166
+ def _group_loops(self) -> list[dict]:
167
+ """The group's shared loops, outermost first; a dim split over cores is one loop at the largest split."""
168
+ loops: list[dict] = []
169
+ splits: dict[str, int] = {}
170
+ for cn in self.problem.workload.get_computation_nodes():
171
+ parts: dict[str, int] = {}
172
+ for iv in reversed(self.ssis[cn].variables) if cn in self.ssis else ():
173
+ loop = {"dim": str(iv.dimension), "size": iv.size, "type": iv.type.name.lower()}
174
+ if iv.type in (IterationVariableType.SPATIAL, IterationVariableType.SPATIOTEMPORAL):
175
+ parts[loop["dim"]] = parts.get(loop["dim"], 1) * iv.size
176
+ elif iv.size > 1 and loop not in loops:
177
+ loops.append(loop)
178
+ for dim, n in parts.items():
179
+ splits[dim] = max(splits.get(dim, 1), n)
180
+ return loops + [{"dim": dim, "size": n, "type": "spatial"} for dim, n in splits.items() if n > 1]
181
+
167
182
  def _steady_state_ir(self) -> dict:
168
183
  """Serialise the tiled/steady-state inspection view: operators, loop nest and transfer graph, and with the
169
184
  decision space the per-core detail of every tiled node, axis and tensor."""
@@ -175,16 +190,7 @@ class Allocation:
175
190
  }
176
191
  for cn in self.problem.source_workload.get_computation_nodes()
177
192
  ]
178
- loops: list[dict] = []
179
- seen: set = set()
180
- for ssis in self.ssis.values():
181
- for iv in ssis.variables:
182
- if iv.effect is LoopEffect.ABSENT:
183
- continue
184
- key = (str(iv.dimension), int(iv.size))
185
- if int(iv.size) > 1 and key not in seen:
186
- seen.add(key)
187
- loops.append({"dim": str(iv.dimension), "size": int(iv.size), "type": iv.type.name.lower()})
193
+ loops = self._group_loops()
188
194
  expanded = False
189
195
  for cn in self.problem.source_workload.get_computation_nodes():
190
196
  core_loops = self._core_loops(cn)
@@ -135,6 +135,8 @@ class _Lowering:
135
135
  with span("iteration_spaces"):
136
136
  self.ssis = self.generate_ssis()
137
137
  self.iterations = self.calculate_iterations()
138
+ with span("routes"):
139
+ self.route_transfers()
138
140
  with span("timeslots"):
139
141
  timeslots = self.ssw.get_timeslots(self.mapping)
140
142
  return AllocationProblem(
@@ -325,7 +327,7 @@ class _Lowering:
325
327
  for node in self.ssw.get_computation_nodes():
326
328
  unique_dims_tiling = (self.ssw.get_unique_dims_inter_core_tiling(node, self.mapping),)
327
329
  self.mapping.update_inter_core_tiling(node, unique_dims_tiling)
328
- # Add transfer node mappings
330
+ # Add transfer node mappings; their routes follow once the iteration spaces give each copy's halos.
329
331
  for node in self.ssw.get_transfer_nodes():
330
332
  assert len(node.inputs) == 1, "Transfer node must have exactly one input tensor."
331
333
  src = cast(HasOutputs, list(self.ssw.predecessors(node))[0])
@@ -333,6 +335,19 @@ class _Lowering:
333
335
  self.update_mapping_for_transfer(node, src, dsts)
334
336
  return self.mapping.with_updated_workload(self.ssw, self.workload) # updates FusedGroups
335
337
 
338
+ def route_transfers(self) -> None:
339
+ """Give each transfer the routes of each of its placements, moving what each copy reads per firing."""
340
+ for node in self.ssw.get_transfer_nodes():
341
+ src = cast(HasOutputs, next(iter(self.ssw.predecessors(node))))
342
+ node_mapping = self.mapping.get(node)
343
+ dst_allocs, tilings = node_mapping.memory_allocation, node_mapping.inter_core_tiling
344
+ self.mapping.set_for_node(
345
+ node,
346
+ resource_allocation=self.determine_possible_transfer_plans(node, src, dst_allocs, tilings),
347
+ inter_core_tiling=tilings,
348
+ memory_allocation=dst_allocs,
349
+ )
350
+
336
351
  def _fresh(self, name: str) -> str:
337
352
  """``name``, suffixed until no tensor of the workload has it, so a copy cannot be taken for another tensor."""
338
353
  taken = {t.name for t in self.workload.tensors}
@@ -414,11 +429,13 @@ class _Lowering:
414
429
 
415
430
  def add_halos(self, tensor: Tensor, transfer: TransferNode, ssis: SteadyStateIterationSpace) -> None:
416
431
  """Give each loop that slides the window of a transfer's copy the halo its consecutive tiles share."""
417
- sliding = (IterationVariableType.TEMPORAL, IterationVariableType.SPATIAL)
418
- loops = [v for v in ssis if v.relevant and v.type in sliding]
419
- windows = self.ssw.get_windows(tensor, transfer, self.mapping, [v.dimension for v in loops])
420
- for loop in loops:
421
- loop.halo = windows[loop.dimension][1] if loop.dimension in windows else 0
432
+ for kind in (IterationVariableType.TEMPORAL, IterationVariableType.SPATIAL):
433
+ loops = [v for v in ssis if v.relevant and v.type is kind]
434
+ dims = [v.dimension for v in loops]
435
+ temporal = kind is IterationVariableType.TEMPORAL
436
+ windows = self.ssw.get_windows(tensor, transfer, self.mapping, dims, temporal=temporal)
437
+ for loop in loops:
438
+ loop.halo = windows[loop.dimension][1] if loop.dimension in windows else 0
422
439
 
423
440
  def update_mapping_for_transfer(self, node: TransferNode, src: HasOutputs, dsts: tuple[HasInputs, ...]) -> None:
424
441
  possible_dst_allocs = self.determine_possible_memory_allocations(node, src, dsts)
@@ -429,15 +446,6 @@ class _Lowering:
429
446
  inter_core_tiling=possible_inter_core_tiling,
430
447
  memory_allocation=possible_dst_allocs,
431
448
  )
432
- possible_allocations = self.determine_possible_transfer_plans(
433
- node, src, possible_dst_allocs, possible_inter_core_tiling
434
- )
435
- self.mapping.set_for_node(
436
- node,
437
- resource_allocation=possible_allocations,
438
- inter_core_tiling=possible_inter_core_tiling,
439
- memory_allocation=possible_dst_allocs,
440
- )
441
449
 
442
450
  def determine_possible_memory_allocations(
443
451
  self, node: TransferNode, src: HasOutputs, dsts: tuple[HasInputs, ...]
@@ -561,31 +569,48 @@ class _Lowering:
561
569
  possible_tilings: tuple[InterCoreTiling, ...],
562
570
  ) -> tuple[MulticastPathPlan, ...]:
563
571
  """The route of each placement of ``node``, moving what each target reads from the sources that hold it, of
564
- each placement the allocation may choose for the input it moves (:func:`placement_options`)."""
565
- all_possible_resource_plans = []
572
+ each placement the allocation may choose for the input it moves (:func:`placement_options`), with and without
573
+ a local copy from a larger copy in a target's memory."""
574
+ all_possible_resource_plans: dict[MulticastPathPlan, None] = {}
566
575
  bitwidth = node.inputs[0].operand_type.bitwidth
567
576
  for placement, src_allocs in self._held_options(src):
568
577
  mapping = self.mapping if placement is None else self.mapping.with_edge_placements({src.name: placement})
569
578
  for dst_allocs, tiling in zip(possible_dst_allocs, possible_tilings, strict=True):
570
- demand = self.ssw.get_transfer_demand(
571
- node,
572
- mapping,
573
- tiling,
574
- len(src_allocs),
575
- len(dst_allocs),
576
- self.hardware.pairs_by_spatial_index((*src_allocs, *dst_allocs)),
577
- dst_allocs,
578
- self._reads_in,
579
- partial(self._iteration_cost, src_allocs, dst_allocs, bitwidth),
580
- )
581
- possible_resource_plans = self.accelerator.communication_manager.get_possible_transfer_plan(
582
- src_allocs, dst_allocs, demand, bitwidth, self.hardware.shares_memory, self.route_alternatives
583
- )
584
- if placement is not None:
585
- possible_resource_plans = [replace(plan, placement=placement) for plan in possible_resource_plans]
586
- all_possible_resource_plans.extend(possible_resource_plans)
579
+ by_spatial_index = self.hardware.pairs_by_spatial_index((*src_allocs, *dst_allocs))
580
+ demands = {
581
+ self.ssw.get_transfer_demand(
582
+ node,
583
+ mapping,
584
+ tiling,
585
+ len(src_allocs),
586
+ len(dst_allocs),
587
+ by_spatial_index,
588
+ dst_allocs,
589
+ self._reads_in,
590
+ partial(self._iteration_cost, src_allocs, dst_allocs, bitwidth),
591
+ ssis=self.ssis.get,
592
+ fusion_splits=self.fusion_splits,
593
+ allow_local_copy=allow_local_copy,
594
+ shares_memory=partial(self._shares_memory, src_allocs, dst_allocs),
595
+ ): None
596
+ # Code generation pairing by spatial index moves every copy by its own transfer.
597
+ for allow_local_copy in ((False,) if by_spatial_index else (False, True))
598
+ }
599
+ for demand in demands:
600
+ possible_resource_plans = self.accelerator.communication_manager.get_possible_transfer_plan(
601
+ src_allocs, dst_allocs, demand, bitwidth, self.hardware.shares_memory, self.route_alternatives
602
+ )
603
+ if placement is not None:
604
+ possible_resource_plans = [
605
+ replace(plan, placement=placement) for plan in possible_resource_plans
606
+ ]
607
+ all_possible_resource_plans.update(dict.fromkeys(possible_resource_plans))
587
608
  return tuple(all_possible_resource_plans)
588
609
 
610
+ def _shares_memory(self, sources: Sequence[Memory], targets: Sequence[Memory], source: int, target: int) -> bool:
611
+ """Whether the source at position ``source`` and the target at position ``target`` share a memory."""
612
+ return self.hardware.shares_memory(sources[source], targets[target])
613
+
589
614
  def calculate_iterations(self) -> int:
590
615
  """Calculate the amount of steady state iterations based on all nodes' SSIS."""
591
616
  iterations_per_node = {node: prod(ssis.get_temporal_sizes()) for node, ssis in self.ssis.items()}
@@ -659,7 +684,7 @@ class _Lowering:
659
684
  times the links they cross from the nearest source holding them."""
660
685
  held: dict[tuple[Memory, str], list[Box]] = defaultdict(list)
661
686
  carried = 0.0
662
- for item in items:
687
+ for item in (item for item in items if item.sources):
663
688
  target = targets[item.target]
664
689
  source = min((sources[s] for s in item.sources), key=lambda memory: self.accelerator.hops(memory, target))
665
690
  for memory, direction in ((source, READ), (target, WRITE)):
@@ -34,8 +34,8 @@ class AllocationSolution:
34
34
  depths: Mapping[Tensor, int]
35
35
  single_buffered: frozenset[Tensor]
36
36
  latency: Latency
37
- slot_latencies: Mapping[int, float]
38
- reuse_factors: Mapping[TransferNode, float]
37
+ slot_latencies: Mapping[int, int]
38
+ reuse_factors: Mapping[TransferNode, int]
39
39
  route_cycles: Mapping[TransferNode, int]
40
40
  primary_cost: float
41
41
  solve_stats: SolveStats
@@ -7,12 +7,16 @@ from math import prod
7
7
  from typing import TYPE_CHECKING, Any
8
8
 
9
9
  from stream.opt.allocation.constraint_optimization.families.traffic import link_name
10
- from stream.opt.allocation.constraint_optimization.report import guarded
10
+ from stream.opt.allocation.constraint_optimization.report import guarded, reported_reuse
11
+ from stream.opt.allocation.constraint_optimization.utils import absent_trips
12
+ from stream.workload.demand import Box, DemandItem, covered, firing_count
11
13
  from stream.workload.node import ComputationNode, Tensor, TransferNode
12
14
 
13
15
  if TYPE_CHECKING:
14
16
  from stream.allocation.allocation import Allocation
17
+ from stream.cost_model.communication_manager import MulticastPathPlan
15
18
  from stream.datatypes import LayerDim
19
+ from stream.hardware.architecture.memory import Memory
16
20
  from stream.opt.allocation.constraint_optimization.space import DecisionSpace
17
21
  from stream.workload.node import HasIterationSpace
18
22
  from stream.workload.steady_state.iteration_space import SteadyStateIterationSpace
@@ -35,7 +39,7 @@ def steady_state_detail(allocation: Allocation, space: DecisionSpace) -> dict[st
35
39
  return {
36
40
  "iterations": allocation.problem.iterations,
37
41
  "axes": _axes(allocation, sliding),
38
- "tensors": _tensors(allocation),
42
+ "tensors": _tensors(allocation, space),
39
43
  "nodes": {name: found for name, found in nodes.items() if found is not None},
40
44
  }
41
45
 
@@ -53,13 +57,16 @@ def _axes(allocation: Allocation, sliding: set[LayerDim]) -> list[dict[str, Any]
53
57
  ]
54
58
 
55
59
 
56
- def _tensors(allocation: Allocation) -> list[dict[str, Any]]:
57
- solution = allocation.solution
60
+ def _tensors(allocation: Allocation, space: DecisionSpace) -> list[dict[str, Any]]:
61
+ """Each tensor as the solution placed and buffered it, a transfer's copy at the window its reader holds."""
62
+ solution, workload, mapping = allocation.solution, allocation.problem.workload, allocation.problem.mapping
63
+ writers = {copy: tn for tn in workload.get_transfer_nodes() for copy in tn.outputs}
64
+ held = {t: workload.get_tensor_single_core(t, tn, mapping) for t, tn in writers.items() if t in allocation.ssis}
58
65
  return [
59
66
  {
60
67
  "name": t.name,
61
- "shape": _shape(t),
62
- "bits": int(t.size_bits()),
68
+ "shape": _shape(held.get(t, t)),
69
+ "bits": space.held_bits(t, held.get(t, t)),
63
70
  "loops": _loops(ssis),
64
71
  "placement": [memory.name for memory in solution.tensor_placements.get(t, ())],
65
72
  "reuse_level": solution.reuse_levels.get(t),
@@ -90,6 +97,11 @@ def _shape(tensor: Tensor) -> list[int]:
90
97
  return [int(s) for s in tensor.shape]
91
98
 
92
99
 
100
+ def _per_firing(points: int, spanned: int) -> int | float:
101
+ """Points over the firings a demand spans, an integer where they divide."""
102
+ return points // spanned if points % spanned == 0 else points / spanned
103
+
104
+
93
105
  class _NodeDetail:
94
106
  """What one tiled node does on its cores, read off the solution and the decision space it was solved in."""
95
107
 
@@ -104,11 +116,12 @@ class _NodeDetail:
104
116
  }
105
117
 
106
118
  def compute(self, cn: ComputationNode) -> dict[str, Any]:
107
- """Its cores, the output tile at each core position and whether a reader waits on it."""
119
+ """Its cores, how often it runs, the output tile at each core position and whether a reader waits on it."""
108
120
  tile = self.workload.get_tensor_single_core
109
121
  return {
110
122
  "dims": [str(dim) for dim in self.workload.get_dims(cn)],
111
123
  "loops": _loops(self.allocation.ssis.get(cn)),
124
+ "calls": self.allocation.problem.iterations // absent_trips(self.space.ssis[cn]),
112
125
  "cores": [core.id for core in self.space.cores(cn)],
113
126
  "tiles": [_shape(tile(cn.outputs[0], cn, self.mapping, p)) for p in range(self._positions(cn))],
114
127
  "waited_on": self.space.is_waited_on(cn),
@@ -116,9 +129,9 @@ class _NodeDetail:
116
129
  }
117
130
 
118
131
  def transfer(self, tn: TransferNode) -> dict[str, Any]:
119
- """Its route, the window of each copy a target holds and what one firing moves to it, the halos its loops
120
- keep, what each source hands each target, and the bits it moves. A target holds the copies of the nodes it
121
- runs, each at its position among that copy's targets modulo the positions, as sources pair with targets."""
132
+ """Its loops, route, copies and the copy each target holds (the copy of a node the target runs), the window
133
+ and moved tile of that copy, each copy's halos, the demand each source serves at each target, the bits it moves
134
+ and the iterations one firing serves."""
122
135
  space, solution = self.space, self.allocation.solution
123
136
  route = solution.transfer_routes[tn]
124
137
  # Pair each copy with the targets it may land in; a target no copy may land in gets the first copy.
@@ -133,26 +146,93 @@ class _NodeDetail:
133
146
  for copy, p in at
134
147
  ]
135
148
  return {
149
+ "loops": _loops(self.allocation.ssis.get(tn)),
136
150
  "sources": [m.name for m in route.sources],
137
151
  "targets": [m.name for _, m in held],
152
+ "copy_names": [copy.name for copy in tn.outputs],
153
+ "target_copies": [tn.outputs.index(copy) for copy, _ in held],
138
154
  "links": [link_name(link) for link in route.links_used],
139
155
  "windows": [_shape(self.workload.get_tensor_single_core(copy, tn, self.mapping, p)) for copy, p in at],
140
156
  "moved": [_shape(tile) for tile in moved],
141
157
  "halos": [
142
- {"dim": str(loop.dimension), "type": loop.type.name.lower(), "halo": loop.halo}
143
- for loop in space.ssis.get(tn.outputs[0]) or ()
158
+ {"dim": str(loop.dimension), "type": loop.type.name.lower(), "halo": loop.halo, "copy": i}
159
+ for i, copy in enumerate(tn.outputs)
160
+ for loop in reversed(space.ssis[copy].variables)
144
161
  if loop.halo
145
162
  ],
146
- "handed": [
147
- {"source": route.sources[i].name, "target": route.targets[j].name, "elements": elements}
148
- for (i, j), elements in space.overlaps(tn).items()
149
- ],
150
- "moved_bits": 0 if space.choice_shares_memory(tn, route) else space.moved_bits(tn, route),
163
+ "demand": self._demand_by_kind(tn, route),
164
+ **self._copy_bits(tn),
165
+ "link_bits": self._link_bits(tn, route),
151
166
  "route_cycles": solution.route_cycles[tn],
152
- "reuse_factor": solution.reuse_factors.get(tn),
153
167
  **self._sliding(tn),
154
168
  }
155
169
 
170
+ def _copy_bits(self, tn: TransferNode) -> dict[str, Any]:
171
+ """Per copy, the bits one of its firings moves and its reuse factor, a box several copies read charged to the
172
+ one firing most often; the transfer's own are its most often firing copy's reuse and bits per such firing."""
173
+ space, solution = self.space, self.allocation.solution
174
+ route = solution.transfer_routes[tn]
175
+ reuse = [
176
+ reported_reuse(space.reuse_levels[(copy, solution.reuse_levels[copy])], space.ssis[tn])
177
+ if copy in solution.reuse_levels
178
+ else reported_reuse(solution.reuse_factors[tn], space.ssis[tn])
179
+ for copy in tn.outputs
180
+ ]
181
+ moved = [0.0] * len(tn.outputs)
182
+ if not space.choice_shares_memory(tn, route):
183
+ for copies in space.copy_sets(tn, route):
184
+ first = min(copies, key=lambda c: reuse[c])
185
+ moved[first] += space.sent_bits(tn, route, copies)
186
+ top = min((r for r, bits in zip(reuse, moved, strict=True) if bits), default=reuse[0])
187
+ return {
188
+ "moved_bits": sum(bits * top / r for bits, r in zip(moved, reuse, strict=True)),
189
+ "reuse_factor": top,
190
+ "copy_moved_bits": moved,
191
+ "copy_reuse_factors": reuse,
192
+ }
193
+
194
+ def _demand_by_kind(self, tn: TransferNode, route: MulticastPathPlan) -> list[dict[str, Any]]:
195
+ """Per source, target and kind, the elements of the target's demand the source serves per firing: over links
196
+ ('moved'), from a source in or sharing the target's memory ('in_place'), from a larger copy in that memory
197
+ ('local_copy'), or as a source's partial sum of a split reduction ('partial_sum')."""
198
+ served: dict[tuple[Memory, Memory, str], list[Box]] = {}
199
+ kind = "in_place" if self.space.choice_shares_memory(tn, route) else "moved"
200
+ sent = [item for item in route.delivered_items if not item.reduce]
201
+ delivered = {(item.target, item.box, item.copies) for item in sent}
202
+ for item in sent:
203
+ served.setdefault((route.sources[item.sources[0]], route.targets[item.target], kind), []).append(item.box)
204
+ for item in route.demand:
205
+ for key in self._served_without_links(route, item, delivered):
206
+ served.setdefault(key, []).append(item.box)
207
+ spanned = firing_count(route.demand)
208
+ return [
209
+ {"source": one.name, "target": other.name, "kind": kind, "elements": _per_firing(covered(boxes), spanned)}
210
+ for (one, other, kind), boxes in served.items()
211
+ ]
212
+
213
+ def _served_without_links(
214
+ self, route: MulticastPathPlan, item: DemandItem, delivered: set[tuple[int, Box, tuple[int, ...]]]
215
+ ) -> list[tuple[Memory, Memory, str]]:
216
+ """The source that serves a demand item no link carries, and the kind."""
217
+ target = route.targets[item.target]
218
+ if item.reduce:
219
+ return [(route.sources[s], target, "partial_sum") for s in item.sources]
220
+ if not item.sources:
221
+ return [(target, target, "local_copy")]
222
+ if (item.target, item.box, item.copies) in delivered:
223
+ return []
224
+ held = [s for s in item.sources if route.sources[s] is target] or [
225
+ s for s in item.sources if self.space.hardware.shares_memory(route.sources[s], target)
226
+ ]
227
+ return [(route.sources[(held or list(item.sources))[0]], target, "in_place")]
228
+
229
+ def _link_bits(self, tn: TransferNode, route: MulticastPathPlan) -> list[float]:
230
+ """Per link of the route, the bits one firing carries over it, as its route cycles count them."""
231
+ if self.space.choice_shares_memory(tn, route):
232
+ return [0.0] * len(route.links_used)
233
+ moved, shares = self.space.moved_bits(tn, route), dict(route.link_shares)
234
+ return [moved * shares.get(link, 0.0) if shares else moved for link in route.links_used]
235
+
156
236
  def _positions(self, node: HasIterationSpace) -> int:
157
237
  tiling = self.mapping.get(node).inter_core_tiling
158
238
  return prod(f for _, f in tiling[0]) if tiling else 1
@@ -242,10 +242,10 @@ def _solve(
242
242
  raise
243
243
  finish_instrumentation(observers)
244
244
  groups = sorted(ctx.get("group_cycles"))
245
- columns = [len(ctx.get("group_columns")[i]) for i in groups]
245
+ cores = [ctx.get("group_cores")[i] for i in groups]
246
246
  return MappingEstimate(
247
247
  mapping=mapping,
248
248
  group_cycles=tuple(ctx.get("group_cycles")[i] for i in groups),
249
- dispatch_cycles=ctx.get("allocation").problem.hardware.dispatch_overhead_cycles(columns),
249
+ dispatch_cycles=ctx.get("allocation").problem.hardware.dispatch_overhead_cycles(cores),
250
250
  context=ctx,
251
251
  )
@@ -8,7 +8,7 @@ from snaxc.ir.tsl import Stride, TiledStride, TiledStridedLayout
8
8
  from xdsl.dialects.builtin import AnyDenseElement, FunctionType, MemRefType, StringAttr, SymbolRefAttr, bf16
9
9
  from xdsl.dialects.func import CallOp, FuncOp
10
10
  from xdsl.dialects.scf import ForOp, IndexSwitchOp, YieldOp
11
- from xdsl.ir import Operation, Region, SSAValue
11
+ from xdsl.ir import Attribute, Operation, Region, SSAValue
12
12
  from xdsl.ir.affine import AffineDimExpr
13
13
  from xdsl.pattern_rewriter import PatternRewriter
14
14
  from xdsl.printer import Printer
@@ -100,14 +100,16 @@ class KernelDeclaration(FuncOp):
100
100
  @dataclass(frozen=True)
101
101
  class StateOperand:
102
102
  """A buffer a kernel keeps on its core from one step of a loop to the next: read at ``carried_over - 1`` and
103
- written at ``carried_over``, ``rows`` per step times the extent of ``indexed_by``. ``handover`` is how deep a
104
- copy the next step of the computation reads, zero for a state kept private."""
103
+ written at ``carried_over``, ``rows`` per step times the extent of ``indexed_by``, of ``element_type`` (the
104
+ output's where None). ``handover`` is how deep a copy the next step of the computation reads, zero for a state
105
+ kept private."""
105
106
 
106
107
  name: str
107
108
  rows: int
108
109
  carried_over: str
109
110
  indexed_by: str
110
111
  handover: int = 0
112
+ element_type: Attribute | None = None
111
113
 
112
114
 
113
115
  @dataclass(kw_only=True)
@@ -122,25 +124,37 @@ class AIEKernel(ABC):
122
124
  FALLBACK: ClassVar[Mapping[str, tuple[str, str | None]]] = {}
123
125
  """The symbol and object, ``None`` for the library's, stream declares for a call it names otherwise,
124
126
  where no provider binds the kernel."""
127
+ ACCUMULATOR: ClassVar[str | None] = None
128
+ """The format the kernel keeps a sum in across the calls adding into it, beside its output; None where it
129
+ adds into the output itself."""
130
+ SCRATCH_BITS: ClassVar[int] = 0
131
+ """Bits of a buffer the binding keeps on each core the kernel runs on, beside its operands and its state."""
125
132
 
126
133
  @property
127
134
  def unique_name(self) -> str:
128
135
  return self.function_name
129
136
 
137
+ @property
138
+ def library_name(self) -> str:
139
+ """The kernel library's entry for this kernel: its function, built as the library describes it."""
140
+ return self.function_name
141
+
130
142
  @property
131
143
  def spec(self) -> KernelSpec:
132
144
  if self.library is None:
133
145
  raise ValueError(f"{type(self).__name__} needs a kernel library")
134
- spec = self.library.spec(self.function_name)
146
+ spec = self.library.spec(self.library_name)
135
147
  if spec is None:
136
- raise ValueError(f"the kernel library does not describe {self.function_name}")
148
+ raise ValueError(f"the kernel library does not describe {self.library_name}")
137
149
  return spec
138
150
 
139
151
  @property
140
152
  def mac(self) -> Mapping[str, int]:
153
+ """The MAC tile the kernel computes in, which is also the tiling it leaves an operand in."""
141
154
  if self.library is None:
142
155
  raise ValueError(f"{type(self).__name__} needs a kernel library")
143
- return self.library.mac
156
+ spec = self.library.spec(self.library_name)
157
+ return spec.mac if spec is not None and spec.mac else self.library.mac
144
158
 
145
159
  def call_shape(self) -> dict[str, int]:
146
160
  return {d.name: int(getattr(self, d.name)) for d in self.spec.dims}
@@ -179,13 +193,18 @@ class AIEKernel(ABC):
179
193
  """What a call to ``call`` resolves to: the provider's binding, or stream's own declaration."""
180
194
  spec = self.spec
181
195
  if spec.binding is not None:
182
- entry = {"binding": spec.binding, "args": {**dims, "npu": bindings.npu}}
196
+ args = {**dims, **spec.options, **self.binding_options(), "npu": bindings.npu}
197
+ entry = {"binding": spec.binding, "args": args}
183
198
  return bindings.resolve(entry if call == self.function_name else entry | {"companion": call})
184
199
  symbol, object_file = self.FALLBACK.get(call, (call, None))
185
200
  if (object_file := object_file or spec.object) is None:
186
201
  raise ValueError(f"the kernel library names neither a binding nor an object for {self.function_name}")
187
202
  return bindings.resolve({"symbol": symbol, "object": object_file})
188
203
 
204
+ def binding_options(self) -> dict[str, bool]:
205
+ """What the provider builds the kernel's object with besides the call's dimensions."""
206
+ return {}
207
+
189
208
  @property
190
209
  @abstractmethod
191
210
  def function_name(self) -> str: ...