|
1 | 1 | import copy |
2 | 2 | from dataclasses import dataclass, field |
3 | | -import itertools |
4 | 3 | from accelforge.frontend.mapping import ( |
5 | 4 | Compute, |
6 | 5 | Mapping, |
7 | | - Nested, |
8 | | - Pipeline, |
9 | 6 | Toll, |
10 | 7 | Reservation, |
11 | | - Sequential, |
12 | 8 | Spatial, |
13 | | - Split, |
14 | 9 | Storage, |
15 | 10 | Temporal, |
16 | 11 | ) |
|
33 | 28 | from accelforge.frontend.workload import ( |
34 | 29 | Workload, |
35 | 30 | TensorName, |
36 | | - isl_expression_has_variable, |
37 | 31 | ) |
38 | | -from accelforge.frontend._workload_isl._isl import get_rank_variable_bounds |
39 | 32 | from accelforge.frontend._workload_isl._symbolic import ( |
40 | 33 | get_projection_expr, |
41 | 34 | get_rank_variable_relevancy, |
|
45 | 38 | PartiallyRelevant, |
46 | 39 | ) |
47 | 40 |
|
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 | +) |
49 | 46 |
|
50 | 47 | from accelforge.mapper.FFM._make_pmappings.pmapper_job import Job |
51 | 48 | from accelforge.util._sympy.broadcast_max import Min, Max |
|
59 | 56 | PRINT_FORMULAS = False |
60 | 57 |
|
61 | 58 |
|
62 | | -@dataclass(eq=True, frozen=True) |
63 | | -class Compute: |
64 | | - einsum: str |
65 | | - level: str |
66 | | - |
67 | | - |
68 | 59 | class Uninitialized: |
69 | 60 | def __init__(self): |
70 | 61 | pass |
@@ -106,6 +97,12 @@ def max_dict(a: dict[Any, Any], b: dict[Any, Any]) -> dict[Any, Any]: |
106 | 97 | return new |
107 | 98 |
|
108 | 99 |
|
| 100 | +@dataclass |
| 101 | +class NetworkStats: |
| 102 | + buffet_to_total_hops: Any |
| 103 | + buffet_to_max_hops: Any |
| 104 | + |
| 105 | + |
109 | 106 | @dataclass |
110 | 107 | class BuffetStats: |
111 | 108 | total_reads_to_parent: Any = field(default=0) |
@@ -240,11 +237,11 @@ def net_max_per_unit_write_actions(self) -> Any: |
240 | 237 | - self.min_per_unit_skipped_first_write_actions |
241 | 238 | ) |
242 | 239 |
|
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 |
248 | 245 |
|
249 | 246 |
|
250 | 247 | @dataclass |
@@ -310,6 +307,8 @@ class SymbolicAnalysisOutput: |
310 | 307 |
|
311 | 308 | buffet_stats: dict[Buffet, BuffetStats] = field(default_factory=dict) |
312 | 309 |
|
| 310 | + network_stats: dict[Network, NetworkStats] = field(default_factory=dict) |
| 311 | + |
313 | 312 | # Mapping [level, einsum] to the fanout |
314 | 313 | fanout: dict[(Buffet, str), int] = field(default_factory=dict) |
315 | 314 |
|
@@ -357,7 +356,7 @@ def get_child_buffet_stats(self, buffet: Buffet) -> BuffetStats: |
357 | 356 | def sum_buffet_stats_per_level(self) -> dict[str, BuffetStats]: |
358 | 357 | result: dict[str, BuffetStats] = {} |
359 | 358 | for buffet, stats in self.buffet_stats.items(): |
360 | | - result.setdefault(buffet.level, blank_buffet_stats()) |
| 359 | + result.setdefault(buffet.level, BuffetStats.blank()) |
361 | 360 | result[buffet.level] += stats |
362 | 361 | return result |
363 | 362 |
|
@@ -396,6 +395,8 @@ class AnalysisInfo: |
396 | 395 |
|
397 | 396 | tensor_to_reservation_backer_id: dict[TensorName, int] = field(default_factory=dict) |
398 | 397 |
|
| 398 | + data_movement_connections: DataMovementConnections = None |
| 399 | + |
399 | 400 | # We track first latency for these nodes (should be Temporal) |
400 | 401 | last_temporal_node_idx: int = None |
401 | 402 | """ |
@@ -517,7 +518,7 @@ def analyze_reuse_and_add_reservations_to_mapping( |
517 | 518 | - * |
518 | 519 | - Compute |
519 | 520 |
|
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 |
521 | 522 | first asterisk, but the global buffer at the point of the second asterisk. |
522 | 523 |
|
523 | 524 | 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( |
555 | 556 | tensor_to_backer_id=tensor_to_backer_id, |
556 | 557 | is_copy_operation=is_copy_operation, |
557 | 558 | job=job, |
| 559 | + src_to_dst_movement=DataMovementConnections.from_pmapping(cur_mapping.nodes), |
558 | 560 | ) |
559 | 561 | cur_result = analyze_node(0, job.rank_variable_bounds, info) |
560 | 562 | if result is None: |
@@ -589,17 +591,6 @@ def analyze_reuse_and_add_reservations_to_mapping( |
589 | 591 | return result |
590 | 592 |
|
591 | 593 |
|
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 | | - |
603 | 594 | class ReservationAnalysisTracker: |
604 | 595 | def __init__(self, buffet, node): |
605 | 596 | self.buffet: Buffet = buffet |
@@ -811,7 +802,7 @@ def handle_repeated_value(repeated_shape): |
811 | 802 | relevancy = info.tensor_to_relevancy[buffet.tensor][node.rank_variable] |
812 | 803 | is_fully_relevant = isinstance(relevancy, Relevant) |
813 | 804 | accumulated_stats = accumulated_buffet_stats.setdefault( |
814 | | - buffet, blank_buffet_stats() |
| 805 | + buffet, BuffetStats.blank() |
815 | 806 | ) |
816 | 807 | accumulated_stats += stats.repeat_temporal( |
817 | 808 | shape_repeats, is_fully_relevant=is_fully_relevant |
@@ -882,7 +873,7 @@ def handle_repeated_value(repeated_shape): |
882 | 873 | for i, (buffet, buffet_stats) in enumerate(child_stats): |
883 | 874 | stats = buffet_stats |
884 | 875 | accumulated_stats = accumulated_buffet_stats.setdefault( |
885 | | - buffet, blank_buffet_stats() |
| 876 | + buffet, BuffetStats.blank() |
886 | 877 | ) |
887 | 878 | relevancy = info.tensor_to_relevancy[buffet.tensor][rank_var] |
888 | 879 |
|
|
0 commit comments