Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a15374-f59f-7a31-86d2-d23b5d2ed181
84 lines
3.4 KiB
Python
84 lines
3.4 KiB
Python
import argparse
|
|
import json
|
|
import math
|
|
from pathlib import Path
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description="Compare measured application cgroup limits; never apply resources"
|
|
)
|
|
parser.add_argument("input", type=Path)
|
|
parser.add_argument("--output", type=Path, required=True)
|
|
parser.add_argument("--expected-cpu-m", type=int, default=1000)
|
|
parser.add_argument("--expected-memory-mib", type=int, default=1024)
|
|
args = parser.parse_args()
|
|
v = json.loads(args.input.read_text())
|
|
if not v.get("measurement_complete") or v.get("measurement_gaps"):
|
|
raise ValueError("measurement gaps prevent a limit comparison")
|
|
if v["app_runtime"]["nano_cpus"] != args.expected_cpu_m * 1000000:
|
|
raise ValueError("actual CPU limit does not match expected limit")
|
|
if v["app_runtime"]["memory_bytes"] != args.expected_memory_mib * 1024**2:
|
|
raise ValueError("actual memory limit does not match expected limit")
|
|
load_names = {p["name"] for p in v.get("phase_results", []) if p["kind"] == "load"} or {"ordinary"}
|
|
samples = [s for s in v["runtime_samples"] if s.get("phase") in load_names and "cpu_seconds" in s]
|
|
pairs = [
|
|
(a, b)
|
|
for a, b in zip(samples, samples[1:])
|
|
if a["phase"] == b["phase"]
|
|
and b["cpu_seconds"] >= a["cpu_seconds"]
|
|
and b["monotonic_seconds"] > a["monotonic_seconds"]
|
|
]
|
|
if not pairs:
|
|
raise ValueError("no valid CPU sample intervals")
|
|
rates = [
|
|
(b["cpu_seconds"] - a["cpu_seconds"]) / (b["monotonic_seconds"] - a["monotonic_seconds"]) * 1000
|
|
for a, b in pairs
|
|
]
|
|
|
|
|
|
def p95(values):
|
|
return sorted(values)[math.ceil(0.95 * len(values)) - 1]
|
|
|
|
|
|
def counter_delta(key):
|
|
return sum(max(0, b["cpu_stat"][key] - a["cpu_stat"][key]) for a, b in pairs)
|
|
|
|
|
|
db = [s["docker_stats"] for s in v["database_samples"] if s["phase"] in load_names]
|
|
report = {
|
|
"status": "provisional-existing-limit-comparison",
|
|
"ordinary": v["ordinary"],
|
|
"startup_seconds": v.get("startup_seconds"),
|
|
"phase_results": v.get("phase_results", []),
|
|
"document_transfer": v["document_transfer"],
|
|
"complete": v["complete"],
|
|
"provisional_pass": v["provisional_pass"],
|
|
"measurement_complete": v["measurement_complete"],
|
|
"measurement_gaps": v["measurement_gaps"],
|
|
"config": v["config"],
|
|
"completed_iterations": v["completed_iterations"],
|
|
"app_runtime": v["app_runtime"],
|
|
"application_measured": {
|
|
"sample_intervals": len(rates),
|
|
"cpu_p95_m": p95(rates),
|
|
"cpu_mean_m": sum(b["cpu_seconds"] - a["cpu_seconds"] for a, b in pairs)
|
|
/ sum(b["monotonic_seconds"] - a["monotonic_seconds"] for a, b in pairs)
|
|
* 1000,
|
|
"cgroup_memory_peak_mib": max(s["rss_bytes"] for s in samples) / 1024**2,
|
|
"throttled_periods": counter_delta("nr_throttled"),
|
|
"periods": counter_delta("nr_periods"),
|
|
"throttled_usec": counter_delta("throttled_usec"),
|
|
},
|
|
"database_separate": {
|
|
"samples": len(db),
|
|
"cpu_p95_percent": p95([float(s["CPUPerc"].rstrip("%")) for s in db]),
|
|
"memory_snapshots_kind": "docker usage; full intervals retained raw",
|
|
},
|
|
"interpretation": (
|
|
"No production limit increase implied. The inspected limit is tested only for this "
|
|
"local synthetic mix. 60m request is not validated as adequate under contention. "
|
|
"Memory includes page cache; comparison to earlier summedRSS is not equivalent. "
|
|
"No human/ingress/SSO acceptance."
|
|
),
|
|
}
|
|
args.output.write_text(json.dumps(report, indent=2) + "\n")
|
|
print(json.dumps(report, indent=2))
|