guardiantails / scripts /perf_audit.py
kshitijthakkar's picture
Perf: JSON-only API scaffolds (-21 components); warm chart imports on startup; aggregate walks/day on timeline
94fad59 verified
Raw
History Blame Contribute Delete
6 kB
"""End-to-end performance audit — every chart, every API, cold + warm.
Goal: find anything that takes >5 seconds (Chiku's life depends on responsive
tools during a medical event).
Reports three tiers:
FAIL > 5000 ms (unacceptable — must fix)
WARN > 1500 ms (noticeable lag, optimize if possible)
OK <= 1500 ms (responsive)
Run: python -m scripts.perf_audit
"""
from __future__ import annotations
import json
import logging
import sys
import time
from pathlib import Path
_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(_ROOT))
from dotenv import load_dotenv
load_dotenv(_ROOT / ".env")
logging.basicConfig(level=logging.WARNING, format="%(levelname)s: %(message)s")
CHIKU = "ec8ed3df-3b7b-4013-8d6d-c76832e1ec88"
FAIL_MS = 5000
WARN_MS = 1500
class Row:
__slots__ = ("label", "ms")
def __init__(self, label: str, ms: float):
self.label = label
self.ms = ms
def tier(self) -> str:
if self.ms > FAIL_MS:
return "FAIL"
if self.ms > WARN_MS:
return "WARN"
return "OK "
def timeit(label: str, fn) -> Row:
t0 = time.perf_counter()
fn()
ms = (time.perf_counter() - t0) * 1000
return Row(label, ms)
def audit_charts_cold() -> list[Row]:
"""Cold-start: time each chart in a fresh Python session by design.
Call from a brand-new subprocess to measure realistic first-call cost.
"""
from guardiantails.services.hf_sync import download_backup
from guardiantails.models import init_db, get_db
download_backup()
init_db()
rows: list[Row] = []
# Import and run each chart from cold — measures full first-call cost
# including any module chains loaded lazily
from guardiantails.core.charts import (
dashboard_timeline, walk_distance_chart, weight_timeline,
medication_adherence_trend, dose_status_calendar,
seizure_severity_bar, seizure_by_hour_bar, seizure_triggers_pie,
seizure_moon_polar, seizure_weather_chart, seizure_vs_pressure_scatter,
poop_timing_bar, lab_trends_chart, cost_breakdown_pie, cost_cumulative_line,
)
from guardiantails.core.dashboard_tab import _get_pet_photo_html
CHART_FNS = [
("dashboard_timeline 90d", lambda: dashboard_timeline(CHIKU, days=90)),
("walk_distance_chart 90d", lambda: walk_distance_chart(CHIKU, days=90)),
("weight_timeline 90d", lambda: weight_timeline(CHIKU, days=90)),
("medication_adherence", lambda: medication_adherence_trend(CHIKU)),
("dose_status_calendar", lambda: dose_status_calendar(CHIKU)),
("seizure_severity_bar", lambda: seizure_severity_bar(CHIKU)),
("seizure_by_hour_bar", lambda: seizure_by_hour_bar(CHIKU)),
("seizure_triggers_pie", lambda: seizure_triggers_pie(CHIKU)),
("seizure_moon_polar", lambda: seizure_moon_polar(CHIKU)),
("seizure_weather_chart", lambda: seizure_weather_chart(CHIKU)),
("seizure_vs_pressure", lambda: seizure_vs_pressure_scatter(CHIKU)),
("poop_timing_bar", lambda: poop_timing_bar(CHIKU)),
("lab_trends_chart", lambda: lab_trends_chart(CHIKU)),
("cost_breakdown_pie", lambda: cost_breakdown_pie(CHIKU)),
("cost_cumulative_line", lambda: cost_cumulative_line(CHIKU)),
("pet_photo_html", lambda: _get_pet_photo_html(CHIKU)),
]
for label, fn in CHART_FNS:
rows.append(timeit(label, fn))
return rows
def audit_api_endpoints() -> list[Row]:
"""Hit the live Space's API endpoints, time each round-trip (cold once,
warm twice), and report the WARM time (simulates steady-state usage).
"""
rows: list[Row] = []
try:
from gradio_client import Client
except Exception as e:
rows.append(Row(f"gradio_client import failed: {e}", 999999))
return rows
c = Client("kshitijthakkar/guardiantails", auth=("admin", "neoThakkar@2017"))
endpoints = [
("/v1/health", lambda: c.predict(api_name="/v1/health")),
("/v1/get_dashboard_stats", lambda: c.predict(CHIKU, api_name="/v1/get_dashboard_stats")),
("/v1/get_daily_log (recent)",lambda: c.predict(CHIKU, "2026-04-16", api_name="/v1/get_daily_log")),
("/v1/get_daily_log (old)", lambda: c.predict(CHIKU, "2025-12-20", api_name="/v1/get_daily_log")),
("/v1/get_seizures", lambda: c.predict(CHIKU, "10", "0", api_name="/v1/get_seizures")),
("/v1/get_weight_history", lambda: c.predict(CHIKU, api_name="/v1/get_weight_history")),
("/v1/get_emergency_packet", lambda: c.predict(CHIKU, api_name="/v1/get_emergency_packet")),
]
for label, fn in endpoints:
# First call = cold; time the second one (warm) so we report realistic steady-state
try:
fn() # warm the path
except Exception as e:
rows.append(Row(f"{label} (ERROR: {str(e)[:80]})", 999999))
continue
rows.append(timeit(label, fn))
return rows
def print_table(title: str, rows: list[Row]) -> None:
print()
print("=" * 70)
print(title)
print("=" * 70)
print(f"{'TIER':6}{'MS':>8} LABEL")
print("-" * 70)
# Sort by ms desc to show worst first
for r in sorted(rows, key=lambda r: -r.ms):
print(f"{r.tier():6}{r.ms:7.0f} {r.label}")
fails = [r for r in rows if r.ms > FAIL_MS]
warns = [r for r in rows if WARN_MS < r.ms <= FAIL_MS]
print()
print(f" {len(fails)} FAIL | {len(warns)} WARN | {len(rows)-len(fails)-len(warns)} OK")
def main() -> None:
print("AUDIT: charts (local, cold-start)")
chart_rows = audit_charts_cold()
print_table("CHARTS — local cold-start", chart_rows)
print()
print("AUDIT: live Space API (warm — 2nd call)")
api_rows = audit_api_endpoints()
print_table("API — live Space round-trip (warm)", api_rows)
if __name__ == "__main__":
main()