analytical-viz: sidebar memory-min buttons are scope-aware (Attn / FFN / Attn+FFN)

Replace the three memory-optimal Pareto-search buttons in the Parallelism
sidebar with three scope-aware memory-min autosuggest buttons. Each
button sizes for a different per-PE memory footprint:

  - Attn      -> attention weights + KV cache (no FFN weights)
  - FFN/MoE   -> FFN weights only (no attention, no KV)
  - Attn+FFN  -> everything (traditional autosuggest)

memory_layout: per_pe_weight_bytes and compute_memory take
include_attention / include_ffn flags; KV cache is zeroed when attention
scope is excluded.

autosuggest: _score_candidate and auto_suggest forward the flags into
compute_memory, so the smallest-fit search now respects the chosen
scope.

app.py: single "Apply memory-min" caption + 3 column buttons. Each
button runs auto_suggest with its scope filter, snaps the sliders to
the picked (CP, TP, PP), and sets the Physical Layout scope filter to
match. Removes the standalone Apply memory-min button (was duplicating
the Attn+FFN case) and the Pareto-search import.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 23:34:05 -07:00
parent 47c4f40f4d
commit 4ded67a443
3 changed files with 79 additions and 79 deletions
+31 -60
View File
@@ -206,25 +206,18 @@ with st.sidebar.expander("Parallelism", expanded=True):
f"{_default_suggestion.pes_used} PEs "
f"(cp_placement={_default_suggestion.cp_placement})"
)
# Memory-min apply — snap sliders back to what the caption says.
if st.button("Apply memory-min", width='stretch',
key="_sb_apply_memmin",
help="Set sliders to the memory-min config shown above "
"(smallest deployment that fits)."):
st.session_state["cp"] = _snap(_default_suggestion.cp, _CP_OPTS)
st.session_state["tp"] = _snap(_default_suggestion.tp, _TP_OPTS)
st.session_state["pp"] = _snap(_default_suggestion.pp, _PP_OPTS)
st.session_state["dp"] = 1
st.session_state["cp_placement"] = _default_suggestion.cp_placement
st.session_state["_pl_active_scope"] = "full"
st.rerun()
# Three memory-optimal apply buttons — pick a scope, load the
# smallest-fit Pareto config into the sidebar sliders.
from tests.analytical_visualization.auto_explore import (
run_auto_explore as _run_auto_explore_sb,
# Three scope-aware memory-min buttons. Each runs auto_suggest with a
# different (include_attention, include_ffn) filter so the memory-fit
# constraint counts only the relevant block:
# - Attn → attention weights + KV cache (no FFN)
# - FFN/MoE → FFN weights only (no attn / no KV)
# - Attn+FFN → everything (the traditional autosuggest)
st.caption(
"**Apply memory-min** — smallest deployment that fits the chosen "
"block. Each button sizes for a different memory footprint."
)
_sb_scope_meta = {
"attn": (True, False, "Attention"),
"attn": (True, False, "Attn"),
"ffn": (False, True, "FFN/MoE"),
"full": (True, True, "Attn+FFN"),
}
@@ -234,56 +227,34 @@ with st.sidebar.expander("Parallelism", expanded=True):
with _sb_col:
_sb_clicks[_sb_scope] = st.button(
_sb_scope_meta[_sb_scope][2], width='stretch',
key=f"_sb_apply_{_sb_scope}",
help=f"Apply memory-optimal (smallest-fit) parallelism for "
f"{_sb_scope_meta[_sb_scope][2]} scope.",
key=f"_sb_apply_memmin_{_sb_scope}",
help=(f"Memory-min autosuggest — memory budget counts only "
f"{_sb_scope_meta[_sb_scope][2]} weights"
f"{' + KV cache' if _sb_scope == 'attn' else ''}"
f". Picks the smallest deployment that fits."),
)
for _sb_scope, _sb_click in _sb_clicks.items():
if not _sb_click:
continue
_sb_ia, _sb_ff, _sb_lbl = _sb_scope_meta[_sb_scope]
with st.spinner(f"Finding memory-optimal parallelism ({_sb_lbl})..."):
_sb_res = _run_auto_explore_sb(
model, _default_machine, s_kv=s_kv, mode=mode,
include_attention=_sb_ia, include_ffn=_sb_ff, b=b_batch,
with st.spinner(f"Sizing memory-min for {_sb_lbl}..."):
_sb_sug = auto_suggest(
model, _default_machine, s_kv=s_kv, mode=mode, b=b_batch,
include_attention=_sb_ia, include_ffn=_sb_ff,
)
if not _sb_res.pareto_scores:
st.error(
f"No feasible parallelism for {_sb_lbl}. Try raising "
"`pe_hbm_gb` or reducing `s_kv`."
if not _sb_sug.fits:
st.warning(
f"{_sb_lbl} memory-min: no config fits at 10% slack; "
f"best-effort {_sb_sug.pes_used} PEs, {_sb_sug.cubes_used} "
f"cubes ({_sb_sug.reason})."
)
else:
# Smallest-fit Pareto point: fewest PEs first, then lowest
# HBM utilization, then fastest latency as final tiebreaker.
# Gives the smallest deployment that's still Pareto-optimal
# for the chosen scope (matches how the memory-min autosuggest
# thinks — but restricted to this scope's Pareto set).
_sb_best = min(_sb_res.pareto_scores,
key=lambda s: (s.pes_used,
s.hbm_utilization,
s.total_latency_ns))
st.session_state["cp"] = _snap(_sb_best.cp, _CP_OPTS)
st.session_state["tp"] = _snap(_sb_best.tp, _TP_OPTS)
st.session_state["pp"] = _snap(_sb_best.pp, _PP_OPTS)
st.session_state["dp"] = _snap(_sb_best.dp, _DP_OPTS)
st.session_state["tp_placement"] = _sb_best.tp_placement
st.session_state["cp_placement"] = _sb_best.cp_placement
st.session_state["cp_ring_variant"] = _sb_best.cp_ring_variant
st.session_state["kv_mode"] = _sb_best.kv_shard_mode
_sb_tp2 = _snap(_sb_best.tp, _TP_OPTS)
_sb_cp2 = _snap(_sb_best.cp, _CP_OPTS)
_sb_dp2 = _snap(_sb_best.dp, _DP_OPTS)
_sb_ffn_map = {
"TP": f"TP only (div={max(1, _sb_tp2)})",
"TP+CP": f"TP*CP (div={max(1, _sb_tp2 * _sb_cp2)})",
"TP+CP+DP": f"TP*CP*DP (div={max(1, _sb_tp2 * _sb_cp2 * _sb_dp2)})",
}
st.session_state["ffn_scope_label"] = \
_sb_ffn_map[_sb_best.ffn_shard_scope]
# Track for the Physical Layout scope filter, so the tables
# below also filter to this scope.
st.session_state["_pl_active_scope"] = _sb_scope
st.rerun()
st.session_state["cp"] = _snap(_sb_sug.cp, _CP_OPTS)
st.session_state["tp"] = _snap(_sb_sug.tp, _TP_OPTS)
st.session_state["pp"] = _snap(_sb_sug.pp, _PP_OPTS)
st.session_state["dp"] = 1
st.session_state["cp_placement"] = _sb_sug.cp_placement
st.session_state["_pl_active_scope"] = _sb_scope
st.rerun()
# Sharding dims — arrange in 2x3 grid to save vertical space
p_row1 = st.columns(3)