This commit is contained in:
Executable
+173
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""the reference node usage report: rolls up the JSONL usage logs (voice/stt/image/music
|
||||
generations) and the scraped vLLM token-counter snapshots into real numbers.
|
||||
|
||||
Usage:
|
||||
usage_report.py # human-readable report, last 14 days
|
||||
usage_report.py --days 7 # narrower daily window
|
||||
usage_report.py --json # machine-readable, same data
|
||||
"""
|
||||
import argparse
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
|
||||
USAGE_DIR = os.path.expanduser("~/lumbridge/compute/.compute/usage")
|
||||
|
||||
EVENT_LOGS = {
|
||||
"voice": ("voice.jsonl", "duration_s"),
|
||||
"stt": ("stt.jsonl", "audio_duration_s"),
|
||||
"image": ("image.jsonl", None),
|
||||
"music": ("music.jsonl", "duration_s"),
|
||||
}
|
||||
|
||||
VLLM_MODELS = ("brain", "embed", "ocr")
|
||||
VLLM_COUNTERS = ("prompt_tokens_total", "generation_tokens_total", "request_success_total")
|
||||
|
||||
|
||||
def _read_jsonl(path):
|
||||
rows = []
|
||||
if not os.path.exists(path):
|
||||
return rows
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
rows.append(json.loads(line))
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
return rows
|
||||
|
||||
|
||||
def _day(ts):
|
||||
return datetime.datetime.fromtimestamp(ts).date().isoformat()
|
||||
|
||||
|
||||
def summarize_events(name, filename, duration_field, days):
|
||||
rows = _read_jsonl(os.path.join(USAGE_DIR, filename))
|
||||
cutoff = datetime.datetime.now().timestamp() - days * 86400
|
||||
by_day = {}
|
||||
total_count = len(rows)
|
||||
total_duration = 0.0
|
||||
for r in rows:
|
||||
ts = r.get("ts")
|
||||
if ts is None:
|
||||
continue
|
||||
dur = r.get(duration_field) or 0.0 if duration_field else 0.0
|
||||
total_duration += dur
|
||||
day = _day(ts)
|
||||
entry = by_day.setdefault(day, {"count": 0, "duration_s": 0.0})
|
||||
entry["count"] += 1
|
||||
entry["duration_s"] += dur
|
||||
recent_days = {d: v for d, v in by_day.items()
|
||||
if datetime.datetime.fromisoformat(d).timestamp() >= cutoff - 86400}
|
||||
return {
|
||||
"service": name,
|
||||
"total_count": total_count,
|
||||
"total_duration_s": round(total_duration, 1),
|
||||
"total_duration_hours": round(total_duration / 3600, 2),
|
||||
"has_duration": duration_field is not None,
|
||||
"daily": dict(sorted(recent_days.items())),
|
||||
}
|
||||
|
||||
|
||||
def summarize_vllm(days):
|
||||
rows = _read_jsonl(os.path.join(USAGE_DIR, "vllm_snapshots.jsonl"))
|
||||
cutoff = datetime.datetime.now().timestamp() - days * 86400
|
||||
by_model = {m: [] for m in VLLM_MODELS}
|
||||
for r in rows:
|
||||
model = r.get("model")
|
||||
if model in by_model:
|
||||
by_model[model].append(r)
|
||||
|
||||
result = {}
|
||||
for model, snaps in by_model.items():
|
||||
snaps.sort(key=lambda r: r["ts"])
|
||||
current = snaps[-1] if snaps else None
|
||||
tracked = {c: 0.0 for c in VLLM_COUNTERS}
|
||||
prev = None
|
||||
for s in snaps:
|
||||
if s["ts"] < cutoff:
|
||||
prev = s
|
||||
continue
|
||||
if prev is not None:
|
||||
for c in VLLM_COUNTERS:
|
||||
delta = s.get(c, 0) - prev.get(c, 0)
|
||||
if delta > 0:
|
||||
tracked[c] += delta
|
||||
prev = s
|
||||
result[model] = {
|
||||
"reachable_now": current is not None and current["ts"] >= cutoff,
|
||||
"snapshots_recorded": len(snaps),
|
||||
"current": {
|
||||
"prompt_tokens_total": current["prompt_tokens_total"],
|
||||
"generation_tokens_total": current["generation_tokens_total"],
|
||||
"request_success_total": current["request_success_total"],
|
||||
} if current else None,
|
||||
"tracked_since_monitoring_started": tracked,
|
||||
}
|
||||
return result
|
||||
|
||||
|
||||
def render_text(events, vllm, days):
|
||||
lines = []
|
||||
lines.append(f"=== the reference node usage report (last {days} days) ===\n")
|
||||
|
||||
for e in events:
|
||||
lines.append(f"-- {e['service']} --")
|
||||
if e["has_duration"]:
|
||||
lines.append(f" total: {e['total_count']} generations, "
|
||||
f"{e['total_duration_hours']}h ({e['total_duration_s']}s)")
|
||||
else:
|
||||
lines.append(f" total: {e['total_count']} generations")
|
||||
if not e["daily"]:
|
||||
lines.append(" (no activity in this window)")
|
||||
else:
|
||||
for day, v in e["daily"].items():
|
||||
if e["has_duration"]:
|
||||
lines.append(f" {day}: {v['count']:>5} gens, {round(v['duration_s']/60, 1):>7} min")
|
||||
else:
|
||||
lines.append(f" {day}: {v['count']:>5} gens")
|
||||
lines.append("")
|
||||
|
||||
lines.append("-- local LLM / vLLM token throughput --")
|
||||
for model, v in vllm.items():
|
||||
if not v["current"]:
|
||||
lines.append(f" {model}: not reachable (no snapshot ever recorded)")
|
||||
continue
|
||||
status = "up" if v["reachable_now"] else f"down (last seen in a prior snapshot)"
|
||||
c = v["current"]
|
||||
t = v["tracked_since_monitoring_started"]
|
||||
lines.append(f" {model}: {status}")
|
||||
lines.append(f" current counters (since last process restart): "
|
||||
f"{int(c['prompt_tokens_total']):,} prompt tok, "
|
||||
f"{int(c['generation_tokens_total']):,} gen tok, "
|
||||
f"{int(c['request_success_total']):,} requests")
|
||||
lines.append(f" tracked in window ({v['snapshots_recorded']} scrapes): "
|
||||
f"{int(t['prompt_tokens_total']):,} prompt tok, "
|
||||
f"{int(t['generation_tokens_total']):,} gen tok, "
|
||||
f"{int(t['request_success_total']):,} requests")
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--days", type=int, default=14)
|
||||
parser.add_argument("--json", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
events = [summarize_events(name, filename, duration_field, args.days)
|
||||
for name, (filename, duration_field) in EVENT_LOGS.items()]
|
||||
vllm = summarize_vllm(args.days)
|
||||
|
||||
if args.json:
|
||||
print(json.dumps({"events": events, "vllm": vllm, "days": args.days}, indent=2))
|
||||
else:
|
||||
print(render_text(events, vllm, args.days))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user