Skip to content

Commit 64efed3

Browse files
Run black + EDP mapper metric
1 parent 8db8810 commit 64efed3

11 files changed

Lines changed: 80 additions & 81 deletions

File tree

accelforge/frontend/mapper/metrics.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,33 @@ class Metrics(Flag):
3737
Memory usage broken down by tensor and Einsum.
3838
"""
3939

40+
ENERGY_DELAY_PRODUCT = auto()
41+
"""The product of energy and latency. """
42+
4043
@classmethod
4144
def all_metrics(cls):
4245
return reduce(or_, iter(cls), cls.LATENCY)
4346

4447
def includes_leak_energy(self) -> bool:
4548
"""Returns True if the metrics include leak energy, either alone or as part of
4649
total energy. False otherwise."""
47-
return self & (Metrics.ENERGY | Metrics.LEAK_ENERGY)
50+
return self & (
51+
Metrics.ENERGY | Metrics.LEAK_ENERGY | Metrics.ENERGY_DELAY_PRODUCT
52+
)
4853

4954
def includes_dynamic_energy(self) -> bool:
5055
"""Returns True if the metrics include dynamic energy, either alone or as part
5156
of total energy. False otherwise."""
52-
return self & (Metrics.ENERGY | Metrics.DYNAMIC_ENERGY)
57+
return self & (
58+
Metrics.ENERGY | Metrics.DYNAMIC_ENERGY | Metrics.ENERGY_DELAY_PRODUCT
59+
)
60+
61+
def includes_latency(self) -> bool:
62+
"""Returns True if the metrics include latency, either alone or as part of
63+
energy-delay product. False otherwise."""
64+
return self & (Metrics.LATENCY | Metrics.ENERGY_DELAY_PRODUCT)
65+
66+
def includes_energy(self) -> bool:
67+
"""Returns True if the metrics include total energy, either alone or as part of
68+
energy-delay product. False otherwise."""
69+
return self & (Metrics.ENERGY | Metrics.ENERGY_DELAY_PRODUCT)

accelforge/mapper/FFM/_join_pmappings/join_pmappings.py

Lines changed: 44 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -62,81 +62,65 @@ def log_total_time(self):
6262
logger.info(f"============================\n")
6363

6464

65+
def _apply_edp_columns(df: pd.DataFrame, metrics: Metrics) -> pd.DataFrame:
66+
if not (metrics & Metrics.ENERGY_DELAY_PRODUCT):
67+
return df
68+
if not (metrics & Metrics.ENERGY):
69+
del df["Total<SEP>energy"]
70+
if not (metrics & Metrics.LATENCY):
71+
del df["Total<SEP>latency"]
72+
return df
73+
74+
6575
class OptimalityThresholder:
6676
def __init__(
6777
self,
6878
prev_solutions: Mappings,
6979
_pmapping_row_filter_function: Callable[[pd.DataFrame], np.ndarray],
70-
aggregator: str,
7180
print_progress: bool,
81+
metrics: Metrics,
7282
):
73-
compare_to = prev_solutions.data
83+
self.metrics = metrics
84+
compare_to = _apply_edp_columns(prev_solutions.data.copy(), metrics)
7485
compare_cols = [c for c in compare_to.columns if col_used_in_pareto(c)]
7586
self._pmapping_row_filter_function = _pmapping_row_filter_function
76-
self.aggregator = aggregator
77-
78-
if self.aggregator in ("prod", "sum"):
79-
objective_cols = [c for c in compare_cols if is_objective_col(c)]
80-
self._agg_cols = objective_cols
81-
if objective_cols:
82-
values = np.column_stack([compare_to[c].values for c in objective_cols])
83-
if self.aggregator == "prod":
84-
agg = np.prod(values, axis=1)
85-
else:
86-
agg = np.sum(values, axis=1)
87-
self._agg_threshold = agg.min()
88-
else:
89-
self._agg_threshold = float("inf")
90-
if print_progress:
91-
label = "product" if self.aggregator == "prod" else "sum"
92-
print(
93-
f"Filtering out pmappings with {label} > "
94-
f"{self._agg_threshold:.2e}"
95-
)
96-
else: # "any"
97-
compare_to = compare_to.sort_values(by=compare_cols, ascending=False)
9887

99-
if len(compare_to) > 10:
100-
chosen_indices = np.round(np.linspace(0, len(compare_to) - 1, 10))
101-
else:
102-
chosen_indices = np.round(np.arange(len(compare_to)))
88+
compare_to = compare_to.sort_values(by=compare_cols, ascending=False)
89+
90+
if len(compare_to) > 10:
91+
chosen_indices = np.round(np.linspace(0, len(compare_to) - 1, 10))
92+
else:
93+
chosen_indices = np.round(np.arange(len(compare_to)))
94+
95+
self.compare_to: list[dict[str, float]] = []
96+
if print_progress:
97+
print(f"Filtering out pmappings worse than the following:")
10398

104-
self.compare_to: list[dict[str, float]] = []
99+
for i in chosen_indices.astype(int):
100+
self.compare_to.append({c: compare_to[c].iloc[i] for c in compare_cols})
105101
if print_progress:
106-
print(f"Filtering out pmappings worse than the following:")
107-
108-
for i in chosen_indices.astype(int):
109-
self.compare_to.append({c: compare_to[c].iloc[i] for c in compare_cols})
110-
if print_progress:
111-
print(
112-
"\t"
113-
+ " ".join(
114-
f"{k}={float(v):.2e}"
115-
for k, v in self.compare_to[-1].items()
116-
)
102+
print(
103+
"\t"
104+
+ " ".join(
105+
f"{k}={float(v):.2e}" for k, v in self.compare_to[-1].items()
117106
)
107+
)
118108

119109
def __call__(self, mapping: pd.DataFrame) -> bool:
120110
nondominated_by_all = np.ones(len(mapping), dtype=bool)
121111

122-
if self.aggregator in ("prod", "sum"):
123-
cols_present = [c for c in self._agg_cols if c in mapping.columns]
124-
if cols_present:
125-
values = np.column_stack([mapping[c].values for c in cols_present])
126-
if self.aggregator == "prod":
127-
agg = np.prod(values, axis=1)
112+
edp_mapping = _apply_edp_columns(
113+
mapping.copy(), self.metrics, return_only_objectives=True
114+
)
115+
116+
for c in self.compare_to:
117+
nondominated = np.zeros(len(edp_mapping), dtype=bool)
118+
for k, v in c.items():
119+
if k not in edp_mapping.columns:
120+
nondominated |= True
128121
else:
129-
agg = np.sum(values, axis=1)
130-
nondominated_by_all = agg <= self._agg_threshold
131-
else: # "any"
132-
for c in self.compare_to:
133-
nondominated = np.zeros(len(mapping), dtype=bool)
134-
for k, v in c.items():
135-
if k not in mapping.columns:
136-
nondominated |= True
137-
else:
138-
nondominated |= mapping[k] <= v
139-
nondominated_by_all &= nondominated
122+
nondominated |= edp_mapping[k] <= v
123+
nondominated_by_all &= nondominated
140124

141125
if self._pmapping_row_filter_function is not None:
142126
nondominated_by_all &= self._pmapping_row_filter_function(mapping)
@@ -235,8 +219,8 @@ def join_strategy_2(
235219
filter_func = OptimalityThresholder(
236220
joined,
237221
_pmapping_row_filter_function,
238-
spec.mapper._metric_aggregator,
239222
print_progress,
223+
metrics,
240224
)
241225
except Exception as e:
242226
if i == len(thresholds) - 1:
@@ -356,6 +340,8 @@ def clean_compress_and_join_pmappings(
356340

357341
joined = decompress_pmappings(joined, decompress_data)
358342

343+
_apply_edp_columns(joined.data, metrics)
344+
359345
for einsum_name in einsum2pmappings:
360346
col = f"{einsum_name}<SEP>{MAPPING_COLUMN}"
361347
joined.data[col] = joined.data[col].apply(

accelforge/mapper/FFM/_make_pmappings/make_pmappings_from_templates/make_tile_shapes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2055,7 +2055,7 @@ def _clean_energy_columns(df: dict, metrics: Metrics):
20552055
# The model outputs separated dynamic energy and leak energy because it's easier for
20562056
# tile shape exploration. Combine them if needed and generate the total energy
20572057
# column.
2058-
if metrics & Metrics.ENERGY:
2058+
if metrics.includes_energy():
20592059
leak = df.pop("Total<SEP>leak_energy")
20602060
dynamic = df.pop("Total<SEP>dynamic_energy")
20612061
df["Total<SEP>energy"] = leak + dynamic

accelforge/mapper/_simanneal2/simanneal.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,8 @@ def _make_mapspace_globals(
714714
objective_function = lambda x: x["Total<SEP>latency"]
715715
elif objective == (Metrics.ENERGY | Metrics.LATENCY):
716716
objective_function = lambda x: x["Total<SEP>energy"] * x["Total<SEP>latency"]
717+
elif objective == Metrics.ENERGY_DELAY_PRODUCT:
718+
objective_function = lambda x: x["Total<SEP>energy"] * x["Total<SEP>latency"]
717719
else:
718720
raise ValueError(f"Unknown objective {objective}")
719721
mg = MapspaceGlobals(

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ def accumulate_child_result(
5252
component_object = find_component_object(
5353
network.component, info.job.flattened_arch
5454
)
55-
workload_bpv = info.job.einsum.tensor_accesses[network.tensor].bits_per_value
55+
workload_bpv = info.job.einsum.tensor_accesses[
56+
network.tensor
57+
].bits_per_value
5658
bits_per_value = component_object.bits_per_value.get(
5759
network.tensor, workload_bpv
5860
)
@@ -62,10 +64,13 @@ def accumulate_child_result(
6264
else:
6365
actions_per_value = bits_per_value
6466
volume = (
65-
compute_dense_tile_occupancy(projection, child_shape) * actions_per_value
67+
compute_dense_tile_occupancy(projection, child_shape)
68+
* actions_per_value
6669
)
6770

68-
if info.job.spec_one_einsum.arch.is_above(node.component, network.component):
71+
if info.job.spec_one_einsum.arch.is_above(
72+
node.component, network.component
73+
):
6974
continue
7075

7176
relevancy = info.tensor_to_relevancy[network.tensor][node.rank_variable]
@@ -103,4 +108,4 @@ def accumulate_child_result(
103108
else:
104109
raise RuntimeError(f"unhandled relevancy type {relevancy}")
105110

106-
return self.overall_max_hops
111+
return self.overall_max_hops

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -634,12 +634,7 @@ def handle_repeated_value(repeated_shape):
634634
)
635635

636636
network_analyzer.accumulate_child_result(
637-
child_result,
638-
info,
639-
shape_repeats,
640-
einsum_name,
641-
child_shape,
642-
node
637+
child_result, info, shape_repeats, einsum_name, child_shape, node
643638
)
644639

645640
for einsum, child_steps in child_result.temporal_steps.items():

accelforge/model/run_model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ def run_model(
192192
for key, count in simple_actions.items():
193193
actions_df[action2col(key)] = count.total * n_instances
194194

195-
if metrics & Metrics.LATENCY:
195+
if metrics.includes_latency():
196196
df["Total<SEP>latency"] = overall_latency * n_instances
197197
# df[f"latency<SEP>compute"] = comp_latency * n_instances
198198
# For first latency, we'll follow the convention of treating compute

examples/arches/compute_in_memory/components/dac_c2c_r2r.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,4 +602,4 @@ def __init__(
602602
self.leak_power_scale *= 2 # Two sides
603603
self.area_scale *= 2 # Two sides
604604
self.energy_scale *= 2 # Two sides
605-
# Voltage is still the full range because we're pulling from a VDD supply
605+
# Voltage is still the full range because we're pulling from a VDD supply

examples/arches/compute_in_memory/components/zero_comparator.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,7 @@ class ZeroComparator(ComponentModel):
2929
priority = 0.5
3030

3131
def __init__(
32-
self,
33-
n_comparators: int,
34-
n_bits: int,
35-
tech_node: str,
36-
voltage: float = 0.85
32+
self, n_comparators: int, n_bits: int, tech_node: str, voltage: float = 0.85
3733
):
3834
self.n_comparators = n_comparators
3935
self.n_bits = n_bits
@@ -81,7 +77,6 @@ def __init__(
8177
energy_scale_function=quadratic,
8278
latency_scale_function=reciprocal,
8379
leak_power_scale_function=linear,
84-
8580
)
8681
subcomponent.leak_power_scale *= 0.02 # Low-leakage technology
8782

tests/not_working/test_network.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def test_hierarchical_1d(self):
9292
* (KN / MAC_TILE)
9393
* M_TILE
9494
* KN # temporal for n1 in mapping
95-
* (MAC_TILE-1) # multicast along X-axis of MacArray
95+
* (MAC_TILE - 1) # multicast along X-axis of MacArray
9696
* BITS_PER_VALUE,
9797
)
9898
self.assertEqual(

0 commit comments

Comments
 (0)