stream-dse 2.2.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.
- {stream_dse-2.2.0/stream_dse.egg-info → stream_dse-2.4.0}/PKG-INFO +20 -3
- {stream_dse-2.2.0 → stream_dse-2.4.0}/pyproject.toml +28 -5
- stream_dse-2.4.0/stream/__init__.py +1 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/aie_setup.py +3 -3
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/allocation/allocation.py +17 -11
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/allocation/lowering.py +60 -35
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/allocation/solution.py +2 -2
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/allocation/steady_state.py +98 -18
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/api.py +2 -2
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/kernels/aie_kernel.py +26 -7
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/kernels/flash.py +141 -62
- stream_dse-2.4.0/stream/compiler/kernels/gemm.py +360 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/kernels/library.py +8 -1
- stream_dse-2.4.0/stream/compiler/kernels/mlir_aie.py +123 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/kernels/registry.py +8 -2
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_convert_ofs.py +250 -109
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/convert_stream_to_aie.py +36 -6
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/cost_model/bandwidth.py +37 -7
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/cost_model/communication_manager.py +191 -89
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/cost_model/core_cost_lut.py +1 -1
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/cost_model/layout.py +31 -16
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/cost_model/roofline.py +20 -4
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/architecture/backends/__init__.py +2 -2
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/architecture/backends/aie2.py +4 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/architecture/backends/zigzag.py +48 -1
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/architecture/core.py +11 -1
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/cost.py +130 -1
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/whole_array_strix.yaml +13 -8
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/ir/allocation.py +39 -17
- stream_dse-2.4.0/stream/mapping/blocks.py +163 -0
- stream_dse-2.4.0/stream/mapping/capacity_tiler.py +1370 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/mapping/generic_generator.py +80 -16
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/mapping/work_share.py +60 -1
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/allocation_model.py +22 -11
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/__init__.py +11 -2
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/aie2.py +30 -2
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/dma.py +8 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/energy.py +16 -2
- stream_dse-2.4.0/stream/opt/allocation/constraint_optimization/families/latency.py +247 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/memory.py +62 -24
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/memory_ports.py +83 -25
- stream_dse-2.4.0/stream/opt/allocation/constraint_optimization/families/offchip.py +111 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/overlap.py +281 -42
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/reuse.py +116 -18
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/families/routing.py +18 -9
- stream_dse-2.4.0/stream/opt/allocation/constraint_optimization/families/traffic.py +302 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/hardware.py +60 -16
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/layouts.py +70 -6
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/report.py +44 -22
- stream_dse-2.4.0/stream/opt/allocation/constraint_optimization/space.py +1088 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/utils.py +5 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/solver/solver.py +30 -17
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/accelerator_validator.py +19 -7
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/mapping_factory.py +4 -2
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/mapping_validator.py +1 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/codegen/aie_code_generation.py +46 -27
- stream_dse-2.4.0/stream/stages/estimation/accelforge/__init__.py +1 -0
- stream_dse-2.4.0/stream/stages/estimation/accelforge/arch.py +140 -0
- stream_dse-2.4.0/stream/stages/estimation/accelforge/backend.py +220 -0
- stream_dse-2.4.0/stream/stages/estimation/accelforge/library.py +32 -0
- stream_dse-2.4.0/stream/stages/estimation/accelforge/mapper.py +191 -0
- stream_dse-2.4.0/stream/stages/estimation/accelforge/tree.py +148 -0
- stream_dse-2.4.0/stream/stages/estimation/accelforge/workload.py +170 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/estimation/aie_cost_estimator.py +17 -5
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/estimation/core_cost_backends.py +79 -7
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/estimation/core_cost_estimation.py +59 -19
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/estimation/memory_accesses_estimation.py +47 -22
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/estimation/zigzag_cost_estimator.py +163 -27
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/fixed_mapping_generation.py +48 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/fusion_group_iteration.py +9 -11
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/kernel_state.py +2 -1
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/placement_generation.py +91 -0
- stream_dse-2.4.0/stream/stages/generation/tile_search.py +271 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/tiling_generation.py +5 -2
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/visualization/steady_state_trace.py +12 -4
- stream_dse-2.4.0/stream/workload/demand.py +123 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/node_key.py +2 -0
- stream_dse-2.4.0/stream/workload/post_ops.py +72 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/utils.py +187 -53
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/workload.py +948 -200
- {stream_dse-2.2.0 → stream_dse-2.4.0/stream_dse.egg-info}/PKG-INFO +20 -3
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream_dse.egg-info/SOURCES.txt +20 -2
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream_dse.egg-info/entry_points.txt +1 -0
- stream_dse-2.4.0/stream_dse.egg-info/requires.txt +46 -0
- stream_dse-2.4.0/tests/test_absent_latency.py +152 -0
- stream_dse-2.4.0/tests/test_boundary_coupling.py +318 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_conv_windows.py +26 -16
- stream_dse-2.4.0/tests/test_copy_sets.py +512 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_data_layout.py +28 -8
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_decode_kv.py +115 -24
- stream_dse-2.4.0/tests/test_epilogue_latency.py +68 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_hardware_combinations.py +34 -22
- stream_dse-2.4.0/tests/test_mapping_validation.py +160 -0
- stream_dse-2.4.0/tests/test_precision.py +470 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_roofline.py +37 -1
- stream_dse-2.4.0/tests/test_sliding_halos.py +127 -0
- stream_dse-2.4.0/tests/test_split_sliding_step.py +103 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_steady_state_detail.py +12 -12
- stream_dse-2.4.0/tests/test_steady_state_ir.py +132 -0
- stream_dse-2.4.0/tests/test_strided_gather.py +254 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_tpu_v7.py +166 -12
- stream_dse-2.4.0/tests/test_transfer_demand.py +107 -0
- stream_dse-2.2.0/stream/__init__.py +0 -1
- stream_dse-2.2.0/stream/compiler/fifo_depths.py +0 -84
- stream_dse-2.2.0/stream/compiler/kernels/gemm.py +0 -57
- stream_dse-2.2.0/stream/compiler/kernels/mlir_aie.py +0 -105
- stream_dse-2.2.0/stream/mapping/blocks.py +0 -58
- stream_dse-2.2.0/stream/mapping/capacity_tiler.py +0 -625
- stream_dse-2.2.0/stream/opt/allocation/constraint_optimization/families/latency.py +0 -78
- stream_dse-2.2.0/stream/opt/allocation/constraint_optimization/families/offchip.py +0 -50
- stream_dse-2.2.0/stream/opt/allocation/constraint_optimization/families/traffic.py +0 -156
- stream_dse-2.2.0/stream/opt/allocation/constraint_optimization/space.py +0 -627
- stream_dse-2.2.0/stream/stages/generation/tile_search.py +0 -156
- stream_dse-2.2.0/stream_dse.egg-info/requires.txt +0 -28
- stream_dse-2.2.0/tests/test_precision.py +0 -198
- {stream_dse-2.2.0 → stream_dse-2.4.0}/LICENSE +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/README.md +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/setup.cfg +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/allocation/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/allocation/artifacts.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/allocation/problem.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/context/aie_context.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/dialects/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/dialects/stream.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/kernels/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/kernels/binding.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/kernels/eltwise_mul.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/kernels/silu.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/kernels/softmax.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_add_tracing_script.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_dispatch.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_move_tile_ops_up.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/aie_tiles.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/clear_memory_space.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/convert_aie_kernels.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/hoist_scale_acquires.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/iteration_space_to_for.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/compiler/transforms/unroll.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/cost_model/core_cost.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/cost_model/memory_accesses.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/datatypes.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/frontends/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/frontends/onnx.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/frontends/torch_export.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/architecture/accelerator.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/architecture/memory.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/architecture/noc/communication_link.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/bundle.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/hardware/ports.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/cores/aie_tile.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/cores/mem_tile_256KB.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/cores/mem_tile_512KB.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/single_col.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/single_core.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/hardware/whole_array.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/kernels/aie2p.toml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/mapping/make_gemm_mapping.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/mapping/make_swiglu_mapping.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/workload/make_onnx_gemm.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/aie/workload/make_onnx_swiglu.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/eyeriss_like.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/fusemax_array.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/fusemax_vec.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/meta_prototype.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/pooling.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/simba_chiplet.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/simd.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/tpu_like.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/tpu_v7_mxu.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/tpu_v7_vmem.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/cores/tpu_v7_vpu.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/eyeriss_like_dual_core.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/eyeriss_like_quad_core.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/eyeriss_like_single_core.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/fusemax.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/meta_prototype_dual_core_simd_offchip.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/simba.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/simba_small.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/tpu_like_quad_core.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/examples/hardware/tpu_v7_ironwood.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/pooling.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/shared_testing_core1.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/shared_testing_core2.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/simd.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/testing_core1.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/testing_core2.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/cores/tpu_like.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/tpu_like_quad_core.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/tpu_like_ring_hbm.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/hardware/tpu_v7_ironwood_hbm_per_chiplet.yaml +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/mapping/make_2_conv_mapping.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_2_conv.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_attention_head.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_conv_relu_flatten_gemm.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_decode_attention.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_resnet_subgraph.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_scan.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/inputs/testing/workload/make_swiglu.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/instrumentation.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/ir/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/ir/accelerator.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/ir/graph_view.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/ir/infeasibility.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/ir/roofline.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/ir/workload.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/mapping/chain_placement.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/mapping/mapping.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/mcp/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/mcp/jobs.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/mcp/server.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/diagnosis.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/formulation.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/allocation/constraint_optimization/quantities.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/opt/solver/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/accelerator_factory.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/core_validator.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/mapping_parser.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/batch_norm.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/conv.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/einsum.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/elementwise.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/gemm.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/global_average_pool.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/layout.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/matmul.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/max_pool.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/model.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/normalization.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/operator_parser.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/reduce.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/slice_gather.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/parser/onnx/utils.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/plugins.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/profiling.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/allocation/steady_state_allocation.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/allocation/steady_state_lowering.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/codegen/backends.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/context.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/flash_decoding.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/fusion_analysis.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/fusion_proposal.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/generic_mapping_generation.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/mapping_generators.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/normalization_expansion.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/generation/structural_dedup.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/parsing/accelerator_parser.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/parsing/onnx_model_parser.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/stages/stage.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/visualization/hardware_graph.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/_svg.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/access_relation.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/affine_access.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/affine_exact.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/affine_transform.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/blocks/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/blocks/library.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/data_movement.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/decompose.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/fusion/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/fusion/analysis.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/fusion/proposer.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/iterator_type.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/models.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/node.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/normalization.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/rewrites/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/rewrites/base.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/rewrites/flash_attention.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/rewrites/flash_decoding.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/rewrites/reference.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/steady_state/computation.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/steady_state/iteration_space.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/steady_state/node.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/structure/__init__.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/structure/block_detect.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/structure/wl.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream/workload/tensor.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream_dse.egg-info/dependency_links.txt +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/stream_dse.egg-info/top_level.txt +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_accelerator_ir.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_ci_workflow.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_co.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_core_cost_lut_caching.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_core_validation.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_decode_attention.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_edge_placements.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_generic_mapping.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_hardware_bundle.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_layout_einsum_reduce.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_metrics_capture.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_on_chip_placement.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_render_metrics_comment.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_resnet_mapping.py +0 -0
- {stream_dse-2.2.0 → stream_dse-2.4.0}/tests/test_resnet_patterns.py +0 -0
- {stream_dse-2.2.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
|
+
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
|
|
@@ -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.
|
|
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.
|
|
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" }]
|
|
@@ -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.
|
|
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.
|
|
151
|
+
current_version = "2.4.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.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.
|
|
35
|
-
_LLVM_AIE_PIN = "llvm-aie==22.0.0.
|
|
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/
|
|
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
|
|
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
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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
|
-
|
|
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
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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,
|
|
38
|
-
reuse_factors: Mapping[TransferNode,
|
|
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
|
|
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":
|
|
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,
|
|
120
|
-
|
|
121
|
-
|
|
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
|
|
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
|
-
"
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
104
|
-
copy the next step of the computation reads, zero for a state
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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: ...
|