"""Dependency-free SVG charts for the winv2 perf baseline.
No matplotlib/pandas (not in the bundled env). Reads baseline_startup.csv and
writes two self-contained SVGs that render in a browser, GitHub, or Notion:
baseline_startup.svg - backend-http-ready per launch (warm vs cold)
baseline_phases.svg - where the time goes (app-launch / first-paint / backend)
Run: python make_graphs.py
"""
import csv
import os
HERE = os.path.dirname(os.path.abspath(__file__))
CSV = os.path.join(HERE, "baseline_startup.csv")
WARM = "#2e9e5b"
COLD = "#d64545"
INK = "#1a1d27"
MUTE = "#8892a4"
GRID = "#e2e6ef"
def rows():
with open(CSV, newline="", encoding="utf-8") as f:
return list(csv.DictReader(f))
def bars_chart(data):
w, h = 900, 420
pad_l, pad_b, pad_t, pad_r = 60, 90, 50, 20
plot_w = w - pad_l - pad_r
plot_h = h - pad_t - pad_b
vals = [int(r["backend_http_ready_ms"]) for r in data]
vmax = max(vals)
n = len(data)
bw = plot_w / n * 0.7
gap = plot_w / n
out = [f'')
return "\n".join(out)
def phases_chart(data):
warm = [r for r in data if r["class"] == "warm"]
cold = [r for r in data if r["class"] == "cold"]
def med(rows_, key):
xs = sorted(int(r[key]) for r in rows_)
return xs[len(xs) // 2] if xs else 0
cases = [
("typical warm launch", med(warm, "app_launch_ms"), med(warm, "first_paint_ms"), med(warm, "backend_http_ready_ms")),
("typical cold launch", med(cold, "app_launch_ms"), med(cold, "first_paint_ms"), med(cold, "backend_http_ready_ms")),
]
w, h = 900, 260
pad_l, pad_r, pad_t = 170, 30, 50
plot_w = w - pad_l - pad_r
vmax = max(c[3] for c in cases)
out = [f'')
return "\n".join(out)
def boot_chart():
"""Before/after grouped bars for the boot-phase breakdown (profile_boot.py)."""
path = os.path.join(HERE, "boot_breakdown.csv")
with open(path, newline="", encoding="utf-8") as f:
data = list(csv.DictReader(f))
w, h = 900, 360
pad_l, pad_r, pad_t, pad_b = 60, 30, 50, 120
plot_w = w - pad_l - pad_r
plot_h = h - pad_t - pad_b
vmax = max(max(int(r["before_ms"]), int(r["after_ms"])) for r in data)
n = len(data)
group = plot_w / n
bw = group * 0.34
out = [f'')
return "\n".join(out)
def appbuilder_chart():
"""Horizontal bars for the App Builder create-path breakdown. Returns None
if the measurement CSV hasn't been generated yet."""
path = os.path.join(HERE, "appbuilder_breakdown.csv")
if not os.path.exists(path):
return None
with open(path, newline="", encoding="utf-8") as f:
raw = list(csv.DictReader(f))
# Keep only real timing phases (drop the boolean/skipped/-1 rows).
data = [r for r in raw if r["ms"].lstrip("-").isdigit() and int(r["ms"]) >= 0
and not r["phase"].strip().startswith("->")]
if not data:
return None
w = 980
row_h, gap, pad_t, pad_l, pad_r = 30, 14, 56, 320, 90
h = pad_t + len(data) * (row_h + gap) + 30
vmax = max(int(r["ms"]) for r in data) or 1
plot_w = w - pad_l - pad_r
out = [f'')
return "\n".join(out)
def startup_beforeafter_chart():
"""Before/after grouped bars for the signed-build startup result (Task #10)."""
path = os.path.join(HERE, "startup_beforeafter.csv")
if not os.path.exists(path):
return None
with open(path, newline="", encoding="utf-8") as f:
data = list(csv.DictReader(f))
w, h = 900, 320
pad_l, pad_r, pad_t, pad_b = 60, 30, 56, 90
plot_w, plot_h = w - pad_l - pad_r, h - pad_t - pad_b
vmax = max(max(int(r["before_ms"]), int(r["after_ms"])) for r in data)
n = len(data); group = plot_w / n; bw = group * 0.30
out = [f'')
return "\n".join(out)
def main():
data = rows()
open(os.path.join(HERE, "baseline_startup.svg"), "w", encoding="utf-8").write(bars_chart(data))
open(os.path.join(HERE, "baseline_phases.svg"), "w", encoding="utf-8").write(phases_chart(data))
open(os.path.join(HERE, "boot_breakdown.svg"), "w", encoding="utf-8").write(boot_chart())
wrote = "baseline_startup.svg + baseline_phases.svg + boot_breakdown.svg"
ab = appbuilder_chart()
if ab:
open(os.path.join(HERE, "appbuilder_breakdown.svg"), "w", encoding="utf-8").write(ab)
wrote += " + appbuilder_breakdown.svg"
sba = startup_beforeafter_chart()
if sba:
open(os.path.join(HERE, "startup_beforeafter.svg"), "w", encoding="utf-8").write(sba)
wrote += " + startup_beforeafter.svg"
print("wrote " + wrote)
if __name__ == "__main__":
main()