hpce-dev / scripts /sim_bundle_stress.py
์ด๋™ํ˜„
[TEST] bundle/worker ๋Œ€๊ทœ๋ชจ ์ŠคํŠธ๋ ˆ์Šค ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ ์ถ”๊ฐ€ (cs ๊ฒ€์ฆ ์ด์‹)
07f059a
Raw
History Blame Contribute Delete
7.49 kB
from __future__ import annotations
"""
๊ฒฐํ•ฉ(bundle-v3) ๋Œ€๊ทœ๋ชจ ๋žœ๋ค ์ŠคํŠธ๋ ˆ์Šค ์‹œ๋ฎฌ๋ ˆ์ด์…˜ โ€” ์˜๋„ ๋ณ€ํ™” ์ ์ ˆ์„ฑยท์ด์ƒ ์ผ€์ด์Šค ํƒ์ง€.
- ์„ค๋ฌธ: ๋ฌด์ž‘์œ„ N_SURVEY๊ฑด (์ „์ˆ˜ 1,870๋งŒ์€ ๋ถˆ๊ฐ€ โ†’ ๋Œ€๊ทœ๋ชจ ์ƒ˜ํ”Œ)
- ํ–‰๋™: N_SESS ์„ธ์…˜ ร— ์„ธ์…˜๋‹น ์ตœ๋Œ€ MAX_ACT ํด๋ฆญ (ํด๋ฆญ ๊ธฐ๋ฐ˜ ์œˆ๋„์šฐ ๊ฐ€์ •)
- ์ง„ํ–‰๋ฐ”๋Š” /tmp/cs_sim_progress.txt ์— in-place ๊ธฐ๋ก (tail -f ๋กœ ๊ด€๋žŒ)
- ์š”์•ฝ์€ stdout, ์ƒ์„ธ๋Š” /tmp/cs_sim_report.json
ํƒ์ง€ ์ด์ƒ:
E1 ๋ฒ”์œ„/NaN (scoreโˆ‰[0,1])
E2 ๋ฒ”์šฉ intent(AI์ถ”์ฒœ๋ฅ˜) top-5 ๋ˆ„์ถœ
E3 ์ƒ์œ„ ๋™์  (top-1๊ณผ ๋™๋ฅ ์ด top-5 ๋‚ด 3๊ฐœ ์ด์ƒ)
E4 ํ–‰๋™ ๋ฌด๋ฐ˜์‘ (ํด๋ฆญ entity์˜ ์‹ ํ˜ธ intent๊ฐ€ top-10์—๋„ ๋ชป ๋“ฆ)
E5 stuck (top-1์ด โ‰ฅSTUCK_N ์—ฐ์† ๊ณ ์ •)
+ ๋ถ„ํฌ ๊ฑด์ „์„ฑ(top-1 ๋‹ค์–‘์„ฑ/HHI), entity๋ณ„ ๋ฐ˜์‘๋ฅ 
"""
import json, random, sys, time
from collections import Counter, defaultdict
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from core.engines import config # noqa: E402
from core.extractor import get_extractor # noqa: E402
from core.inference import infer_batch, infer_with_behavior # noqa: E402
SID = "bundle-v3"
N_SURVEY = 30_000
N_SESS = 8_000
MAX_ACT = 30
STUCK_N = 15
GENERIC = set() # bundle: ๋ฒ”์šฉ intent ์—†์Œ (E2 N/A)
PROG = "/tmp/bundle_sim_progress.txt"
REPORT = "/tmp/bundle_sim_report.json"
tax = config.get_taxonomy(SID)["intents"]
NM = {i["id"]: i["name"] for i in tax}
SURVEY = config.get_survey(SID)["questions"]
OPTS = {q["id"]: [o["code"] for o in q["options"]] for q in SURVEY}
SIG = config.get_behavior_signals(SID)
# ํ–‰๋™ ํŠธ๋ฆฌ
_bc = config.get_behaviors(SID)
STEP1 = [(b["event_type"], b["entity"], b["id"]) for b in _bc["step1"]["behaviors"]]
STEP2 = {}
for parent, items in _bc["step2"]["by_parent"].items():
STEP2[parent] = [(b["event_type"], b["entity"], b["id"]) for b in items]
def _bar(frac, label):
n = int(frac * 30)
with open(PROG, "w") as f:
f.write(f"[{'#'*n}{'.'*(30-n)}] {frac*100:5.1f}% {label}")
def _rand_survey(rng):
return {q: rng.choice(OPTS[q]) for q in OPTS}
def _top(scores, k):
return sorted(scores, key=lambda s: s.final_score, reverse=True)[:k]
def _check_common(scores, anom, tag):
# E1 ๋ฒ”์œ„/NaN
for s in scores:
v = s.final_score
if v != v or v < -1e-9 or v > 1.0001:
anom["E1"].append((tag, s.intent_id, v)); break
top = _top(scores, 5)
top_ids = [s.intent_id for s in top]
# E2 ๋ฒ”์šฉ ๋ˆ„์ถœ
g = GENERIC & set(top_ids)
if g:
anom["E2"].append((tag, list(g)))
# E3 ์ƒ์œ„ ๋™์ 
tv = round(top[0].final_score, 2)
tie = sum(1 for s in top if round(s.final_score, 2) == tv)
if tie >= 3:
anom["E3"].append((tag, tv, tie, top_ids[:tie]))
return top_ids
def run():
ext = get_extractor()
rng = random.Random(20240601)
t0 = time.time()
anom = defaultdict(list)
# ์„ค๋ฌธ sweep
top1_survey = Counter()
for i in range(N_SURVEY):
a = _rand_survey(rng)
try:
_, sc = infer_batch(a, SID)
except Exception as e:
anom["E1"].append(("survey", "EXCEPTION", str(e)[:80])); continue
top_ids = _check_common(sc, anom, "survey")
top1_survey[top_ids[0]] += 1
if i % 500 == 0:
_bar(i / (N_SURVEY + N_SESS), f"์„ค๋ฌธ {i:,}/{N_SURVEY:,}")
# ํ–‰๋™ sweep
ent_rise = defaultdict(lambda: [0, 0]) # entity โ†’ [์‹ ํ˜ธ์ƒ์Šน, ์‹œ๋„]
stuck_runs = []
top1_beh = Counter()
for j in range(N_SESS):
a = _rand_survey(rng)
sess = f"__st_{j}"
ext.reset(sess)
cur_parent = None
last_top1 = None; run_len = 0; max_run = 0
n_act = rng.randint(5, MAX_ACT)
for _ in range(n_act):
# ํŠธ๋ฆฌ ๋„ค๋น„๊ฒŒ์ด์…˜
r = rng.random()
if cur_parent is None or r < 0.35:
et, en, bid = rng.choice(STEP1); cur_parent = bid
elif r < 0.5 and cur_parent:
cur_parent = None; ext.add_event(sess, "navigate_back", "back_to_step1"); continue
else:
items = STEP2.get(cur_parent) or STEP1
et, en, bid = rng.choice(items)
ext.add_event(sess, et, en)
try:
_, sc = infer_with_behavior(a, sess, SID)
except Exception as e:
anom["E1"].append((f"beh_{j}", "EXCEPTION", str(e)[:80])); break
top_ids = _check_common(sc, anom, f"beh_{j}")
# E4 ๋ฐ˜์‘์„ฑ (์‹ ํ˜ธ entity๊ฐ€ top-10์—)
targets = SIG.get(en, [])
if targets:
ent_rise[en][1] += 1
if set(targets) & set([s.intent_id for s in _top(sc, 10)]):
ent_rise[en][0] += 1
# E5 stuck
if top_ids[0] == last_top1:
run_len += 1; max_run = max(max_run, run_len)
else:
last_top1 = top_ids[0]; run_len = 1
top1_beh[top_ids[0]] += 1
if max_run >= STUCK_N:
stuck_runs.append((f"beh_{j}", last_top1, max_run))
ext.reset(sess)
if j % 150 == 0:
_bar((N_SURVEY + j) / (N_SURVEY + N_SESS), f"ํ–‰๋™ {j:,}/{N_SESS:,}")
_bar(1.0, "์™„๋ฃŒ")
dt = time.time() - t0
# โ”€โ”€ ์ง‘๊ณ„/์š”์•ฝ โ”€โ”€
n_surv_top1 = sum(top1_survey.values())
hhi = sum((c / n_surv_top1) ** 2 for c in top1_survey.values()) if n_surv_top1 else 0
low_ent = {e: f"{v[0]}/{v[1]}={v[0]/v[1]*100:.0f}%" for e, v in ent_rise.items() if v[1] and v[0]/v[1] < 0.9}
summary = {
"elapsed_sec": round(dt, 1),
"n_survey": N_SURVEY, "n_sess": N_SESS, "max_act": MAX_ACT,
"E1_range_nan": len(anom["E1"]),
"E2_generic_leak": len(anom["E2"]),
"E3_top_tie(>=3)": len(anom["E3"]),
"E5_stuck(>=%d)" % STUCK_N: len(stuck_runs),
"survey_top1_distinct": len(top1_survey),
"survey_top1_HHI": round(hhi, 4),
"survey_top1_top8": [(NM[i][:14], f"{c/n_surv_top1*100:.1f}%") for i, c in top1_survey.most_common(8)],
"entity_low_responsiveness(<90%)": low_ent,
"stuck_samples": stuck_runs[:10],
"E1_samples": anom["E1"][:5],
"E2_samples": anom["E2"][:5],
"E3_samples": anom["E3"][:5],
}
json.dump({"summary": summary,
"anom_E1": anom["E1"][:200], "anom_E2": anom["E2"][:200],
"anom_E3": anom["E3"][:200], "stuck": stuck_runs[:200]},
open(REPORT, "w"), ensure_ascii=False, indent=1)
print("=" * 64)
print(f"๊ฒฐํ•ฉ ์ŠคํŠธ๋ ˆ์Šค ์‹œ๋ฎฌ ์™„๋ฃŒ โ€” {dt/60:.1f}๋ถ„ (์„ค๋ฌธ {N_SURVEY:,} + ํ–‰๋™ {N_SESS:,}ร—โ‰ค{MAX_ACT})")
print("=" * 64)
print(f" [E1] ๋ฒ”์œ„/NaN/์˜ˆ์™ธ : {len(anom['E1'])} ๊ฑด")
print(f" [E2] ๋ฒ”์šฉ intent ๋ˆ„์ถœ : {len(anom['E2'])} ๊ฑด")
print(f" [E3] ์ƒ์œ„ ๋™์ (โ‰ฅ3) : {len(anom['E3'])} ๊ฑด")
print(f" [E5] stuck(top1 โ‰ฅ{STUCK_N}์—ฐ์†): {len(stuck_runs)} ์„ธ์…˜")
print(f" ์„ค๋ฌธ top-1 ๋‹ค์–‘์„ฑ: {len(top1_survey)}์ข…, HHI={hhi:.3f}")
print(f" ์„ค๋ฌธ top-1 ์ตœ๋นˆ: " + ", ".join(f"{NM[i][:10]} {c/n_surv_top1*100:.0f}%" for i, c in top1_survey.most_common(5)))
print(f" ํ–‰๋™ ๋ฐ˜์‘๋ฅ <90% entity: {low_ent if low_ent else '์—†์Œ โœ“'}")
if stuck_runs:
print(" stuck ์ƒ˜ํ”Œ:", [(s[1], s[2]) for s in stuck_runs[:5]])
print(f"\n์ƒ์„ธ ๋ฆฌํฌํŠธ: {REPORT}")
if __name__ == "__main__":
run()