analytical-viz: compound tiebreaker — fewer PEs / lower HBM% when latency ties
Every place that picks a single "best" config from the Pareto set now
uses a compound sort key: (latency_ns ↑, pes_used ↑, hbm_utilization ↑).
Primary = latency; when configs tie on latency (common — cp_ring
variants, some placement variants often produce identical numbers),
prefer smaller-footprint picks.
Places updated:
- app.py: sidebar Apply Attn/FFN/Attn+FFN button
- app.py: Physical Layout tab Attn/FFN/Attn+FFN button
- app.py: Auto Suggest tab "Best latency" metric
- app.py: Auto Hardware tab "Best latency" metric (uses parallelism.pes_used
+ parallelism.hbm_utilization since JointScore wraps ConfigScore)
- auto_hardware.py: _best_parallelism_for_hw iteration key
No behavior change when there's a strict latency winner. When there are
ties, the picked config uses fewer PEs and lower HBM utilization.
Verified: all 24 pytest tests pass (default include_attention=True and
include_ffn=True paths unchanged).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -237,8 +237,12 @@ with st.sidebar.expander("Parallelism", expanded=True):
|
|||||||
"`pe_hbm_gb` or reducing `s_kv`."
|
"`pe_hbm_gb` or reducing `s_kv`."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
# Compound key: min latency, then fewer PEs, then lower HBM %.
|
||||||
|
# Prefer smaller-footprint configs when they tie on latency.
|
||||||
_sb_best = min(_sb_res.pareto_scores,
|
_sb_best = min(_sb_res.pareto_scores,
|
||||||
key=lambda s: s.total_latency_ns)
|
key=lambda s: (s.total_latency_ns,
|
||||||
|
s.pes_used,
|
||||||
|
s.hbm_utilization))
|
||||||
st.session_state["cp"] = _snap(_sb_best.cp, _CP_OPTS)
|
st.session_state["cp"] = _snap(_sb_best.cp, _CP_OPTS)
|
||||||
st.session_state["tp"] = _snap(_sb_best.tp, _TP_OPTS)
|
st.session_state["tp"] = _snap(_sb_best.tp, _TP_OPTS)
|
||||||
st.session_state["pp"] = _snap(_sb_best.pp, _PP_OPTS)
|
st.session_state["pp"] = _snap(_sb_best.pp, _PP_OPTS)
|
||||||
@@ -580,8 +584,11 @@ with tab_layout:
|
|||||||
"`s_kv`."
|
"`s_kv`."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
# Compound tiebreaker: min latency, then fewer PEs, then lower HBM %.
|
||||||
_pl_best = min(_pl_res.pareto_scores,
|
_pl_best = min(_pl_res.pareto_scores,
|
||||||
key=lambda s: s.total_latency_ns)
|
key=lambda s: (s.total_latency_ns,
|
||||||
|
s.pes_used,
|
||||||
|
s.hbm_utilization))
|
||||||
# Load the winning config into the sidebar's session state.
|
# Load the winning config into the sidebar's session state.
|
||||||
st.session_state["cp"] = _pl_best.cp
|
st.session_state["cp"] = _pl_best.cp
|
||||||
st.session_state["tp"] = _pl_best.tp
|
st.session_state["tp"] = _pl_best.tp
|
||||||
@@ -1587,7 +1594,10 @@ def _render_auto_explore_tab():
|
|||||||
_m2.metric("Feasible", f"{_res.total_feasible:,}")
|
_m2.metric("Feasible", f"{_res.total_feasible:,}")
|
||||||
_m3.metric("Pareto configs", len(_res.pareto_scores))
|
_m3.metric("Pareto configs", len(_res.pareto_scores))
|
||||||
if _res.pareto_scores:
|
if _res.pareto_scores:
|
||||||
_best = min(_res.pareto_scores, key=lambda s: s.total_latency_ns)
|
_best = min(_res.pareto_scores,
|
||||||
|
key=lambda s: (s.total_latency_ns,
|
||||||
|
s.pes_used,
|
||||||
|
s.hbm_utilization))
|
||||||
_m4.metric("Best latency", f"{_best.latency_ms:.2f} ms")
|
_m4.metric("Best latency", f"{_best.latency_ms:.2f} ms")
|
||||||
|
|
||||||
if not _res.pareto_scores:
|
if not _res.pareto_scores:
|
||||||
@@ -1884,7 +1894,9 @@ def _render_auto_hardware_tab():
|
|||||||
_hm3.metric("Pareto configs", len(_hw_res.pareto_scores))
|
_hm3.metric("Pareto configs", len(_hw_res.pareto_scores))
|
||||||
if _hw_res.pareto_scores:
|
if _hw_res.pareto_scores:
|
||||||
_best = min(_hw_res.pareto_scores,
|
_best = min(_hw_res.pareto_scores,
|
||||||
key=lambda s: s.total_latency_ns)
|
key=lambda s: (s.total_latency_ns,
|
||||||
|
s.parallelism.pes_used,
|
||||||
|
s.parallelism.hbm_utilization))
|
||||||
_hm4.metric("Best latency", f"{_best.latency_ms:.2f} ms")
|
_hm4.metric("Best latency", f"{_best.latency_ms:.2f} ms")
|
||||||
|
|
||||||
if not _hw_res.pareto_scores:
|
if not _hw_res.pareto_scores:
|
||||||
|
|||||||
@@ -245,14 +245,19 @@ def _best_parallelism_for_hw(
|
|||||||
matches the caller's attention/FFN/full choice.
|
matches the caller's attention/FFN/full choice.
|
||||||
"""
|
"""
|
||||||
best: ConfigScore | None = None
|
best: ConfigScore | None = None
|
||||||
|
best_key: tuple | None = None
|
||||||
for topo in _iter_reduced_parallelism(model, s_kv, mode):
|
for topo in _iter_reduced_parallelism(model, s_kv, mode):
|
||||||
cfg = FullConfig(model=model, topo=topo, machine=machine)
|
cfg = FullConfig(model=model, topo=topo, machine=machine)
|
||||||
s = score_config(cfg, include_attention=include_attention,
|
s = score_config(cfg, include_attention=include_attention,
|
||||||
include_ffn=include_ffn)
|
include_ffn=include_ffn)
|
||||||
if not (s.fits_memory and s.placement_valid):
|
if not (s.fits_memory and s.placement_valid):
|
||||||
continue
|
continue
|
||||||
if best is None or s.total_latency_ns < best.total_latency_ns:
|
# Compound tiebreaker: prefer fewer PEs and lower HBM % when latency
|
||||||
|
# ties across variant knobs (cp_ring, placement, kv_shard_mode, etc.).
|
||||||
|
_k = (s.total_latency_ns, s.pes_used, s.hbm_utilization)
|
||||||
|
if best is None or _k < best_key:
|
||||||
best = s
|
best = s
|
||||||
|
best_key = _k
|
||||||
return best
|
return best
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user