- perf/run-all.sh: масштабы 1 и 2, шаги reset -> gen -> verify -> stand -> preflight -> scroll -> coauthor -> grow -> modals -> modals_profiling -> memory -> memtrend -> [control4x] -> bench -> aggregate; лог и run-all.status.json, возобновление (PERF_STEPS, PERF_SKIP_RESET), сухой режим с оценкой длительности, PERF_S2_REPEATS/PERF_S2_TARGETS, контроль CPU 4x (PERF_CONTROL_TARGETS). - Основная метрика: main_thread_ms и main_thread_ms_per_step в скролле (CDP TaskDuration), frame_excess_ms; в summary.md первыми строками. - SQL-статистика по шагам: PERF_SQLSTATS_TAG -> sql/<шаг>/ (sqlstats --out). - netlog: тела /auth/ не пишутся, поля password/token/secret вырезаются. - scroll.spec: уникальные имена целей (лист ССП с суффиксом /ssp, год в отчёте проекта) - иначе Playwright не запускал файл из-за дублей. - PERF_TRACE=0 для прогонов с одним повтором. - README: scroll-coauthor, run-all, возобновление, без CPU 4/6 в матрицах. - design.md: уточнена формулировка R-2, решения Task 10a. Refs #202 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
70 lines
2.7 KiB
Python
70 lines
2.7 KiB
Python
from perfkit import sqlstats
|
|
from perfkit.sqlstats import explain_candidates, v3_functions, is_explainable, pick_params
|
|
|
|
|
|
def row(q, total=1.0):
|
|
return {"query": q, "total_exec_time": total}
|
|
|
|
|
|
def test_v3_functions_extracts_names():
|
|
assert v3_functions("SELECT * FROM v3.v_sheet_rows($1, $2)") == ["v_sheet_rows"]
|
|
assert v3_functions("select v3.upd_cell($1,$2)") == ["upd_cell"]
|
|
assert v3_functions("SELECT 1") == []
|
|
|
|
|
|
def test_is_explainable_select_and_read_functions():
|
|
assert is_explainable("SELECT * FROM v3.v_sheet_rows($1)")
|
|
assert is_explainable(" select a from t where id = $1")
|
|
assert is_explainable("WITH x AS (SELECT 1) SELECT * FROM x")
|
|
|
|
|
|
def test_is_explainable_rejects_dml_and_writers():
|
|
assert not is_explainable("UPDATE t SET a = $1")
|
|
assert not is_explainable("INSERT INTO t VALUES ($1)")
|
|
assert not is_explainable("DELETE FROM t")
|
|
assert not is_explainable("SELECT * FROM v3.add_line($1)")
|
|
assert not is_explainable("SELECT v3.upd_cell($1, $2)")
|
|
assert not is_explainable("SELECT v3.del_line($1)")
|
|
assert not is_explainable("SELECT * FROM t FOR UPDATE")
|
|
assert not is_explainable("SELECT set_config('a', $1, false)")
|
|
assert not is_explainable("SELECT pg_stat_statements_reset()")
|
|
assert not is_explainable("EXPLAIN SELECT 1")
|
|
|
|
|
|
def test_explain_candidates_top5_by_total_in_order():
|
|
rows = [row("UPDATE t SET a=$1", 100)] + [row(f"SELECT {i} FROM t WHERE a=$1", i) for i in range(10)]
|
|
got = explain_candidates(rows, n=5)
|
|
assert [r["total_exec_time"] for r in got] == [9, 8, 7, 6, 5]
|
|
|
|
|
|
def test_pick_params_uses_sample_when_given():
|
|
assert pick_params("SELECT $1, $2", {"SELECT $1, $2": [1, "a"]}) == [1, "a"]
|
|
assert pick_params("SELECT $1", {}) is None
|
|
|
|
|
|
def test_dump_out_dir_passed_to_dump(monkeypatch, tmp_path):
|
|
"""--out: sql_top.json/explain пишутся в отдельный каталог шага (run-all), сетевой лог читается из run_dir."""
|
|
seen = {}
|
|
|
|
async def fake(run_dir, top, out_dir):
|
|
seen.update(run_dir=run_dir, top=top, out_dir=out_dir)
|
|
return {"explained": 0, "skipped": 0}
|
|
|
|
monkeypatch.setattr(sqlstats, "_dump", fake)
|
|
out = tmp_path / "sql" / "scroll"
|
|
assert sqlstats.main(["dump", str(tmp_path), "--top", "7", "--out", str(out)]) == 0
|
|
assert seen == {"run_dir": tmp_path, "top": 7, "out_dir": out}
|
|
assert out.is_dir()
|
|
|
|
|
|
def test_dump_without_out_writes_to_run_dir(monkeypatch, tmp_path):
|
|
seen = {}
|
|
|
|
async def fake(run_dir, top, out_dir):
|
|
seen.update(out_dir=out_dir)
|
|
return {"explained": 0, "skipped": 0}
|
|
|
|
monkeypatch.setattr(sqlstats, "_dump", fake)
|
|
assert sqlstats.main(["dump", str(tmp_path)]) == 0
|
|
assert seen["out_dir"] == tmp_path
|