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