accelforge 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- accelforge/__init__.py +21 -0
- accelforge/_accelerated_imports.py +16 -0
- accelforge/_deprecate/_simanneal/evalmapping.py +271 -0
- accelforge/_deprecate/_simanneal/mapspaceglobals.py +298 -0
- accelforge/_deprecate/_simanneal/simanneal.py +666 -0
- accelforge/_deprecate/_simanneal/tracking.py +105 -0
- accelforge/_deprecate/_simanneal/wrappers.py +218 -0
- accelforge/_deprecate/_simanneal2/__init__.py +7 -0
- accelforge/_deprecate/_simanneal2/simanneal.py +493 -0
- accelforge/_deprecate/_simanneal2/tracking.py +116 -0
- accelforge/_deprecate/compatibility_util.py +181 -0
- accelforge/_deprecate/layerdeduplication/__init__.py +2 -0
- accelforge/_deprecate/layerdeduplication/group_similar_einsums.py +160 -0
- accelforge/_deprecate/layerdeduplication/grouped_einsums.py +84 -0
- accelforge/_deprecate/mapping_filter_tags/__init__.py +2 -0
- accelforge/_deprecate/mapping_filter_tags/ffmt.py +212 -0
- accelforge/_deprecate/mapping_filter_tags/onesplit.py +24 -0
- accelforge/_deprecate/mapping_filter_tags/util.py +24 -0
- accelforge/_deprecate/tags.py +69 -0
- accelforge/_deprecate/viz/__init__.py +0 -0
- accelforge/_deprecate/viz/interactive.py +159 -0
- accelforge/_deprecate/viz/reservationtree.py +307 -0
- accelforge/_deprecate/viz/ski_slope.py +88 -0
- accelforge/_version.py +15 -0
- accelforge/examples.py +39 -0
- accelforge/frontend/__init__.py +10 -0
- accelforge/frontend/_binding.py +129 -0
- accelforge/frontend/_workload_isl/__init__.py +2 -0
- accelforge/frontend/_workload_isl/_isl.py +149 -0
- accelforge/frontend/_workload_isl/_symbolic.py +141 -0
- accelforge/frontend/arch copy.py +1544 -0
- accelforge/frontend/arch.py +1642 -0
- accelforge/frontend/config.py +63 -0
- accelforge/frontend/mapper/__init__.py +5 -0
- accelforge/frontend/mapper/ffm.py +126 -0
- accelforge/frontend/mapper/mapper.py +7 -0
- accelforge/frontend/mapper/metrics.py +30 -0
- accelforge/frontend/mapping/__init__.py +1 -0
- accelforge/frontend/mapping/mapping.py +1736 -0
- accelforge/frontend/model.py +14 -0
- accelforge/frontend/renames.py +150 -0
- accelforge/frontend/spec copy.py +230 -0
- accelforge/frontend/spec.py +301 -0
- accelforge/frontend/variables.py +12 -0
- accelforge/frontend/workload.py +952 -0
- accelforge/mapper/FFM/__init__.py +9 -0
- accelforge/mapper/FFM/_join_pmappings/__init__.py +0 -0
- accelforge/mapper/FFM/_join_pmappings/compatibility.py +653 -0
- accelforge/mapper/FFM/_join_pmappings/compress_pmappings.py +140 -0
- accelforge/mapper/FFM/_join_pmappings/join_pmappings.py +703 -0
- accelforge/mapper/FFM/_join_pmappings/pmapping_dataframe.py +901 -0
- accelforge/mapper/FFM/_join_pmappings/pmapping_group.py +337 -0
- accelforge/mapper/FFM/_make_pmappings/contraints/__init__.py +0 -0
- accelforge/mapper/FFM/_make_pmappings/contraints/constraints.py +360 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/__init__.py +1 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_loops.py +373 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_pmapping_templates.py +463 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_reservations.py +95 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_storage_order.py +382 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmapping_templates/make_storages.py +155 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmappings.py +411 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/__init__.py +1 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/make_pmappings_from_templates.py +407 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/make_tile_shapes.py +1681 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/run_model.py +170 -0
- accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/symbol_relations.py +174 -0
- accelforge/mapper/FFM/_make_pmappings/pmapper_job.py +282 -0
- accelforge/mapper/FFM/_pareto_df/df_convention.py +273 -0
- accelforge/mapper/FFM/_pareto_df/pareto copy.py +836 -0
- accelforge/mapper/FFM/_pareto_df/pareto.py +508 -0
- accelforge/mapper/FFM/data.py +61 -0
- accelforge/mapper/FFM/main copy.py +236 -0
- accelforge/mapper/FFM/main.py +208 -0
- accelforge/mapper/FFM/mappings.py +510 -0
- accelforge/mapper/FFM/pmappings.py +310 -0
- accelforge/mapper/__init__.py +4 -0
- accelforge/mapper.py +0 -0
- accelforge/model/__init__.py +1 -0
- accelforge/model/_looptree/__init__.py +0 -0
- accelforge/model/_looptree/accesses.py +335 -0
- accelforge/model/_looptree/capacity/__init__.py +1 -0
- accelforge/model/_looptree/capacity/aggregators.py +36 -0
- accelforge/model/_looptree/capacity/capacity.py +47 -0
- accelforge/model/_looptree/energy.py +150 -0
- accelforge/model/_looptree/equivalent_ranks.py +29 -0
- accelforge/model/_looptree/latency/__init__.py +1 -0
- accelforge/model/_looptree/latency/latency.py +98 -0
- accelforge/model/_looptree/latency/memory.py +120 -0
- accelforge/model/_looptree/latency/processors.py +92 -0
- accelforge/model/_looptree/mapping_utilities.py +71 -0
- accelforge/model/_looptree/reuse/__init__.py +4 -0
- accelforge/model/_looptree/reuse/isl/__init__.py +1 -0
- accelforge/model/_looptree/reuse/isl/des.py +59 -0
- accelforge/model/_looptree/reuse/isl/isl_functions.py +374 -0
- accelforge/model/_looptree/reuse/isl/mapping_to_isl/__init__.py +4 -0
- accelforge/model/_looptree/reuse/isl/mapping_to_isl/analyze_mapping.py +297 -0
- accelforge/model/_looptree/reuse/isl/mapping_to_isl/skews_from_mapping.py +236 -0
- accelforge/model/_looptree/reuse/isl/mapping_to_isl/tiling.py +685 -0
- accelforge/model/_looptree/reuse/isl/mapping_to_isl/types.py +188 -0
- accelforge/model/_looptree/reuse/isl/spatial.py +260 -0
- accelforge/model/_looptree/reuse/isl/temporal.py +182 -0
- accelforge/model/_looptree/reuse/symbolic/__init__.py +1 -0
- accelforge/model/_looptree/reuse/symbolic/symbolic copy 2.py +1346 -0
- accelforge/model/_looptree/reuse/symbolic/symbolic copy.py +1408 -0
- accelforge/model/_looptree/reuse/symbolic/symbolic.py +1396 -0
- accelforge/model/_looptree/run.py +122 -0
- accelforge/model/_looptree/types.py +26 -0
- accelforge/model/_looptree/visualization/__init__.py +0 -0
- accelforge/model/_looptree/visualization/occupancy.py +11 -0
- accelforge/model/main.py +222 -0
- accelforge/plotting/__init__.py +2 -0
- accelforge/plotting/mappings.py +219 -0
- accelforge/plotting/specs.py +57 -0
- accelforge/util/__init__.py +4 -0
- accelforge/util/_base_analysis_types.py +24 -0
- accelforge/util/_basetypes.py +1089 -0
- accelforge/util/_frozenset.py +36 -0
- accelforge/util/_isl.py +29 -0
- accelforge/util/_itertools.py +14 -0
- accelforge/util/_mathfuncs.py +57 -0
- accelforge/util/_parse_expressions.py +339 -0
- accelforge/util/_picklecache.py +32 -0
- accelforge/util/_setexpressions.py +268 -0
- accelforge/util/_sympy/__init__.py +0 -0
- accelforge/util/_sympy/broadcast_max.py +18 -0
- accelforge/util/_visualization.py +112 -0
- accelforge/util/_yaml.py +579 -0
- accelforge/util/parallel.py +193 -0
- accelforge-0.0.1.dist-info/METADATA +64 -0
- accelforge-0.0.1.dist-info/RECORD +258 -0
- accelforge-0.0.1.dist-info/WHEEL +5 -0
- accelforge-0.0.1.dist-info/licenses/LICENSE +19 -0
- accelforge-0.0.1.dist-info/top_level.txt +5 -0
- docs/_build/html/_sources/fastfusion.frontend.mapper.rst.txt +37 -0
- docs/_build/html/_sources/fastfusion.frontend.rst.txt +70 -0
- docs/_build/html/_sources/fastfusion.frontend.workload.rst.txt +21 -0
- docs/_build/html/_sources/fastfusion.mapper.FFM.rst.txt +37 -0
- docs/_build/html/_sources/fastfusion.mapper.rst.txt +18 -0
- docs/_build/html/_sources/fastfusion.rst.txt +20 -0
- docs/_build/html/_sources/fastfusion.util.rst.txt +21 -0
- docs/_build/html/_sources/index.rst.txt +87 -0
- docs/_build/html/_sources/modules.rst.txt +7 -0
- docs/_build/html/_sources/notes/citation.rst.txt +45 -0
- docs/_build/html/_sources/notes/definitions.rst.txt +43 -0
- docs/_build/html/_sources/notes/faqs.rst.txt +39 -0
- docs/_build/html/_sources/notes/modeling/accelerator_energy_latency.rst.txt +72 -0
- docs/_build/html/_sources/notes/modeling/component_energy_area.rst.txt +96 -0
- docs/_build/html/_sources/notes/modeling/mapping.rst.txt +100 -0
- docs/_build/html/_sources/notes/modeling.rst.txt +33 -0
- docs/_build/html/_sources/notes/parsing/arithmetic_parsing.rst.txt +136 -0
- docs/_build/html/_sources/notes/parsing/setexpressions.rst.txt +63 -0
- docs/_build/html/_sources/notes/parsing/yaml_parsing.rst.txt +176 -0
- docs/_build/html/_sources/notes/quickstart_and_installation.rst.txt +9 -0
- docs/_build/html/_sources/notes/spec/architecture.rst.txt +133 -0
- docs/_build/html/_sources/notes/spec/mapping.rst.txt +12 -0
- docs/_build/html/_sources/notes/spec/workload.rst.txt +83 -0
- docs/_build/html/_sources/notes/spec.rst.txt +36 -0
- docs/source/_ext/include_attrs.py +213 -0
- docs/source/_ext/include_docstring.py +364 -0
- docs/source/_ext/include_functions.py +154 -0
- docs/source/_ext/include_notebook.py +131 -0
- docs/source/_ext/include_yaml.py +119 -0
- docs/source/_ext/inherited_attributes.py +222 -0
- docs/source/_ext/paths.py +4 -0
- docs/source/conf.py +79 -0
- examples/arches/compute_in_memory/_include.yaml +74 -0
- examples/arches/compute_in_memory/_include_functions.py +229 -0
- examples/arches/compute_in_memory/_load_spec.py +57 -0
- examples/arches/compute_in_memory/components/c2c_multiplier.py +181 -0
- examples/arches/compute_in_memory/components/dac_c2c_r2r.py +605 -0
- examples/arches/compute_in_memory/components/misc.py +195 -0
- examples/arches/compute_in_memory/components/util/bit_functions.py +51 -0
- examples/arches/compute_in_memory/components/zero_comparator.py +92 -0
- examples/arches/compute_in_memory/isaac.yaml +233 -0
- examples/arches/compute_in_memory/memory_cells/ecram_demo.yaml +63 -0
- examples/arches/compute_in_memory/memory_cells/rram_example.yaml +63 -0
- examples/arches/compute_in_memory/memory_cells/rram_isaac_isca_2016.yaml +64 -0
- examples/arches/compute_in_memory/memory_cells/rram_neurosim_default.yaml +63 -0
- examples/arches/compute_in_memory/memory_cells/rram_raella_isca_2023.yaml +70 -0
- examples/arches/compute_in_memory/memory_cells/rram_wan_nature_2022.yaml +63 -0
- examples/arches/compute_in_memory/memory_cells/sram_colonnade_jssc_2021.yaml +63 -0
- examples/arches/compute_in_memory/memory_cells/sram_example.yaml +63 -0
- examples/arches/compute_in_memory/memory_cells/sram_jia_jssc_2020.yaml +63 -0
- examples/arches/compute_in_memory/memory_cells/sram_sinangil_jssc_2021.yaml +63 -0
- examples/arches/compute_in_memory/memory_cells/sram_wang_vlsi_2022.yaml +63 -0
- examples/arches/compute_in_memory/wang_vlsi_2022.yaml +289 -0
- examples/arches/eyeriss.yaml +68 -0
- examples/arches/fanout_variations/at_glb.yaml +31 -0
- examples/arches/fanout_variations/at_glb_with_fanout_node.yaml +34 -0
- examples/arches/fanout_variations/at_mac.yaml +31 -0
- examples/arches/fanout_variations/at_mac_with_constraints.yaml +38 -0
- examples/arches/fanout_variations/at_mac_with_fanout_node.yaml +34 -0
- examples/arches/nvdla.yaml +47 -0
- examples/arches/simple.yaml +28 -0
- examples/arches/tpu_v4i.yaml +67 -0
- examples/mappings/unfused_matmuls_to_simple.yaml +33 -0
- examples/misc/component_annotated.yaml +33 -0
- examples/workloads/gpt3_6.7B.yaml +124 -0
- examples/workloads/matmuls.yaml +20 -0
- examples/workloads/mobilenet_28.yaml +81 -0
- examples/workloads/mobilenet_various_separate.yaml +106 -0
- examples/workloads/three_matmuls_annotated.yaml +59 -0
- notebooks/.ipynb_checkpoints/fastfusion_arch_study_michael-checkpoint.ipynb +359 -0
- notebooks/compute_in_memory/_scripts.py +339 -0
- notebooks/compute_in_memory/isaac.guide.ipynb +270 -0
- notebooks/compute_in_memory/wang_vlsi_2022.ipynb +602 -0
- notebooks/paths.py +4 -0
- notebooks/tutorials/.ipynb_checkpoints/1_FFM-checkpoint.ipynb +3110 -0
- notebooks/tutorials/FFM.ipynb +3498 -0
- notebooks/tutorials/_include.py +48 -0
- notebooks/tutorials/component_energy_area.ipynb +363 -0
- tests/Q_mapping.yaml +38 -0
- tests/__init__.py +0 -0
- tests/conv.mapping.yaml +27 -0
- tests/conv.workload.yaml +13 -0
- tests/conv_sym.mapping.yaml +43 -0
- tests/copy.mapping.yaml +35 -0
- tests/copy.workload.yaml +15 -0
- tests/distribuffers/__init__.py +0 -0
- tests/distribuffers/multicast/test_cases.yaml +482 -0
- tests/distribuffers/spec/binding/valid_bindings.yaml +97 -0
- tests/distribuffers/spec/distributed.yaml +100 -0
- tests/distribuffers/spec/logical_arch.yaml +32 -0
- tests/distribuffers/spec/physical_arch.yaml +69 -0
- tests/distribuffers/test_binding.py +48 -0
- tests/frontend/__init__.py +0 -0
- tests/frontend/test_mapping_viz.py +52 -0
- tests/mapper/__init__.py +0 -0
- tests/mapper/configs/conv1d/conv1d.mapping.yaml +31 -0
- tests/mapper/configs/conv1d/conv1d.workload.yaml +11 -0
- tests/mapper/configs/two_conv1d/two_conv1d.expected.yaml +38 -0
- tests/mapper/configs/two_conv1d/two_conv1d.mapping.yaml +54 -0
- tests/mapper/configs/two_conv1d/two_conv1d.workload.yaml +19 -0
- tests/mapper/test_mapping_to_isl.py +90 -0
- tests/mapper/test_spatial_reuse_analysis.py +67 -0
- tests/mapper/test_temporal_reuse_analysis.py +56 -0
- tests/mapper/util.py +58 -0
- tests/matmul.mapping.yaml +29 -0
- tests/matmul.workload.yaml +12 -0
- tests/matmul_spatial.mapping.yaml +44 -0
- tests/mha.renames.yaml +65 -0
- tests/mha.workload.yaml +67 -0
- tests/mha.yaml +59 -0
- tests/mha_full.workload.yaml +67 -0
- tests/mobilenet.workload.yaml +35 -0
- tests/mobilenet_long.workload.yaml +64 -0
- tests/pmappingcache.py +24 -0
- tests/processing_stage.arch.yaml +40 -0
- tests/snowcat.arch.yaml +36 -0
- tests/test_ffm_join_pmappings.py +106 -0
- tests/test_ffm_make_pmappings.py +82 -0
- tests/test_ffm_make_tile_shapes.py +49 -0
- tests/test_mapper.py +100 -0
- tests/test_model.py +37 -0
- tests/test_plotting.py +72 -0
- tests/test_processing_stage.py +46 -0
- tests/test_symbolic_model.py +248 -0
- tests/test_workload.py +141 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "code",
|
|
5
|
+
"execution_count": 1,
|
|
6
|
+
"metadata": {},
|
|
7
|
+
"outputs": [
|
|
8
|
+
{
|
|
9
|
+
"name": "stderr",
|
|
10
|
+
"output_type": "stream",
|
|
11
|
+
"text": [
|
|
12
|
+
"WARNING Loading configuration file from /home/gilbertm/work/infrastructure/venv/fastfusion/config.yaml\n",
|
|
13
|
+
"WARNING Loading configuration file from /home/gilbertm/work/infrastructure/venv/fastfusion/config.yaml\n"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "stdout",
|
|
18
|
+
"output_type": "stream",
|
|
19
|
+
"text": [
|
|
20
|
+
"Loading from cache: Unfused64-512-256\n",
|
|
21
|
+
"Loading from cache: FlashAttention A64-512-256\n",
|
|
22
|
+
"Loading from cache: FlashAttention B64-512-256\n",
|
|
23
|
+
"Loading from cache: Fixed-Dataflow64-512-256\n",
|
|
24
|
+
"Loading from cache: FFM64-512-256\n",
|
|
25
|
+
"Loading from cache: Unfused1-8192-256\n"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "stderr",
|
|
30
|
+
"output_type": "stream",
|
|
31
|
+
"text": [
|
|
32
|
+
"WARNING Loading configuration file from /home/gilbertm/work/infrastructure/venv/fastfusion/config.yaml\n"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "stdout",
|
|
37
|
+
"output_type": "stream",
|
|
38
|
+
"text": [
|
|
39
|
+
"Loading from cache: FlashAttention A1-8192-256\n",
|
|
40
|
+
"Loading from cache: FlashAttention B1-8192-256\n",
|
|
41
|
+
"Loading from cache: Fixed-Dataflow1-8192-256\n",
|
|
42
|
+
"Loading from cache: FFM1-8192-256\n",
|
|
43
|
+
"Loading from cache: Unfused1-32768-256\n",
|
|
44
|
+
"Loading from cache: FlashAttention A1-32768-256\n",
|
|
45
|
+
"Loading from cache: FlashAttention B1-32768-256\n",
|
|
46
|
+
"Loading from cache: Fixed-Dataflow1-32768-256\n",
|
|
47
|
+
"Loading from cache: FFM1-32768-256\n"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"source": [
|
|
52
|
+
"import hashlib\n",
|
|
53
|
+
"import os\n",
|
|
54
|
+
"import pickle\n",
|
|
55
|
+
"from hwcomponents_cacti import SRAM as CactiSRAM\n",
|
|
56
|
+
"from hwcomponents_library import AladdinAdder, AladdinMultiplier\n",
|
|
57
|
+
"\n",
|
|
58
|
+
"from fastfusion.frontend.architecture import Memory\n",
|
|
59
|
+
"from fastfusion.frontend.specification import Specification\n",
|
|
60
|
+
"from fastfusion.mapper.FFM.exploration.mapper_multi_einsum import get_sims\n",
|
|
61
|
+
"from fastfusion.mapper.simanneal.wrappers import join_sims\n",
|
|
62
|
+
"\n",
|
|
63
|
+
"import copy\n",
|
|
64
|
+
"import time\n",
|
|
65
|
+
"from fastfusion import Specification\n",
|
|
66
|
+
"from fastfusion.mapper.metrics import Metrics\n",
|
|
67
|
+
"from fastfusion.mapper.FFM.exploration.mapper_multi_einsum import get_sims\n",
|
|
68
|
+
"from fastfusion.mapper.FFM.joining.sim import SIM\n",
|
|
69
|
+
"from fastfusion.mapper.FFM.joining.simexplore import join_sims\n",
|
|
70
|
+
"import fastfusion.mapper.FFM.exploration.mapper_one_einsum as mapper_one_einsum\n",
|
|
71
|
+
"\n",
|
|
72
|
+
"from fastfusion.mapper.FFM.exploration.mapping_filter_tags.ffmt import get_ffmt_tag\n",
|
|
73
|
+
"from fastfusion.mapper.FFM.exploration.mapping_filter_tags.onesplit import get_one_split_tag\n",
|
|
74
|
+
"from fastfusion.mapper.FFM.pareto import PartialMappings\n",
|
|
75
|
+
"from fastfusion.mapper.FFM import make_pmappings, join_pmappings\n",
|
|
76
|
+
"\n",
|
|
77
|
+
"# TODO: Make a setting for the below two in the spec\n",
|
|
78
|
+
"# TODO: Generate pmappings one Einsum at a time. Once we've made compatibility, check it\n",
|
|
79
|
+
"# against the previously-generated compatibilities and stop if there's no match.\n",
|
|
80
|
+
"# TODO: Once the previous is done, also add a forward check. Once the compatibilities of\n",
|
|
81
|
+
"# a particular Einsum are generated, we can immediately check the previous Einsums.\n",
|
|
82
|
+
"\n",
|
|
83
|
+
"objective = lambda df: df['Total\\0latency']# * df['Total_Energy']\n",
|
|
84
|
+
"LOAD_FROM_CACHE = True\n",
|
|
85
|
+
"\n",
|
|
86
|
+
"def get_fused_mappings(\n",
|
|
87
|
+
" spec: Specification, \n",
|
|
88
|
+
" cache_key=None,\n",
|
|
89
|
+
" parameterization=\"\",\n",
|
|
90
|
+
" ) -> PartialMappings:\n",
|
|
91
|
+
" os.makedirs(\"cache\", exist_ok=True)\n",
|
|
92
|
+
" if cache_key is not None:\n",
|
|
93
|
+
" fname = parameterization + \"-\".join(str(x) for x in cache_key)\n",
|
|
94
|
+
" if LOAD_FROM_CACHE and os.path.exists(f\"cache/{fname}.pkl\"):\n",
|
|
95
|
+
" print(f\"Loading from cache: {fname}\")\n",
|
|
96
|
+
" mappings = pickle.load(open(f\"cache/{fname}.pkl\", \"rb\"))\n",
|
|
97
|
+
" return objective(mappings.data).min() if mappings is not None else None, mappings\n",
|
|
98
|
+
" spec = copy.deepcopy(spec)\n",
|
|
99
|
+
" \n",
|
|
100
|
+
" main_memory: Memory = spec.architecture.nodes[\"MainMemory\"]\n",
|
|
101
|
+
" if parameterization == \"Unfused\":\n",
|
|
102
|
+
" main_memory.constraints.tensors.keep = \"All()\"\n",
|
|
103
|
+
" elif parameterization == \"FlashAttention B\":\n",
|
|
104
|
+
" main_memory.constraints.tensors.keep = \"~bypass\"\n",
|
|
105
|
+
" main_memory.constraints.tensors.bypass = \"I | Q | K | V | QK | QK_softmax\"#Q | K | V | I\"# | QK | FFA\"\n",
|
|
106
|
+
" elif parameterization == \"FlashAttention A\":\n",
|
|
107
|
+
" main_memory.constraints.tensors.keep = \"~bypass\"\n",
|
|
108
|
+
" main_memory.constraints.tensors.bypass = \"QK | QK_softmax\"#Q | K | V | I\"# | QK | FFA\"\n",
|
|
109
|
+
" elif parameterization == \"FFM\":\n",
|
|
110
|
+
" main_memory.constraints.tensors.keep = \"~Intermediates()\" #\"# | AV | Z \"\n",
|
|
111
|
+
" pass\n",
|
|
112
|
+
" elif parameterization == \"Fixed-Dataflow\":\n",
|
|
113
|
+
" main_memory.constraints.tensors.keep = \"~Intermediates() | weight\"\n",
|
|
114
|
+
" spec.architecture.nodes[\"GlobalBuffer\"].constraints.dataflow.tensor_order_options = [\n",
|
|
115
|
+
" [\"MainMemory.tensors() & weight\", \"MainMemory.tensors() & input\", \"MainMemory.tensors() & output\", \"weight - MainMemory.tensors()\", \"input - MainMemory.tensors()\", \"output - MainMemory.tensors()\"],\n",
|
|
116
|
+
" ]\n",
|
|
117
|
+
" else:\n",
|
|
118
|
+
" assert False, f\"Parameterization {parameterization} not supported\"\n",
|
|
119
|
+
" \n",
|
|
120
|
+
" spec.calculate_component_energy_area()\n",
|
|
121
|
+
" if LOAD_FROM_CACHE and cache_key is not None and os.path.exists(f\"pmappings_cache/{fname}.pkl\"):\n",
|
|
122
|
+
" print(f\"Loading from cache: {fname}\")\n",
|
|
123
|
+
" pmappings = pickle.load(open(f\"cache/pmappings_{fname}.pkl\", \"rb\"))\n",
|
|
124
|
+
" else:\n",
|
|
125
|
+
" pmappings = make_pmappings(spec)\n",
|
|
126
|
+
" pickle.dump(pmappings, open(f\"cache/pmappings_{fname}.pkl\", \"wb\"))\n",
|
|
127
|
+
" try:\n",
|
|
128
|
+
" mappings = join_pmappings(spec, pmappings)\n",
|
|
129
|
+
" except:\n",
|
|
130
|
+
" mappings = None\n",
|
|
131
|
+
"\n",
|
|
132
|
+
" # TODO: the final joined pmappings have lambdas somewhere, which can't be pickled.\n",
|
|
133
|
+
" if cache_key is not None:\n",
|
|
134
|
+
" pickle.dump(mappings, open(f\"cache/{fname}.pkl\", \"wb\"))\n",
|
|
135
|
+
" \n",
|
|
136
|
+
" return objective(mappings.data).min() if mappings is not None else None, mappings\n",
|
|
137
|
+
"\n",
|
|
138
|
+
"parameterization2edp = {}\n",
|
|
139
|
+
"parameterization2mappings = {}\n",
|
|
140
|
+
"\n",
|
|
141
|
+
"parameterizations = [\"Unfused\", \"FlashAttention A\", \"FlashAttention B\", \"Fixed-Dataflow\", \"FFM\"]\n",
|
|
142
|
+
"# for batch_size, n_tokens in [(64, 512), (1, 8192), (1, 16384), (1, 32768), (64, 8192), (64, 16384), (64, 32768)]:\n",
|
|
143
|
+
"for batch_size, n_tokens in [(64, 512), (1, 8192), (1, 32768)]:\n",
|
|
144
|
+
" for n_pes in [256]:# [64, 256]:\n",
|
|
145
|
+
" spec = Specification.from_yaml(\n",
|
|
146
|
+
" f\"architecture/tpu_like_asplos.arch.yaml\",\n",
|
|
147
|
+
" \"workloads/mha_full.workload.yaml\",\n",
|
|
148
|
+
" \"workloads/mha_full.renames.yaml\",\n",
|
|
149
|
+
" jinja_parse_data={\n",
|
|
150
|
+
" \"BATCH_SIZE\": batch_size,\n",
|
|
151
|
+
" \"N_TOKENS\": n_tokens,\n",
|
|
152
|
+
" \"N_PES\": n_pes,\n",
|
|
153
|
+
" }\n",
|
|
154
|
+
" )\n",
|
|
155
|
+
" spec.mapper.ffm.metrics = Metrics.LATENCY\n",
|
|
156
|
+
" cache_key = (batch_size, n_tokens, n_pes)\n",
|
|
157
|
+
" spec.architecture.nodes[\"LocalBuffer\"].spatial[\"Z\"].fanout = n_pes\n",
|
|
158
|
+
" for parameterization in parameterizations:\n",
|
|
159
|
+
" x, mappings = get_fused_mappings(\n",
|
|
160
|
+
" spec,\n",
|
|
161
|
+
" cache_key=cache_key,\n",
|
|
162
|
+
" parameterization=parameterization,\n",
|
|
163
|
+
" )\n",
|
|
164
|
+
" parameterization2edp.setdefault((batch_size, n_tokens, n_pes), {})[parameterization] = x\n",
|
|
165
|
+
" parameterization2mappings.setdefault((batch_size, n_tokens, n_pes), {})[parameterization] = mappings"
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"cell_type": "code",
|
|
170
|
+
"execution_count": 5,
|
|
171
|
+
"metadata": {},
|
|
172
|
+
"outputs": [
|
|
173
|
+
{
|
|
174
|
+
"name": "stdout",
|
|
175
|
+
"output_type": "stream",
|
|
176
|
+
"text": [
|
|
177
|
+
"Elementwise-Only: {'Batch=64\\nSeq. length=512': np.float64(0.27285390803099696), 'Batch=1\\nSeq. length=8k': np.float64(0.04927433922747447), 'Batch=1\\nSeq. length=32k': np.float64(0.02675507038893531)}\n",
|
|
178
|
+
"FlashAttention: {'Batch=64\\nSeq. length=512': np.float64(0.45709841694467), 'Batch=1\\nSeq. length=8k': np.float64(0.47993180829615223), 'Batch=1\\nSeq. length=32k': np.float64(0.6504716129657209)}\n",
|
|
179
|
+
"Fast & Fusiest: {'Batch=64\\nSeq. length=512': np.float64(1.0), 'Batch=1\\nSeq. length=8k': np.float64(1.0), 'Batch=1\\nSeq. length=32k': np.float64(1.0)}\n"
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"data": {
|
|
184
|
+
"image/png": "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Blib6aQ+JGnHjh0yDEPu7u6Kisq4/uTgwYOt83/88ccMr8+dO1eGYWRYXuB6G2798ssvevDBB1WuXDl5eHjI399flSpVUocOHTRx4kRdunQp034xMTF655131LRpU5UoUUKenp4qX768+vTpo82bN2fax1l79uzR9OnTJV17W+HgwYOzPLdIkSKaO3euypQpo5SUFI0YMSLDOek3kFi4cKHatGmjEiVKyNvbW3Xr1tWkSZOUkpLidI0RERHy9vaWYRiaP39+tue+9tprMgxDlSpVumXW9YTrbNmyRf/973/VsmVLVaxYUV5eXipWrJiaNGmid999V7GxsVn2jY+P18SJE9W0aVMVL15chQsXVunSpVWzZk31799f33//fbbXvnr1qt5//33VqVNHPj4+Klq0qNq2basVK1Y4VXvqkgP9+/dXSEiIWrVqpatXr2Z675QkwzA0YMAASdLx48cz3DvHjh2rtWvXyjAMaz3FmTNnZjgvsz/K2PF96rffftP999+v0qVLy8vLSzVq1NC4ceN05coVh345rdGZDbcWLVqkzp07KyAgQB4eHgoICFDnzp21ePHiLPu44l6IW1tiYqKWLl2qQYMGqWHDhgoMDJSHh4fKlCmje++9V3Pnzs32+15YWJheeOEF1apVSz4+PvL09FRQUJAaNGigF154Qdu2bbPObdOmjW677Tarfdtttzl8DeVmY9HUtVyDg4Nz3NfVnNnsMLsNspKSkvTVV1+pTZs2KlWqlAoXLqySJUuqWrVq6t27t8MSMM6Ml+rYsWMaNmyYatWqJV9fX3l7e6t69ep6/vnnreUbMnPgwAENGjRIt99+u7y9veXl5aXy5curSZMmeuWVV3TgwAGHj/3uu++22unvl2wIhn87lh0AAFzXe++9p1GjRlm/vHl7eysxMVF79uyxQrWffvpJ9erVy3KM119/XePHj5ebm5v8/PwUExOjzZs364EHHtCUKVM0aNAgDRgwQDNnzpS7u7uKFCmiuLg4bdiwQffee69++OEH3X9/xs3K4uPj9dhjj2nhwoXWc/7+/oqKitKGDRu0YcMGffPNN1q+fLmKFy+eaW3Jycl64IEH9MMPP8jd3V3e3t6KiYnRli1btGXLFh08eNBhswpfX18FBATo/PnzSklJkb+/v4oUKZJh3Hr16qlYsWKKjIzUunXr1LVrV4fXV69e7XDcuXPnTF9P+8Pq9YwfP16vv/661fb29pZpmjp69KiOHj2qVatWqWHDhhl+ofnrr7/UpUsXhYWFSZIKFSokb29vhYWFad68eZo/f74mTJigUaNGOV1LWp9//rmka2ujjRkz5rrnlyxZUs8884xef/11bdu2TX/88YcaN26c6bnPPvusJk+eLDc3N/n7+ys+Pl67du3SsGHDtHPnTqc2xJCk4sWL66GHHtLMmTP11Vdf6aGHHsr0vOTkZCtIHjhwoBW2A7nVtGlT69jb21ve3t6KiIjQ1q1btXXrVn3zzTdas2aNypQp49AvJiZGLVu21K5duyRd+2W2aNGiioyM1IULF7R//36tW7dOPXr0yPS6sbGxatWqlbZu3arChQvL09PTemvu2rVr9fXXX+uJJ57Isu4tW7Zo37598vf3t9Y77d+/v9atW6dp06bp+eefz9AnICBA8fHxio6OznStRF9fXyt4jIqK0pUrV+Tl5aWiRR03gkudzZbKju9T77//vv773/9KkooWLaqrV6/qwIEDGjt2rNatW6dVq1ZZb1fOTY1ZuXr1qh577DHNmzdP0rX7ZNGiRXXhwgX99NNP+umnn/Twww9r5syZKly4cJbj2HUvxK1t48aN6tatm9X29/eXl5eXzp8/r5UrV2rlypVavHixvvvuuwwb6+3atUt33323IiIiJF37WcLf399a033nzp2KiIiwwscSJUqoVKlS1h9HSpUq5bAkQIkSJXJcf58+ffTFF19o6tSpGjx4cKY/n92MkpOT1alTJ61atcp6rmjRooqLi9OlS5f0zz//aP78+XryySdzNO6cOXP05JNPKiEhQZLk6ekpNzc3hYaGKjQ0VNOnT9fChQvVoUMHh36rVq1Sly5drH6p6/eHhYUpLCxMW7dulYeHh/UHp9KlSys6Otr6t5F+/eH090/g34aZrwCAbE2bNk3//e9/5e3trQkTJig8PFxxcXG6fPmytm/frrZt2yo8PFxdu3bNcnbWX3/9pQkTJmjChAm6dOmSIiMjFRYWZq0J+PLLL2vs2LGaP3++pkyZoqioKEVHR+uff/5Rw4YNlZycrP/85z+ZztwZNGiQFi5cqEqVKmnOnDmKiopSVFSULl++rB9++EGVKlXSli1bsg0QJk+erLVr12rGjBmKjo5WVFSUTp48qS5dukiS3nzzTR08eNA6/6WX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9u3b65FHHtGyZct08uRJpaSkqESJEgoICFBAQIC1JED6Ge19+/bV888/L8Mw9N133+mBBx5Q6dKlVbVqVT3zzDPasWNHttfO7ddPaGiofv/9d0n/NysqLTc3N/Xr10+S65ceyM/vU0lJSTZXf+3tu9L1d2YvV66cw/npufL7GG4t//zzj2rWrKkRI0Zo/fr1On/+vAoXLqzSpUtb96RU6e9J7733nu6++27Fxsbqww8/VJs2beTv76+GDRvq9ddf16lTp1xW98cffyxJeuCBB1SnTh1J1/7wsGbNGlWqVElbt27V3Xff7fA1tH79eklSmzZtsv0auhG0aNFC7777rjw8PLRixQr17dtXwcHBKl++vAYMGJDl2vhZSb13JiYmZnvvTP05LP27GL7++mvVqVNH58+f1xtvvKEmTZrIz89PLVq00Pvvv88fe4B0CF8BAFlKTk6WdG0jkevNpjVNU8eOHSuQ+r744gun6nN2xq/d0oerqf9NfT4kJES33XabQkNDdfr0aR06dEgnT56UlLPwVZLat2+vo0eP6ptvvlH//v1VtWpVRUVFadmyZerXr5/q1avn8MtP6udQuvaDtTOfx9QwOTk5Ocsf1tO+va9w4cKqWrWqJGnnzp1Ofyx///23NYsi7czb/JC69MCqVausf9crV67U8ePH5e7urgEDBuRrPfj3mjBhgtasWaMiRYroo48+0vHjx3XlyhVdvHjR2ogkdYZqZrPYP/74Y4WGhuqtt95Sx44dVaxYMR06dEiff/65GjZsmOmSL3mVNlCtUqWKwyzd1Mc777wjSVq3bp21NqAr3Ojfp4CbzYABAxQWFqaQkBAtWLBAFy9eVFxcnM6dO6czZ844/AyR/p5UrFgxrV69Whs2bNCIESPUvHlzubu7a8eOHRo/fryqVq3qsrWHU98h0Lx5c4fny5Urp9WrV6tixYratWuXWrVqZc14Tb2X3SybZ7788ss6evSoPvroI3Xv3l1lypRRWFiYZsyYobZt26pXr15O/5El9d551113OXXvTP//ukKFCtq5c6dWrFih5557Tg0aNFBKSoo2btyoESNGqEqVKmzyB6RB+AoAyFLqpiU30tvM07rR60uVGqAePHhQYWFhGcLXtOesXr3aev3222+/7myozPj4+Khfv36aMWOG/vnnH4WFhendd9+Vl5eXNSM2VdoNfnL6eQwJCcnyB/T0G3Olvj3tzz//1NGjR50aP+2uuGk/V/mhdu3aatasmcNs19QNuLp168ZGW7BN6qaCY8aM0bBhw1ShQoUMs6qvt8ZflSpVNGrUKC1fvlwXL17U5s2b1b17d0nSpEmTtHTpUtvqTUpK0jfffOP0+aZpunT2683yfSArZcqUkZTx7dvppb6eej7gCidPnrTWlp47d6569uzp8O4Vybk1R1Nnaf7++++KjIzUDz/8oNq1ays+Pl5PPPFEjteOd0bq7PbM3pVSsWJFrV69WuXKlVNoaKhatmypTz75RJs3b1bVqlXVu3dv2+vJTOos9Ow2ALvevgxBQUEaNmyYFi9erLNnz2r37t3Wmq0LFy7UF1984VQtdtw73dzcdO+992rSpEnavn27Ll26pDlz5qhChQqKiIhQ3759WYoA+P8IXwEAWUqdPbBjx44bckH91Pqy2o3b1VI3G8huTVVJql69ugIDAyVdC1fXrl0rNzc3awap5Dg7NjdLDmQnODhYI0aM0Isvvijp2mzOVI0aNZKHh4ckZVjf1E5PP/20pGufq9S1F7Nz8eJFTZ48WZLUoEEDNW7c2GW1ZSV19uv//vc/nTp1yvr8DBo0KN9rwb9X6iz3evXqZfr6sWPHdOjQIafHc3NzU5MmTbRw4UJVqFBBkuPXfF799NNPOnPmjAoXLqywsDDFxMRk+fjggw8kSTNnznSYZe/svdOZ8wr6+5SzH0tW0q7lmlXoEhkZ6bA2LOAqqfcjKet7Uuo6+s7y8vJS165drT+oXrlyxVq2RPq/ryEp919H0rUNWqVra79mplKlSlqzZo2CgoJ07Ngxa8mWKVOmqFChQrm+bk6kbiKa9vOcVkpKSpbrOmeldu3amjp1qnUvdPZ+n3r+mTNncnzNrPj5+alv377WH63Pnj2rPXv2WK/b9f8auBkRvgIAstSrVy8VK1ZMiYmJGj58eLY/KKWkpCgyMjL/itP/hWB79+697l/64+LibP/re+rmKM583KlB6ueff67w8HDVqVPHYTZJ2pmva9eudXjOWQkJCdm+XqRIEUmOP/z6+Piob9++kqR3331XJ06cyHaM3K7hVadOHWttyBkzZujLL7/M8twrV67o4Ycf1vnz5+Xm5qb3338/V9fMq169eqlkyZI6ffq0+vbtq8TERDbagu2KFi0qSdq1a1emr48cOTLLvtl9zRcqVMj6w0rar/m8Sv2lOnVTLV9f3ywfffr0kZubm06dOuWwU7az905nzivo71M5+T6QmR49esjd3V1XrlzRu+++m+k5b731lhISElS4cGH16NEjt6UC15V6P5IyvyfFxMTozTffzLRvUlKSUlJSshw79WcQyfGelHajubx8fT700EOSpKVLl2Y5279KlSr6+uuvrXaxYsVUrVq1XF8zp1LXol28eHGm96qZM2dmOQs+Nz/jZefuu+9WlSpVJEkvvPDCdX9GTvvz3/XOdfX/a+BmRPgKAMhSsWLFrA0MvvvuO91///3aunWr9cN1SkqK9u/frw8++EC1atXK9xmorVu3ttbefOaZZ/TCCy/oyJEj1usJCQnasmWLRowYoYoVK2a5UUlupe6Mu3Dhwgw76KaXGqRu3bpVUsa30QcFBalatWo6fvy49Za+tDNjnfHuu++qY8eOmjVrlsMP7wkJCZo/f74VYt5///0O/d566y0FBQXpwoULatq0qWbNmqWYmBjr9fPnz+v777/XAw88oIcffjhHNaWVugaldG0mbL9+/bRjxw7rF5D4+HgtWrRIDRs2tGZuvP3227bNAM4pT09PPf7445L+b1MONtqC3e677z5J0ptvvqlFixZZmzodPXpUffv21fz5863ZUundddddeu6557R27VqHjW9Onz6toUOHWjNmO3XqZEut4eHhWr58uaT/CzqyExQUZM2uSg1tpf+7d0ZHR2v+/PlZ9k89b8OGDTpw4ECm5xT09ylnasxOcHCwnn/+eUnSO++8o9dff90KJSIjI/Xaa69Z9+7hw4db76IAXKFGjRrWjPknnnjCYdO+zZs3q02bNln+vBMWFqaqVavqzTff1J9//umwQd3u3butjSx9fHzUunVr67VixYpZSyxNnz491xvbvfjii6pWrZpM01SPHj302muvOaxPe/z4cU2YMEF9+vSRdG15goiICN13333X/RnOLqk/Q+3fv1+DBg2yNiGNjo7WRx99pKeffjrDMg+punfvrieeeEI///yzQ3B56dIlvfnmm9aM3/Q/42XF3d1dU6ZMkbu7u37//Xe1atVKv/32m8OasUeOHNGUKVPUqFEjff7559bzmzZt0p133qmPPvpI+/fvt+63pmlq06ZN1juHypUrpzvvvNPqd/vtt1t/FPz666+Z/YpbCuErAPwLZbUDfdpH6ppe19O/f3998cUX8vDw0M8//6wmTZrI29tbpUqVkpeXl2rWrKmXXnpJBw4cKJBQasqUKRo4cKBM09THH3+sypUry8/PTyVKlJC3t7eaNm2q999/XxcvXrS9vkGDBskwDG3atEmlS5dWUFCQQkJCFBISkuHc9GFrZmuYpg0Za9as6bCjsDNSUlK0YsUKPfbYYypfvry8vb1VsmRJFSlSRL1791ZUVJRq1KihDz/80KFfYGCgfv31V91+++06ffq0HnvsMRUrVkwlS5aUr6+vypQpo549e2rJkiXZzmq5Hh8fH61bt06PPPKIJGn27Nlq2LChPD09VaJECfn4+KhHjx76+++/VaxYMc2YMUMjRozI9fXs8PTTT1v/bthoC67w5ptvKiAgQDExMerRo4eKFCmiYsWKqVKlSpo7d64mTJjg8MtrWpGRkfr000919913y8/PT8WLF5evr6+Cg4P12WefSbo2o+nee++1pdbU5QMKFy5srSl7Pb169ZJ0bVmT8+fPS7o2+yx1HejevXvL39/funemBqnStVmhpUuXVkREhGrUqKHSpUtb523ZssU6ryC/TzlbY3beeustPfTQQ9ayLCVLllSJEiVUsmRJa5bhww8/rDfeeMPW2oH03NzcNHnyZLm7u+vvv/9Ww4YN5ePjIx8fHzVr1kyhoaGaN29elv2PHDmi1157TfXr15eXl5dKliwpT09P1alTR2vXrpWHh4dmzJiRIWBMXZro008/la+vrypUqKCQkBArKHWGj4+Pfv31VzVu3FhJSUl68803Va5cOeu+GBISotGjRys+Pl6vvvqqfv/9dxUpUkR79+5V165ds12H1S7t2rVTv379JF0LH0uVKqXixYurePHiGj58uAYPHqwuXbpk2jc+Pl7Tp09Xp06dVLx4cRUtWlRFixZVyZIl9dprr8k0TfXs2dNa/9XZehYsWCA/Pz9t3bpV7du3l4+Pj3XvrFy5soYMGaLt27dnuHfu2bNHw4cPV82aNeXl5aVSpUrJw8NDzZs31549e+Tv769vv/3WYUkHb29v6+MfMWKEfH19VbFiRYWEhOill17K6acTuKkQvgLAv1BWO9CnfeTkLfhPP/20QkND9dJLL6lOnTry9PRUZGSkfH191bBhQw0dOlSrVq3K06zI3PLw8NDUqVO1adMmPf7446pcubKSk5MVGxurMmXKqE2bNhozZox2796dq82rstOqVSv99NNPat++vYoVK6azZ8/q+PHjmW5eUKlSJWs2ibu7u1q1apXhnMw24MqJQYMG6auvvtLDDz+sO+64Q97e3oqOjlbx4sXVsmVLffzxx9q5c2emm0XVqFFDu3fv1pdffqkOHTqoVKlSio6OlmmaqlKlinr16qWvvvoq21lqzvD29tbs2bO1fft2DR06VHfccYd8fX0VGxurgIAAtWnTRu+++66OHDmi/v375+ladqhSpYrq1q0riY224BoVK1bU9u3b9eSTTyooKEjStTUSO3furF9++UWjRo3Ksu93332ncePGqV27drrtttt09epVJSYmqmLFiurdu7d+++23DH9syYvUjbPat2+f5Wzc9Hr27Ck3NzclJiZq1qxZ1vMLFy7UCy+8oNtvv12JiYnWvTPtjK7ixYtr/fr16tOnj4KDgxUVFWWdlz4oKajvUzmpMSseHh6aN2+eFi5cqI4dO6pkyZKKiYlRyZIl1bFjRy1atEjffvutChcubGvtQGY6d+6s9evX6/7771exYsWUlJSkUqVKacCAAdqxY4f1h5P0goODtXTpUr3wwgtq0qSJAgMDFRsbK3d3d9WsWVPPPPOM9u7dq549e2bo+8orr2jSpElq2LChtZ502ncCOatcuXLauHGjZs2apU6dOikgIEBxcXEqXLiwGjRooFGjRunQoUN688031axZM82cOVOGYej3339Xnz59HNamdpUZM2Zo0qRJqlu3rooUKaKUlBQ1b95c8+fP1yeffJJlv08//VTvvvuuOnXqpKpVq8o0TcXHxysoKEhdu3bV999/rwULFuR4mZnu3bvr0KFDev3119W4cWP5+voqMjLSCs0HDhyoxYsX6+WXX7b6NGrUSPPnz9eQIUPUoEED62dGLy8v1a1bVyNGjND+/fvVsmXLDNebPHmyxo4dq9q1a0uSTpw4oePHj+vChQs5qhu42Rgmc70BFKADBw7o0Ucf1ezZs1W9evWCLgcAHJw5c0bly5dXUlKSfvnlF3Xo0KGgSwIAALgl8bsjblbMfAUAAMjClClTlJSUpCpVqrDRFgAAAIAcI3wFAADIxPbt2/XBBx9IurbRDRttAQAAAMgp94IuAAAA4EYSEhKihIQEa625evXq5WgDCwAAAABIRfgKAACQRuqGaWXLltV9992nd955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LgEAAAAAAAAANxVbwtctW7bo3LlzMgxDhmHoo48+0nPPPWfH0AAAAAAAAABwU3KzY5C///7bOq5RowbBKwAAAAAAAIBbni3h66VLl6zjdu3a2TEkAAAAAAAAANzUbAlfS5QokekxAAAAAAAAANyqbAlfK1asaB1fvHjRjiEBAAAAAAAA4KZmS/japk0bFStWTJK0adMmO4YEAAAAAAAAgJuaLeGrp6enBgwYINM09eeff2rLli12DAsAAAAAAAAANy1bwldJmjBhgmrVqiXTNNW/f39duHDBrqEBAAAAAAAA4KZjW/jq5eWlH3/8UXfccYcOHjyoBg0a6Mcff7RreAAAAAAAAAC4qbjbNdD48eMlSR06dNA///yjkydPqlu3bipfvrxatGih4OBg+fj45GjMMWPG2FUeAAAAAAAAAOQr28LXsWPHyjAMq20YhkzT1IkTJzR37txcjUn4CgAAAAAAAOBmZduyA5kxDMMhkHWWaZouqAYAAAAAAAAA8o9tM18lQlMAAAAAAAAASGVb+JqSkmLXUAAAAAAAAABw03PpsgMAAAAAAAAAcKsifAUAAAAAAAAAFyB8BQAAAAAAAAAXIHwFAAAAAAAAABcgfAUAAAAAAAAAF3AqfP37779dXYdTbpQ6AAAAAAAAAOB6nApf69atqyeffFInTpxwdT2ZOn78uB5//HHVrVu3QK4PAAAAAAAAADnlVPianJysGTNmqGrVqurfv792797t6rokSbt27VK/fv10++23a9asWUpJScmX6wIAAAAAAABAXjkVvlaqVEmmaSoxMVGzZ89WvXr11LRpU02bNk2XLl2ytaBLly5p6tSpuuuuu1S/fn19++23SkxMlGmaqly5sq3XAgAAAAAAAABXcSp83bdvn8aNGydvb2+ZpinTNPXHH39o0KBBKlu2rNq1a6d33nlHW7Zs0dWrV3NUQEJCgjZv3qy3335b7dq1U9myZfX0009r+/bt1rW8vb01fvx47d27N1cfJAAAAAAAAADkN3dnTvLw8NBrr72mp556SuPHj9e0adOUmJgoSUpKStLatWu1du1aSVKhQoVUpUoVVa1aVeXKlVOZMmVUpEgReXh46OrVq7p8+bLOnTunsLAwHTx4UIcOHXJYTsA0TYfrPvXUU3r11VdVtmxZGz9sAAAAAAAAAHAtp8LXVGXLltXnn3+uV155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d+3aNcMvN8mVK1dOjz76qN2hAcgDjh8/rjVr1uitt95Sv379bL1EtHv37lq+fLnTZ646HA5Nnz7dctbM6tWrM1zQH+5DDgLypzVr1ljaI0aMSLPwekvlypU1YsQIs20YhtavX++W+OA55AUAznr77bcty6atXLkyzb7FixfX/v37Myy8JjVy5EhLMTcsLEzr1q3LVKxwHcVX5Cm7du2ytLt06eKhSADANV5erl+MUrp0aXXt2tVs37hxQ3v27LEzLLiAHATkT8lvsHX33Xc7Na5Vq1aW9tmzZ22LCTkDeQGAs8qVK6e6deua7evXr+vy5cup9i1QoECm1mt9+OGHLe3t27e7PAcyh2UHkKdcvHjR0i5evHi27dswDO3bt0+HDh1SaGioYmJiVLZsWdWqVUutW7eWt7d3pudOSEjQpk2bFBQUpLCwMJUvX14BAQFq165dpgo2ucWRI0e0Z88ehYaG6tq1aypTpoyqV6+uNm3ayM/Pz5Z9GIahv/76S0FBQTp37pyKFi2qGjVqqH379ipatGim571w4YI2btyoM2fOKDExUZUrV1ajRo1y5N2M//77b+3du1enTp2Sl5eXKlasqPbt26tixYqeDg1OuO222yztCxcueCgSkIPyFnJQ9sgLOejWGnq3FClSxKlxyfultR4gci/yQt5CXsgeeSEvZFby3xHJ80tW8XeDBxlAHvL+++8bkszHf/7zH7fvMzw83Bg/frxRoUIFy76TPooUKWI8+eSTxunTp12aOz4+3njvvfeMcuXKpTpv+fLljddff924ceOGYRiG0b59e/O19u3bu+HdOm/mzJmWWI8fP+7UuOvXrxvvvPOOERAQkObn6e3tbTz00EPG33//7dScaX0uX375pVGjRo1U9+Hj42M8//zzRmRkpEvv+59//jG6detmFChQINV5mzdvbqxevdowDMM4fvy45bWZM2da5kr+urOP5J/1pEmTLK/fsmHDBuPuu+9Oc55evXoZR48eden9e5In//0n/1kNGTIk2/b99NNPW/a9cOHCbNs3rMhB5KDUkIPyfg565513LLH/73//c2rcl19+6fTv7yFDhpj9qlev7tT8CxcuNAoXLmyOK1WqlLFhwwanxsIe5AXyQmrIC3k/L2RW5cqVzfdbvHhxIyEhwdb5f/75Z8tn+txzz6Xbv3r16mZfZ/6+SUxMNF5++WXLPu68807j1KlTNr2D3IviK/KUefPmWf6jV6pUybhy5Yrb9rdixQqjVKlSTiee4sWLGytWrHBq7sjISKNdu3ZOzdu2bVvjypUruf4Lzs6dO42qVas6/Xl6e3sbs2bNynDe5J9LTEyM0a9fP6f20bx5cyM8PNyp97xkyRLD19c3wzkLFChgvPvuux79gvP2228bBQsWzHCusmXLGnv37nXq/Xtafi2+tmnTxrLv7du3Z9u+YUUOIgelhhyU93PQvn37LHF36tTJqXEdOnQwxxQpUiTd3xeuFl8//vhjS7ElICDACAwMdPYtwSbkBfJCasgLeT8vZMamTZss7/WRRx6xfR+vvvqqZR/vvvtuuv1dKb7GxMQYjzzyiGX+rl27GlevXrXxHeReefeaAORL7du3l8PhkGEYkm6unXXvvffqyy+/VIsWLWzd15w5czR06FDFx8eb2ypXrqy2bduqWrVq8vHx0blz57RhwwZzof2rV6+qe/fuWrFihTp37pzm3AkJCerZs6c2bdpk2d6kSRO1adNGJUqU0KlTp7RixQpduHBBmzdvtty0ITdat26devXqpaioKHNb2bJl1bZtW9WqVUtFihRRaGiotmzZov3790uS4uLiNHToUCUmJmrYsGFO72vkyJFauHChJKlatWrq1KmTKleurJiYGO3YsUMbN240++7YsUNjxozRrFmz0p1z/fr1GjBggOLi4sxtRYsW1X333afatWsrISFBf//9t1avXq2YmBi99NJLKly4cLpzOhwOc9H1xMRE89+1JMti7KmNS8/MmTM1fvx4SVLJkiXVqVMn1apVS15eXgoMDNSKFSsUHR0tSbp06ZIefvhh7dmzR76+vunOm5OcPHlSQ4YM0Y4dO3Tu3DnFx8erTJkyqlKlitq2basePXqke/fQ3OL48ePasmWL2S5ZsqSaNGniwYjyN3JQ7kUOSokc5Lw777xT3bt317JlyyRJa9eu1fTp0/Xss8+mOeaDDz7Qhg0bzPbzzz+vEiVKZDmWxMREPf/885o2bZq5rXnz5lq6dKn8/f2zPD9cQ17IvcgLKZEX3OfMmTP617/+ZbZ9fHz02muv2boPwzD0448/WrZ17NjRlrnDwsLUp08fbd682dw2fPhwzZgxI08vReISDxZ+Abd48MEHUz1K1rhxY2PChAnG8uXLjbCwsCztY+/evZaj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XN9o586dliNQaUnvSHDBggW1dOlSdevWTZs3bza379q1K9W7mLZu3VpfffWVevfuneF+c6r27dtr+/bt6t+/vyUBHTx4MNUvocl5+si6n5+fli1bpmeeeUazZ89Ot2+HDh00b968FDcsyGi90c8//1xHjhyxXFpiGEaKYmJuWpfKHa5fv66tW7dq69atGfZ98MEH9dVXXzl9J9HExESnbihgGIbLNx5I7XK2zNy8IL///D2JHEQO8hRykOc9+eSTkqQxY8YoOjpa0s3f4Rs3bky3+OTn56fp06fb+sdp1apVtWnTJnXp0sU8U2/GjBmKiorSrFmzVLBgQdv2hfSRF8gLnkJeyDliY2PT/L+SXMmSJfXBBx9keLJHan83ZOZztvNGaR07dtTq1avVrVs3XblyRQkJCRo6dKiioqI0atQo2/aTW7HsAPKUfv366eLFi/ruu+/02GOPWS67Sk/16tX18ssvKzAw0KV1H++55x4FBQXp008/Vf369TPs7+/vr0GDBmnJkiWaM2dOun2LFi2q9evX691331W5cuVS7VO2bFm99tpr2rBhg0qUKOF03DlVvXr1tG/fPn333Xe66667Mjw7o1SpUurXr5/mzJnj0XWVbvHz89OsWbO0detWjRo1SnXr1lWxYsXk5+en22+/XQMGDNBvv/2mtWvXyt/fX5cuXbKMz+hnWLFiRe3evVtff/21evfurRo1aqho0aKcxSLplVdeUceOHVW0aNEM+/r4+Kh3795au3atfvnlF6cLr0BGyEG5GzmIHJRVTz75pPbv369Ro0aluBlNcsWLF9czzzyjAwcOaOjQobbH4u/vr40bN6pFixbmth9++EEPPfQQlwVnI/JC7kZeIC9k1syZMzV8+PBU12lOze23366pU6fqyJEjTl1ll1O1atVK69evN39HGIahp59+Os1lTfITh+HKytFALnTx4kUdOXJEwcHBCg8PV1RUlHx9fVW8eHFVrlxZjRo1suUyL0k6f/68tm7dqgsXLigsLEwFChRQsWLFVK1aNdWrV8/pX77JxcfHa9OmTfrnn38UHh6u8uXLKyAgQO3atTMXt5ZuHrW8dXZF+/btc0TSz4qwsDD99ddfOnv2rC5fvizDMFSsWDFVrlxZdevWVZ06dSxrDeU2n3zyiWU9qLNnz2bqLsf4P4mJiTp69KiCgoJ0+vRpRUREKC4uTkWLFlWpUqVUp04dNW3aNM31kwC7kYNyL3IQsiIhIUH79+/XgQMHFBYWpmvXrqlo0aIqXbq07rzzTt1xxx2cgZpPkRdyL/ICMuPy5cs6dOiQjh8/rkuXLik6Olq+vr4qUaKEqlSpombNmql8+fKeDhNuRvEVyEPy2hecvK59+/batGmTJKly5crmJWIAkBuRg3IXchAAdyMv5C7kBcB9cu9hGQDIxVauXGl+uZFuLlIOAEB2IAcBAJIiLwDuRfEVAGyQmJiohQsXOrXQ+ZYtW/Too49atrEIOQAgs8hBAICkyAtAzuLl6QAAIC9ITEzUgw8+qJo1a2rgwIHq2LGjGjZsqLJly0q6udbPzp07NW/ePM2bN89y19snn3xSjRo18lToAIBcjhwEAEiKvADkLKz5CuQhrKvkOfHx8ZYbDDirbdu2WrFihYoUKeKGqAAg+5CDPIccBCAnIi94DnkByFlYdgAAbOBwOOTr6+t0fx8fH40ZM0Zr1qzhyw0AIEvIQQCApMgLQM7CsgMAYIOCBQsqNDRUy5cv1+bNm7V3716FhIQoLCxMMTExKlq0qMqUKaMGDRqoQ4cOGjRokCpWrOjpsAEAeQA5CACQFHkByFlYdgAAAAAAAAAA3IBlBwAAAAAAAADADSi+AgAAAAAAAIAbUHwFAAAAAAAAADeg+AoAAAAAAAAAbkDxFQAAAAAAAADcgOIrAAAAAAAAALgBxVcAAAAAAAAAcAOKrwAAAAAAAADgBhRfAQAAAAAAAMAN/h8luWhuS44A5AAAAABJRU5ErkJggg==",
|
|
185
|
+
"text/plain": [
|
|
186
|
+
"<Figure size 1600x800 with 1 Axes>"
|
|
187
|
+
]
|
|
188
|
+
},
|
|
189
|
+
"metadata": {},
|
|
190
|
+
"output_type": "display_data"
|
|
191
|
+
}
|
|
192
|
+
],
|
|
193
|
+
"source": [
|
|
194
|
+
"results = parameterization2edp\n",
|
|
195
|
+
"\n",
|
|
196
|
+
"import matplotlib.pyplot as plt\n",
|
|
197
|
+
"plt.style.use('default')\n",
|
|
198
|
+
"plt.rcParams.update({'font.size': 28})\n",
|
|
199
|
+
"\n",
|
|
200
|
+
"def plot_default_formatting(ax, grid_axis='both'):\n",
|
|
201
|
+
" ax.tick_params(axis='both', which='major')#, labelsize=20)\n",
|
|
202
|
+
" ax.tick_params(axis='both', which='minor')#, labelsize=20)\n",
|
|
203
|
+
"\n",
|
|
204
|
+
" # Set legend ncols to 5\n",
|
|
205
|
+
" for spine in ax.spines.values():\n",
|
|
206
|
+
" spine.set_edgecolor('black')\n",
|
|
207
|
+
" legend = ax.legend(fontsize=18, ncols=5, loc=\"upper center\", bbox_to_anchor=(0.5, 1.2))\n",
|
|
208
|
+
" legend.get_frame().set_facecolor('white')\n",
|
|
209
|
+
" legend.get_frame().set_edgecolor('black')\n",
|
|
210
|
+
"\n",
|
|
211
|
+
" ax.spines['right'].set_visible(False)\n",
|
|
212
|
+
" ax.spines['top'].set_visible(False)\n",
|
|
213
|
+
" ax.spines['bottom'].set_visible(False)\n",
|
|
214
|
+
" # ax.minorticks_on()\n",
|
|
215
|
+
" # ax.grid(axis=grid_axis, which='major', linestyle='-', linewidth='0.3', color='gray')\n",
|
|
216
|
+
" # ax.grid(axis=grid_axis, which='minor', linestyle='--', linewidth='0.1', color='lightgray')\n",
|
|
217
|
+
"\n",
|
|
218
|
+
"colors = [\n",
|
|
219
|
+
" \"#1f77b4\",\n",
|
|
220
|
+
" \"#ff7f0e\",\n",
|
|
221
|
+
" \"#2ca02c\",\n",
|
|
222
|
+
" \"#d62728\",\n",
|
|
223
|
+
" \"#9467bd\",\n",
|
|
224
|
+
" \"#ff0000\",\n",
|
|
225
|
+
"]\n",
|
|
226
|
+
"\n",
|
|
227
|
+
"def make_bar_chart(\n",
|
|
228
|
+
" data,\n",
|
|
229
|
+
" title,\n",
|
|
230
|
+
" xlabel,\n",
|
|
231
|
+
" ylabel,\n",
|
|
232
|
+
" y_scale,\n",
|
|
233
|
+
" output_file=None,\n",
|
|
234
|
+
" normalize: bool = False,\n",
|
|
235
|
+
" ylim=(None, None),\n",
|
|
236
|
+
" xlim=(None, None),\n",
|
|
237
|
+
"):\n",
|
|
238
|
+
" \"\"\"\n",
|
|
239
|
+
" Create a bar chart from the given data and save it as a PDF.\n",
|
|
240
|
+
" \"\"\"\n",
|
|
241
|
+
" plt.figure(figsize=(16, 8))\n",
|
|
242
|
+
" \n",
|
|
243
|
+
" if isinstance(data, dict) and isinstance(next(iter(data.values())), dict):\n",
|
|
244
|
+
" bar_width = 0.8 / len(data)\n",
|
|
245
|
+
" keys = list(next(iter(data.values())).keys())\n",
|
|
246
|
+
" x = range(len(keys))\n",
|
|
247
|
+
" first = next(iter(data.values()))\n",
|
|
248
|
+
" \n",
|
|
249
|
+
" for i, (label, values) in enumerate(data.items()):\n",
|
|
250
|
+
" bar_positions = [pos + i * bar_width for pos in x]\n",
|
|
251
|
+
" to_plot = values\n",
|
|
252
|
+
" if normalize:\n",
|
|
253
|
+
" to_plot = {k: v / first[k] for k, v in values.items()}\n",
|
|
254
|
+
" bars = plt.bar(bar_positions, to_plot.values(), width=bar_width, label=label, color=colors[i])\n",
|
|
255
|
+
" plt.xticks([pos + (len(data) - 1) * bar_width / 2 for pos in x], keys)\n",
|
|
256
|
+
" # plt.legend(loc='upper right', fontsize=10)\n",
|
|
257
|
+
" plt.legend(fontsize=10, ncol=len(data), loc='upper center', bbox_to_anchor=(0.5, 0.75))\n",
|
|
258
|
+
" else:\n",
|
|
259
|
+
" keys = list(data.keys())\n",
|
|
260
|
+
" bars = plt.bar(keys, data.values())\n",
|
|
261
|
+
" \n",
|
|
262
|
+
"\n",
|
|
263
|
+
" # Set logarithmic scale for Y-axis if specified\n",
|
|
264
|
+
" if y_scale == 'log':\n",
|
|
265
|
+
" plt.yscale('log')\n",
|
|
266
|
+
"\n",
|
|
267
|
+
" # Add labels and title\n",
|
|
268
|
+
" plt.title(title)\n",
|
|
269
|
+
" plt.xlabel(xlabel)\n",
|
|
270
|
+
" plt.ylabel(ylabel)\n",
|
|
271
|
+
" plt.ylim(ylim)\n",
|
|
272
|
+
" plt.xlim(xlim)\n",
|
|
273
|
+
"\n",
|
|
274
|
+
" # Rotate X-axis labels vertically\n",
|
|
275
|
+
" # plt.xticks(rotation=90)\n",
|
|
276
|
+
" \n",
|
|
277
|
+
" plot_default_formatting(plt.gca(), grid_axis='y')\n",
|
|
278
|
+
" \n",
|
|
279
|
+
" if output_file is not None:\n",
|
|
280
|
+
" with open(output_file, 'wb') as f:\n",
|
|
281
|
+
" plt.savefig(f, format='pdf', bbox_inches='tight')\n",
|
|
282
|
+
"\n",
|
|
283
|
+
" # Show the plot\n",
|
|
284
|
+
" plt.show()\n",
|
|
285
|
+
"\n",
|
|
286
|
+
"entries = {}\n",
|
|
287
|
+
"\n",
|
|
288
|
+
"name_changes = {\n",
|
|
289
|
+
" \"Unfused\": \"Elementwise-Only\",\n",
|
|
290
|
+
" \"FlashAttention A\": \"FlashAttention\",\n",
|
|
291
|
+
" \"Fixed-Dataflow\": \"FLAT\",\n",
|
|
292
|
+
" \"FlashAttention B\": \"FlashAttention B\",\n",
|
|
293
|
+
" \"FFM\": \"Fast & Fusiest\",\n",
|
|
294
|
+
" # (64, 512, 64): \"Big Batch\\n64 Cores\",\n",
|
|
295
|
+
" (64, 512, 256): \"Batch=64\\nSeq. length=512\",#\\n256 Cores\",\n",
|
|
296
|
+
" # (1, 16384, 64): \"Big Seq\\n64 Cores\",\n",
|
|
297
|
+
" (1, 8192, 256): \"Batch=1\\nSeq. length=8k\",#\\n256 Cores\",\n",
|
|
298
|
+
" # (1, 32768, 256): \"Bigger Seq\\n256 Cores\",\n",
|
|
299
|
+
" (1, 32768, 256): \"Batch=1\\nSeq. length=32k\",#\\n256 Cores\",\n",
|
|
300
|
+
"}\n",
|
|
301
|
+
"\n",
|
|
302
|
+
"for k, v in results.items():\n",
|
|
303
|
+
" if k not in name_changes:\n",
|
|
304
|
+
" continue\n",
|
|
305
|
+
" k = name_changes.get(k, k)\n",
|
|
306
|
+
" entries[k] = {name_changes.get(k2, k2): 1/v[k2] if v[k2] else 0 for k2 in v}\n",
|
|
307
|
+
" max_val = max(entries[k].values())\n",
|
|
308
|
+
" for k2, v2 in entries[k].items():\n",
|
|
309
|
+
" entries[k][k2] = v2 / max_val if max_val else 0\n",
|
|
310
|
+
"\n",
|
|
311
|
+
"entries={k: v for k, v in sorted(entries.items(), key=lambda x: list(name_changes.values()).index(x[0]))}\n",
|
|
312
|
+
"\n",
|
|
313
|
+
"# Transpose everything\n",
|
|
314
|
+
"entries2 = {}\n",
|
|
315
|
+
"for k, v in entries.items():\n",
|
|
316
|
+
" for k2, v2 in v.items():\n",
|
|
317
|
+
" entries2.setdefault(k2, {})[k] = v2\n",
|
|
318
|
+
"entries = entries2\n",
|
|
319
|
+
"\n",
|
|
320
|
+
"del entries2['FlashAttention B']\n",
|
|
321
|
+
"del entries2['FLAT']\n",
|
|
322
|
+
"\n",
|
|
323
|
+
"# Print as a table\n",
|
|
324
|
+
"for name, e in entries2.items():\n",
|
|
325
|
+
" print(f\"{name}: {e}\")\n",
|
|
326
|
+
" \n",
|
|
327
|
+
"make_bar_chart(entries, title=None, xlabel=None, ylabel=\"Throughput (normalized)\", y_scale='linear', output_file=\"mapsapce_compare.pdf\", normalize=False, ylim=(0, 1), xlim=(None, None))"
|
|
328
|
+
]
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"cell_type": "code",
|
|
332
|
+
"execution_count": null,
|
|
333
|
+
"metadata": {},
|
|
334
|
+
"outputs": [],
|
|
335
|
+
"source": []
|
|
336
|
+
}
|
|
337
|
+
],
|
|
338
|
+
"metadata": {
|
|
339
|
+
"kernelspec": {
|
|
340
|
+
"display_name": "Python 3 (ipykernel)",
|
|
341
|
+
"language": "python",
|
|
342
|
+
"name": "python3"
|
|
343
|
+
},
|
|
344
|
+
"language_info": {
|
|
345
|
+
"codemirror_mode": {
|
|
346
|
+
"name": "ipython",
|
|
347
|
+
"version": 3
|
|
348
|
+
},
|
|
349
|
+
"file_extension": ".py",
|
|
350
|
+
"mimetype": "text/x-python",
|
|
351
|
+
"name": "python",
|
|
352
|
+
"nbconvert_exporter": "python",
|
|
353
|
+
"pygments_lexer": "ipython3",
|
|
354
|
+
"version": "3.12.3"
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
"nbformat": 4,
|
|
358
|
+
"nbformat_minor": 4
|
|
359
|
+
}
|