Skip to content

Commit 307196d

Browse files
committed
[network] Tested distributed buffers
1 parent 4b3fcab commit 307196d

5 files changed

Lines changed: 177 additions & 45 deletions

File tree

accelforge/frontend/arch/_flattened_arch.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
from typing import TypeVar
2+
3+
4+
_FIND_SENTINEL = object()
5+
6+
D = TypeVar("D")
7+
T = TypeVar("T")
8+
9+
110
class FlattenedArch:
211
"""
312
A flattened arch is an architecture spec that has been
@@ -51,3 +60,27 @@ def is_above(self, name_a: str, name_b: str):
5160
idx_a = self.index(name_a)
5261
idx_b = self.index(name_b)
5362
return idx_a < idx_b
63+
64+
def find_first_of_type_between(
65+
self, node_type: T, name_lower: str, name_upper: str, default: D = _FIND_SENTINEL
66+
) -> T | D:
67+
"""
68+
Returns the first node with type `node_type` above `name_lower` and under `name_upper`.
69+
70+
If `name` does not exist, raises an error.
71+
72+
If no node of `node_type` is found, either `default` is
73+
returned (if provided) or raises an error.
74+
"""
75+
upper_idx = self.index(name_upper)
76+
lower_idx = self.index(name_lower)
77+
78+
for i, node in enumerate(self.nodes):
79+
if not isinstance(node, node_type) or i <= upper_idx or i >= lower_idx:
80+
continue
81+
else:
82+
return node
83+
if default is not _FIND_SENTINEL:
84+
return default
85+
else:
86+
raise ValueError(f"node with type {node_type} between {name_upper} and {name_lower} not found")

accelforge/model/_looptree/reuse/symbolic/_symbolic.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -903,19 +903,21 @@ def analyze_reservation(node_idx, current_shape, info: AnalysisInfo):
903903
child_result.buffet_stats[buffet] = stats
904904

905905
# Reservation nodes are the first to produce stats for a network
906-
network_node = info.job.spec_one_einsum.arch.find_first_of_type_above(
907-
NetworkSpec, buffet.level, default=None
908-
)
909-
if network_node is not None:
910-
network = Network(
911-
tensor,
912-
einsum_name,
913-
info.data_movement_connections.get_src(buffet),
914-
buffet,
915-
component=network_node.name if network_node else network_node,
906+
src = info.data_movement_connections.get_src(buffet)
907+
if src is not None:
908+
network_node = info.job.flattened_arch.find_first_of_type_between(
909+
NetworkSpec, buffet.level, src.level, default=None
916910
)
917-
assert network not in child_result.network_stats
918-
child_result.network_stats[network] = NetworkStats()
911+
if network_node is not None:
912+
network = Network(
913+
tensor,
914+
einsum_name,
915+
src,
916+
buffet,
917+
component=network_node.name if network_node else network_node,
918+
)
919+
assert network not in child_result.network_stats
920+
child_result.network_stats[network] = NetworkStats()
919921

920922
fanout_key = (node.resource, einsum_name)
921923
if fanout_key not in child_result.fanout:
@@ -965,18 +967,20 @@ def analyze_compute(
965967
stats.max_occupancy = 1
966968
result_accumulator.buffet_stats[buffet] = stats
967969

968-
network_node = info.job.spec_one_einsum.arch.find_first_of_type_above(
969-
NetworkSpec, node.component, default=None
970-
)
971-
if network_node is not None:
972-
network = Network(
973-
tensor,
974-
info.job.einsum_name,
975-
info.data_movement_connections.get_src(buffet),
976-
buffet,
977-
component=network_node.name if network_node else network_node,
970+
src = info.data_movement_connections.get_src(buffet)
971+
if src is not None:
972+
network_node = info.job.flattened_arch.find_first_of_type_between(
973+
NetworkSpec, node.component, src.level, default=None
978974
)
979-
result_accumulator.network_stats[network] = NetworkStats()
975+
if network_node is not None:
976+
network = Network(
977+
tensor,
978+
info.job.einsum_name,
979+
src,
980+
buffet,
981+
component=network_node.name if network_node else network_node,
982+
)
983+
result_accumulator.network_stats[network] = NetworkStats()
980984

981985
return result_accumulator
982986

tests/input_files/networked/flat.yaml

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
{% set N_ROW_BUFFER = N_ROW_BUFFER | default(4) %}
2-
{% set N_COL_BUFFER = N_COL_BUFFER | default(4) %}
31
arch:
42
nodes:
53
- !Memory
@@ -12,29 +10,12 @@ arch:
1210
- {name: read, energy: 100, latency: 0}
1311
- {name: write, energy: 100, latency: 0}
1412

15-
- !Network
16-
name: NoC
17-
area: 0
18-
leak_power: 0
19-
actions:
20-
- {name: hops, energy: 1, latency: 0}
21-
2213
- !Array
2314
name: Array
2415
spatial:
2516
- {name: X, fanout: 4}
2617
- {name: Y, fanout: 4}
2718
nodes:
28-
- !Memory
29-
name: GlobalBuffer
30-
size: inf
31-
area: 0
32-
leak_power: 0
33-
tensors: {keep: ~MainMemory, may_keep: All}
34-
actions:
35-
- {name: read, energy: 10, latency: 0}
36-
- {name: write, energy: 10, latency: 0}
37-
3819
- !Memory
3920
name: RowBuffer
4021
size: inf
@@ -45,7 +26,7 @@ arch:
4526
- {name: read, energy: 5, latency: 0}
4627
- {name: write, energy: 5, latency: 0}
4728
spatial:
48-
- {name: X, fanout: {{N_ROW_BUFFER}}}
29+
- {name: X, fanout: 4}
4930

5031
- !Memory
5132
name: ColumnBuffer
@@ -57,7 +38,7 @@ arch:
5738
- {name: read, energy: 5, latency: 0}
5839
- {name: write, energy: 5, latency: 0}
5940
spatial:
60-
- {name: Y, fanout: {{N_COL_BUFFER}}}
41+
- {name: Y, fanout: 4}
6142

6243
- !Memory
6344
name: DistributedBuffer
@@ -72,6 +53,14 @@ arch:
7253
- {name: X, fanout: 2}
7354
- {name: Y, fanout: 2}
7455

56+
- !Network
57+
name: NoC
58+
area: 0
59+
leak_power: 0
60+
actions:
61+
- {name: hops, energy: 1, latency: 0}
62+
63+
7564
- !Memory
7665
name: Scratchpad
7766
size: inf
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
mapping:
2+
nodes:
3+
- !Storage
4+
component: MainMemory
5+
tensors: [T0, T1, W0]
6+
- !Storage
7+
component: DistributedBuffer
8+
tensors: [W0]
9+
- !Temporal
10+
rank_variable: m
11+
tile_shape: {{ M_TILE }}
12+
- !Storage
13+
component: RowBuffer
14+
tensors: [T0]
15+
- !Storage
16+
component: ColumnBuffer
17+
tensors: [T1]
18+
- !Spatial
19+
rank_variable: n0
20+
tile_shape: {{ MAC_TILE }}
21+
component: Array
22+
name: X
23+
- !Spatial
24+
rank_variable: n1
25+
tile_shape: {{ MAC_TILE }}
26+
component: Array
27+
name: Y
28+
- !Storage
29+
component: Scratchpad
30+
tensors: [T0, T1, W0]
31+
- !Temporal
32+
rank_variable: m
33+
tile_shape: 1
34+
- !Temporal
35+
rank_variable: n0
36+
tile_shape: 1
37+
- !Temporal
38+
rank_variable: n1
39+
tile_shape: 1
40+
- !Compute
41+
einsum: Matmul0
42+
component: MAC

tests/test_network.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ def test_flat(self):
3333
{n.name for n in spec.arch.get_nodes_of_type(af.spec.Leaf)},
3434
{
3535
"MainMemory",
36-
"GlobalBuffer",
3736
"NoC",
3837
"RowBuffer",
3938
"ColumnBuffer",
@@ -226,6 +225,71 @@ def test_hierarchical(self):
226225
* BITS_PER_VALUE,
227226
)
228227

228+
def test_flat(self):
229+
M = 8
230+
KN = 8
231+
MAC_TILE = 2
232+
M_TILE = 4
233+
BITS_PER_VALUE = 8
234+
235+
spec = af.Spec.from_yaml(
236+
af.examples.workloads.matmuls,
237+
INPUT_FILES_DIR / "flat.yaml",
238+
INPUT_FILES_DIR / "one_matmul_to_flat.yaml",
239+
jinja_parse_data={
240+
"N_EINSUMS": 1,
241+
"M": 8,
242+
"KN": 8,
243+
"MAC_TILE": MAC_TILE,
244+
"M_TILE": M_TILE,
245+
},
246+
)
247+
result = spec.evaluate_mapping()
248+
self.assertEqual(
249+
result.data['Matmul0<SEP>action<SEP>NoC<SEP>T0<SEP>hops'].iloc[0],
250+
(
251+
M / M_TILE
252+
*
253+
(KN / MAC_TILE) * (KN / MAC_TILE - 1) # num rows * multicast_hops
254+
*
255+
M_TILE * MAC_TILE # tile shape
256+
*
257+
BITS_PER_VALUE
258+
)
259+
)
260+
self.assertEqual(
261+
result.data['Matmul0<SEP>action<SEP>NoC<SEP>T1<SEP>hops'].iloc[0],
262+
(
263+
M / M_TILE
264+
*
265+
(KN / MAC_TILE) * (KN / MAC_TILE - 1) # num rows * multicast_hops
266+
*
267+
M_TILE * MAC_TILE # tile shape
268+
*
269+
BITS_PER_VALUE
270+
)
271+
)
272+
self.assertEqual(
273+
result.data['Matmul0<SEP>action<SEP>NoC<SEP>W0<SEP>hops'].iloc[0],
274+
(
275+
M / M_TILE
276+
*
277+
(
278+
4 # a 2x2 grid of physical buffers
279+
*
280+
(
281+
sum(i for i in range(2)) * MAC_TILE # unicast along row * tile shape
282+
+
283+
2 * sum(i for i in range(2)) # num cols * unicast down col
284+
)
285+
)
286+
*
287+
MAC_TILE * MAC_TILE # tile shape
288+
*
289+
BITS_PER_VALUE
290+
)
291+
)
292+
229293

230294
class TestMapper(TestCase):
231295
def test_hierarchical(self):

0 commit comments

Comments
 (0)