Skip to content

Commit 57423ea

Browse files
committed
[model] Classes to hold network stats + cleanup
1 parent 90c95dd commit 57423ea

3 files changed

Lines changed: 109 additions & 34 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from accelforge.frontend.mapping import (
2+
Mapping,
3+
)
4+
5+
from accelforge.frontend.mapping import (
6+
Mapping,
7+
TensorHolder,
8+
)
9+
from accelforge.frontend.workload import (
10+
TensorName,
11+
)
12+
from accelforge.model._looptree.types import Buffet, Compute
13+
14+
15+
class DataMovementConnections:
16+
"""
17+
For querying connection between Buffet or Compute
18+
(e.g., which Buffet supplies this Compute).
19+
"""
20+
def __init__(self):
21+
self.src_to_dst = {}
22+
self.dst_to_src = {}
23+
24+
def get_src(self, dst: Buffet | Compute) -> Buffet | None:
25+
return self.dst_to_src[dst]
26+
27+
def get_dst(self, src: TensorHolder) -> Buffet | Compute:
28+
return self.src_to_dst[src]
29+
30+
@classmethod
31+
def from_pmapping(cls, pmapping):
32+
einsum_name = pmapping[-1].einsum
33+
src_to_dst = {}
34+
dst_to_src = {}
35+
tensor_to_last_src = {}
36+
for node in pmapping:
37+
if isinstance(node, TensorHolder):
38+
for tensor in node.tensors:
39+
buffet = Buffet(tensor, einsum_name, node.component)
40+
if tensor in tensor_to_last_src:
41+
src = tensor_to_last_src[tensor]
42+
else:
43+
src = None
44+
tensor_to_last_src[tensor] = buffet
45+
dst_to_src[buffet] = src
46+
src_to_dst[src] = buffet
47+
src_to_dst[buffet] = None
48+
result = DataMovementConnections()
49+
result.src_to_dst = src_to_dst
50+
result.dst_to_src = dst_to_src
51+
return result
52+
53+
54+
def get_tensor_to_backer_id(mapping: Mapping):
55+
tensor_to_ids: dict[TensorName, set[int]] = {}
56+
for node in mapping:
57+
if isinstance(node, TensorHolder):
58+
for tensor in node.tensors:
59+
if tensor in tensor_to_ids:
60+
continue
61+
tensor_to_ids[tensor] = id(node)
62+
return tensor_to_ids
63+

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

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
import copy
22
from dataclasses import dataclass, field
3-
import itertools
43
from accelforge.frontend.mapping import (
54
Compute,
65
Mapping,
7-
Nested,
8-
Pipeline,
96
Toll,
107
Reservation,
11-
Sequential,
128
Spatial,
13-
Split,
149
Storage,
1510
Temporal,
1611
)
@@ -33,9 +28,7 @@
3328
from accelforge.frontend.workload import (
3429
Workload,
3530
TensorName,
36-
isl_expression_has_variable,
3731
)
38-
from accelforge.frontend._workload_isl._isl import get_rank_variable_bounds
3932
from accelforge.frontend._workload_isl._symbolic import (
4033
get_projection_expr,
4134
get_rank_variable_relevancy,
@@ -45,7 +38,11 @@
4538
PartiallyRelevant,
4639
)
4740

48-
from accelforge.model._looptree.types import Buffet
41+
from accelforge.model._looptree.types import Buffet, Compute, Network
42+
from accelforge.model._looptree.reuse.symbolic.mapping_utils import (
43+
DataMovementConnections,
44+
get_tensor_to_backer_id
45+
)
4946

5047
from accelforge.mapper.FFM._make_pmappings.pmapper_job import Job
5148
from accelforge.util._sympy.broadcast_max import Min, Max
@@ -59,12 +56,6 @@
5956
PRINT_FORMULAS = False
6057

6158

62-
@dataclass(eq=True, frozen=True)
63-
class Compute:
64-
einsum: str
65-
level: str
66-
67-
6859
class Uninitialized:
6960
def __init__(self):
7061
pass
@@ -106,6 +97,12 @@ def max_dict(a: dict[Any, Any], b: dict[Any, Any]) -> dict[Any, Any]:
10697
return new
10798

10899

100+
@dataclass
101+
class NetworkStats:
102+
buffet_to_total_hops: Any
103+
buffet_to_max_hops: Any
104+
105+
109106
@dataclass
110107
class BuffetStats:
111108
total_reads_to_parent: Any = field(default=0)
@@ -240,11 +237,11 @@ def net_max_per_unit_write_actions(self) -> Any:
240237
- self.min_per_unit_skipped_first_write_actions
241238
)
242239

243-
244-
def blank_buffet_stats() -> BuffetStats:
245-
stats = BuffetStats()
246-
stats.n_loops_above = None # Inherit from whoever is added to this
247-
return stats
240+
@classmethod
241+
def blank(cls):
242+
stats = cls()
243+
stats.n_loops_above = None # Inherit from whoever is added to this
244+
return stats
248245

249246

250247
@dataclass
@@ -310,6 +307,8 @@ class SymbolicAnalysisOutput:
310307

311308
buffet_stats: dict[Buffet, BuffetStats] = field(default_factory=dict)
312309

310+
network_stats: dict[Network, NetworkStats] = field(default_factory=dict)
311+
313312
# Mapping [level, einsum] to the fanout
314313
fanout: dict[(Buffet, str), int] = field(default_factory=dict)
315314

@@ -357,7 +356,7 @@ def get_child_buffet_stats(self, buffet: Buffet) -> BuffetStats:
357356
def sum_buffet_stats_per_level(self) -> dict[str, BuffetStats]:
358357
result: dict[str, BuffetStats] = {}
359358
for buffet, stats in self.buffet_stats.items():
360-
result.setdefault(buffet.level, blank_buffet_stats())
359+
result.setdefault(buffet.level, BuffetStats.blank())
361360
result[buffet.level] += stats
362361
return result
363362

@@ -396,6 +395,8 @@ class AnalysisInfo:
396395

397396
tensor_to_reservation_backer_id: dict[TensorName, int] = field(default_factory=dict)
398397

398+
data_movement_connections: DataMovementConnections = None
399+
399400
# We track first latency for these nodes (should be Temporal)
400401
last_temporal_node_idx: int = None
401402
"""
@@ -517,7 +518,7 @@ def analyze_reuse_and_add_reservations_to_mapping(
517518
- *
518519
- Compute
519520
520-
A loop spatial-for (Reg) k in [0..K) would affect the register at the point of the
521+
A loop 'spatial-for (Reg) k in [0..K)' would affect the register at the point of the
521522
first asterisk, but the global buffer at the point of the second asterisk.
522523
523524
To handle this, we make a separate mapping for each tensor, analyze each, and
@@ -555,6 +556,7 @@ def analyze_reuse_and_add_reservations_to_mapping(
555556
tensor_to_backer_id=tensor_to_backer_id,
556557
is_copy_operation=is_copy_operation,
557558
job=job,
559+
src_to_dst_movement=DataMovementConnections.from_pmapping(cur_mapping.nodes),
558560
)
559561
cur_result = analyze_node(0, job.rank_variable_bounds, info)
560562
if result is None:
@@ -589,17 +591,6 @@ def analyze_reuse_and_add_reservations_to_mapping(
589591
return result
590592

591593

592-
def get_tensor_to_backer_id(mapping: Mapping):
593-
tensor_to_ids: dict[TensorName, set[int]] = {}
594-
for node in mapping:
595-
if isinstance(node, TensorHolder):
596-
for tensor in node.tensors:
597-
if tensor in tensor_to_ids:
598-
continue
599-
tensor_to_ids[tensor] = id(node)
600-
return tensor_to_ids
601-
602-
603594
class ReservationAnalysisTracker:
604595
def __init__(self, buffet, node):
605596
self.buffet: Buffet = buffet
@@ -811,7 +802,7 @@ def handle_repeated_value(repeated_shape):
811802
relevancy = info.tensor_to_relevancy[buffet.tensor][node.rank_variable]
812803
is_fully_relevant = isinstance(relevancy, Relevant)
813804
accumulated_stats = accumulated_buffet_stats.setdefault(
814-
buffet, blank_buffet_stats()
805+
buffet, BuffetStats.blank()
815806
)
816807
accumulated_stats += stats.repeat_temporal(
817808
shape_repeats, is_fully_relevant=is_fully_relevant
@@ -882,7 +873,7 @@ def handle_repeated_value(repeated_shape):
882873
for i, (buffet, buffet_stats) in enumerate(child_stats):
883874
stats = buffet_stats
884875
accumulated_stats = accumulated_buffet_stats.setdefault(
885-
buffet, blank_buffet_stats()
876+
buffet, BuffetStats.blank()
886877
)
887878
relevancy = info.tensor_to_relevancy[buffet.tensor][rank_var]
888879

accelforge/model/_looptree/types.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,24 @@ class Buffet:
2424
"An einsum operating on the tensor."
2525
level: ComponentName
2626
"The abstract hardware level the buffet resides in."
27+
28+
29+
@dataclass(eq=True, frozen=True)
30+
class Compute:
31+
einsum: str
32+
level: str
33+
34+
35+
@dataclass(eq=True, frozen=True)
36+
class Network:
37+
"""
38+
A logical network that delivers a tensor.
39+
"""
40+
tensor: TensorName
41+
"The tensor held by the buffet."
42+
einsum: EinsumName
43+
"An einsum operating on the tensor."
44+
source: ComponentName
45+
"The source of data."
46+
destination: ComponentName
47+
"The destination of data."

0 commit comments

Comments
 (0)