#!/usr/bin/env python3
"""Render a self-contained final report for Feature #149."""
from __future__ import annotations
import argparse
import html
import json
import statistics
from pathlib import Path
from typing import Any
EXPECTED_COHORTS = (
"prefetch_pp_object_system",
"prefetch_pp_object_data",
"pp_object_system",
"pp_object_data",
)
def number(value: Any, digits: int = 0) -> str:
if not isinstance(value, (int, float)):
return "n/a"
return f"{value:,.{digits}f}"
def load(path: Path) -> dict[str, Any]:
value = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} is not an object")
return value
def latest(record: dict[str, Any], key: str) -> Any:
return (record.get("latestCounts") or {}).get(key)
def stats(record: dict[str, Any], key: str) -> dict[str, Any]:
value = record.get(key) or {}
return value if isinstance(value, dict) else {}
def delta_median(record: dict[str, Any]) -> float | None:
value = stats(record, "deltaWallMs").get("median")
return float(value) if isinstance(value, (int, float)) else None
def stable_median(record: dict[str, Any]) -> float | None:
value = stats(record, "stableDeltaWallMs").get("median")
return float(value) if isinstance(value, (int, float)) else None
def delta_mean(record: dict[str, Any]) -> float | None:
value = stats(record, "deltaWallMs").get("mean")
return float(value) if isinstance(value, (int, float)) else None
def stable_mean(record: dict[str, Any]) -> float | None:
value = stats(record, "stableDeltaWallMs").get("mean")
return float(value) if isinstance(value, (int, float)) else None
def percent_change(baseline: float | None, value: float | None) -> float | None:
if baseline in (None, 0) or value is None:
return None
return (value - baseline) / baseline * 100
def percent_text(baseline: float | None, value: float | None) -> str:
change = percent_change(baseline, value)
return "n/a" if change is None else f"{change:+.1f}%"
def stat_value(record: dict[str, Any], field: str, key: str) -> float | None:
value = stats(record, field).get(key)
return float(value) if isinstance(value, (int, float)) else None
def svg_chart(records: list[dict[str, Any]]) -> str:
values = [delta_median(record) or 0 for record in records]
maximum = max(values) if values else 1
width, height, left, baseline = 860, 250, 62, 212
bar_width, gap = 112, 56
bars: list[str] = []
for index, (record, value) in enumerate(zip(records, values)):
x = left + index * (bar_width + gap)
bar_height = 0 if maximum == 0 else value / maximum * 164
y = baseline - bar_height
colour = "#0f766e" if record.get("disk") == "data" else "#2563eb"
label = html.escape(str(record.get("cohortId")))
bars.append(
f' '
f'{number(value / 1000, 2)}s '
f'{label} '
)
return f'''
delta median wall clock
{''.join(bars)}
'''
def timeline_svg(records: list[dict[str, Any]]) -> str:
"""Render the fixed serial order and the six run slots in each cohort."""
width, row_height, top = 930, 48, 36
height = top + row_height * len(records) + 18
parts = [
f'',
'each row: snapshot (S) then five delta runs (D1–D5); adjacent starts are 600 s apart ',
]
for row, record in enumerate(records):
y = top + row * row_height
label = html.escape(str(record.get("cohortId")))
parts.append(f'{label} ')
parts.append(f' ')
for index in range(6):
x = 310 + index * 116
mode = "S" if index == 0 else f"D{index}"
fill = "#2563eb" if index == 0 else "#0f766e"
parts.append(f' ')
parts.append(f'{mode} ')
parts.append(" ")
return "".join(parts)
def milestone_svg() -> str:
labels = (
("M1", "data disk init"),
("M2", "package + dry-run"),
("M3", "prefetch cohorts"),
("M4", "no-prefetch cohorts"),
("M5", "evidence + report"),
)
width, y = 900, 44
parts = [f' ']
for index, (milestone, label) in enumerate(labels):
x = 72 + index * 189
parts.append(f'{milestone} {label} ')
parts.append(" ")
return "".join(parts)
def paired_rows(records: dict[str, dict[str, Any]]) -> list[tuple[str, dict[str, Any], dict[str, Any]]]:
return [
("prefetch + PP + object", records["prefetch_pp_object_system"], records["prefetch_pp_object_data"]),
("PP + object", records["pp_object_system"], records["pp_object_data"]),
]
def prefetch_rows(records: dict[str, dict[str, Any]]) -> list[tuple[str, dict[str, Any], dict[str, Any]]]:
return [
("system disk", records["pp_object_system"], records["prefetch_pp_object_system"]),
("data disk", records["pp_object_data"], records["prefetch_pp_object_data"]),
]
def run_rows(records: list[dict[str, Any]]) -> list[tuple[str, dict[str, Any]]]:
return [(str(record.get("cohortId")), run) for record in records for run in (record.get("runs") or [])]
def all_delta_stats(records: list[dict[str, Any]]) -> dict[str, float]:
values = [
float(run["wallMs"])
for _, run in run_rows(records)
if run.get("syncMode") == "delta" and isinstance(run.get("wallMs"), (int, float))
]
if not values:
return {}
return {
"count": float(len(values)),
"min": min(values),
"max": max(values),
"mean": statistics.mean(values),
"median": statistics.median(values),
"p90": statistics.quantiles(values, n=10, method="inclusive")[8] if len(values) > 1 else values[0],
}
def conclusion_lines(indexed: dict[str, dict[str, Any]]) -> list[str]:
prefetch_system = indexed["prefetch_pp_object_system"]
prefetch_data = indexed["prefetch_pp_object_data"]
no_prefetch_system = indexed["pp_object_system"]
no_prefetch_data = indexed["pp_object_data"]
return [
f"两种磁盘的差异没有在两个 profile 上呈现同一方向:prefetch profile 的稳定 delta median 为 system {number(stable_median(prefetch_system) / 1000 if stable_median(prefetch_system) else None, 2)}s、data {number(stable_median(prefetch_data) / 1000 if stable_median(prefetch_data) else None, 2)}s(data vs system {percent_text(stable_median(prefetch_system), stable_median(prefetch_data))});无 prefetch profile 为 system {number(stable_median(no_prefetch_system) / 1000 if stable_median(no_prefetch_system) else None, 2)}s、data {number(stable_median(no_prefetch_data) / 1000 if stable_median(no_prefetch_data) else None, 2)}s({percent_text(stable_median(no_prefetch_system), stable_median(no_prefetch_data))})。",
f"在同一磁盘内,开启 transport prefetch 相对关闭 prefetch 的稳定 delta median 下降:system {percent_text(stable_median(no_prefetch_system), stable_median(prefetch_system))},data {percent_text(stable_median(no_prefetch_data), stable_median(prefetch_data))};这是本实验最稳定的方向性信号。",
f"snapshot 不与 delta 同向:system 开启 prefetch 后为 {percent_text((no_prefetch_system.get('snapshot') or {}).get('wallMs'), (prefetch_system.get('snapshot') or {}).get('wallMs'))},data 为 {percent_text((no_prefetch_data.get('snapshot') or {}).get('wallMs'), (prefetch_data.get('snapshot') or {}).get('wallMs'))};因此不能把单次 snapshot wall 解释为纯磁盘因果。",
"VRP/VAP/PP 产物量级和 warnings 随 live 发布窗口小幅变化,全部 run 成功且没有 recovery snapshot;网络同步长尾与 live 数据演进是主要限制。",
]
def write_markdown(records: list[dict[str, Any]], source_commit: str, package_sha256: str, remote_host: str, input_paths: list[Path], path: Path) -> None:
indexed = {str(record.get("cohortId")): record for record in records}
all_stats = all_delta_stats(records)
lines = [
"# Feature #149 远端系统盘/数据盘性能实验报告",
"",
f"- 远端:`{remote_host}`;源码:`{source_commit}`;portable archive SHA-256:`{package_sha256}`",
"- 结论口径:snapshot 单样本;全部 delta 为 delta1–delta5;稳定 delta 为 delta2–delta5。",
"",
"## 结论摘要",
"",
]
lines.extend(f"- {line}" for line in conclusion_lines(indexed))
lines += [
"",
"## Cohort 摘要",
"",
"| cohort | disk | profile | total elapsed | snapshot wall | all delta min/mean/median/p90/max | stable median | max RSS | latest VRP/VAP/PP/warnings |",
"| --- | --- | --- | ---: | --- | ---: | ---: | ---: | --- |",
]
for record in records:
delta = stats(record, "deltaWallMs")
lines.append(
"| {id} | {disk} | {profile} | {elapsed}s | {snapshot}ms | {min}/{mean}/{median}/{p90}/{max}ms | {stable}ms | {rss} KiB | {vrp}/{vap}/{pp}/{warnings} |".format(
id=record.get("cohortId"), disk=record.get("disk"), profile=record.get("profile"), elapsed=record.get("elapsedSeconds"),
snapshot=number((record.get("snapshot") or {}).get("wallMs"), 1), min=number(delta.get("min"), 1), mean=number(delta.get("mean"), 1),
median=number(delta.get("median"), 1), p90=number(delta.get("p90"), 1), max=number(delta.get("max"), 1), stable=number(stable_median(record), 1),
rss=number(record.get("maxRssKb")), vrp=latest(record, "vrps"), vap=latest(record, "vaps"), pp=latest(record, "publicationPoints"), warnings=latest(record, "warnings"),
)
)
lines += [
"",
"## 全部 delta 汇总",
"",
f"20 个 delta 样本:min/mean/median/p90/max = {number(all_stats.get('min'), 1)}/{number(all_stats.get('mean'), 1)}/{number(all_stats.get('median'), 1)}/{number(all_stats.get('p90'), 1)}/{number(all_stats.get('max'), 1)} ms。",
"",
"## 磁盘配对与 prefetch 对比",
"",
"| profile | system all/stable median | data all/stable median | data vs system(all / stable) |",
"| --- | ---: | ---: | ---: |",
]
for label, system, data in paired_rows(indexed):
lines.append(f"| {label} | {number(delta_median(system), 1)} / {number(stable_median(system), 1)} ms | {number(delta_median(data), 1)} / {number(stable_median(data), 1)} ms | {percent_text(delta_median(system), delta_median(data))} / {percent_text(stable_median(system), stable_median(data))} |")
lines += [
"",
"| profile | system all/stable mean | data all/stable mean | data vs system(all / stable) |",
"| --- | ---: | ---: | ---: |",
]
for label, system, data in paired_rows(indexed):
lines.append(f"| {label} | {number(delta_mean(system), 1)} / {number(stable_mean(system), 1)} ms | {number(delta_mean(data), 1)} / {number(stable_mean(data), 1)} ms | {percent_text(delta_mean(system), delta_mean(data))} / {percent_text(stable_mean(system), stable_mean(data))} |")
lines += [
"",
"| disk | no-prefetch stable median | prefetch stable median | prefetch vs no-prefetch |",
"| --- | ---: | ---: | ---: |",
]
for label, no_prefetch, prefetch in prefetch_rows(indexed):
lines.append(f"| {label} | {number(stable_median(no_prefetch), 1)} ms | {number(stable_median(prefetch), 1)} ms | {percent_text(stable_median(no_prefetch), stable_median(prefetch))} |")
lines += [
"",
"| disk | no-prefetch stable mean | prefetch stable mean | prefetch vs no-prefetch |",
"| --- | ---: | ---: | ---: |",
]
for label, no_prefetch, prefetch in prefetch_rows(indexed):
lines.append(f"| {label} | {number(stable_mean(no_prefetch), 1)} ms | {number(stable_mean(prefetch), 1)} ms | {percent_text(stable_mean(no_prefetch), stable_mean(prefetch))} |")
lines += ["", "## 逐 run 证据", "", "| cohort | run | mode | actual start UTC | wall ms | max RSS KiB | schedule lag ms | VRP/VAP/PP/warnings | artifacts |", "| --- | --- | --- | --- | ---: | ---: | ---: | --- | --- |"]
for cohort, run in run_rows(records):
lines.append(f"| {cohort} | {run.get('runId')} | {run.get('syncMode')} | {run.get('actualStartRfc3339Utc')} | {number(run.get('wallMs'), 1)} | {number(run.get('maxRssKb'))} | {number(run.get('scheduleLagMs'), 1)} | {run.get('vrps')}/{run.get('vaps')}/{run.get('publicationPoints')}/{run.get('warnings')} | {'complete' if run.get('artifactsComplete') and not run.get('missingArtifacts') else 'INCOMPLETE'} |")
lines += [
"",
"## 验收、异常与证据",
"",
"- 4 个 cohort 均为 6/6 success、首轮 snapshot 后连续五轮 delta,实际相邻启动节拍为 600 秒,`scheduleLagMs=0`;没有 recovery snapshot 或缺失核心产物。",
"- warnings 的最新值范围为 524–540(各 run 约 518–544),VRP/VAP/PP 在 live 窗口内小幅变化;这些属于可解释的 live/网络窗口变化,不是失败状态。",
"- 完整 run root 保留在远端对应系统盘或 `/data`;本地只回传四份 `cohort-summary.json/.md` 轻量证据。",
"",
"本报告由四份 `cohort-summary.json` 自动生成;由于 live RPKI 数据、网络和运行时间窗口不同,磁盘结果仅作方向性比较。",
"",
"### 本地证据",
"",
]
lines.extend(f"- `{path}`" for path in input_paths)
lines += ["", "### 远端原始证据根", ""]
for record in records:
package_root = record.get("packageRoot", "n/a")
cohort = record.get("cohortId", "unknown")
lines.append(f"- `{cohort}` package/run root:`{package_root}`;cohort summary:`{package_root}/experiments/feature149-{cohort}/cohort-summary.json`")
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--cohort-summary", action="append", required=True, type=Path)
parser.add_argument("--out-html", required=True, type=Path)
parser.add_argument("--out-markdown", required=True, type=Path)
parser.add_argument("--remote-host", required=True)
parser.add_argument("--source-commit", required=True)
parser.add_argument("--package-sha256", default="see M2 package report")
args = parser.parse_args()
input_paths = list(args.cohort_summary)
records = [load(path) for path in input_paths]
indexed = {str(record.get("cohortId")): record for record in records}
if set(indexed) != set(EXPECTED_COHORTS):
raise ValueError(f"expected cohorts {EXPECTED_COHORTS}, got {tuple(indexed)}")
ordered = [indexed[name] for name in EXPECTED_COHORTS]
for record in ordered:
runs = record.get("runs") or []
if record.get("successCount") != 6 or record.get("runCount") != 6 or record.get("artifactStatus") != "complete" or len(runs) != 6:
raise ValueError(f"incomplete cohort {record.get('cohortId')}")
if runs[0].get("syncMode") != "snapshot" or any(run.get("syncMode") != "delta" for run in runs[1:]):
raise ValueError(f"unexpected sync modes in {record.get('cohortId')}")
all_stats = all_delta_stats(ordered)
cards = [
("Cohorts", "4", "all complete"),
("Runs", "24 / 24", "snapshot + 5 delta per cohort"),
("All delta median", f"{number(all_stats.get('median', 0) / 1000, 2)}s", "20 live delta samples"),
("Source", html.escape(args.source_commit), html.escape(args.remote_host)),
]
card_html = "".join(f'{title}
{value} {detail} ' for title, value, detail in cards)
cohort_rows_html = "".join(
"
{id} {disk} {profile} {elapsed}s {snapshot} ms {min}/{mean}/{median}/{p90}/{max} ms {stable} ms {rss} KiB {vrp} {vap} {pp} {warnings} ".format(
id=html.escape(str(record.get("cohortId"))), disk=html.escape(str(record.get("disk"))), profile=html.escape(str(record.get("profile"))), elapsed=number(record.get("elapsedSeconds")),
snapshot=number((record.get("snapshot") or {}).get("wallMs"), 1), min=number(stat_value(record, "deltaWallMs", "min"), 1), mean=number(stat_value(record, "deltaWallMs", "mean"), 1),
median=number(stat_value(record, "deltaWallMs", "median"), 1), p90=number(stat_value(record, "deltaWallMs", "p90"), 1), max=number(stat_value(record, "deltaWallMs", "max"), 1), stable=number(stable_median(record), 1),
rss=number(record.get("maxRssKb")), vrp=number(latest(record, "vrps")), vap=number(latest(record, "vaps")), pp=number(latest(record, "publicationPoints")), warnings=number(latest(record, "warnings")),
)
for record in ordered
)
paired_html = "".join(
"{label} {system_all} / {system_stable} {data_all} / {data_stable} {all_change} / {stable_change} ".format(
label=html.escape(label), system_all=number(delta_median(system), 1), system_stable=number(stable_median(system), 1), data_all=number(delta_median(data), 1), data_stable=number(stable_median(data), 1),
all_change=percent_text(delta_median(system), delta_median(data)), stable_change=percent_text(stable_median(system), stable_median(data)),
)
for label, system, data in paired_rows(indexed)
)
paired_mean_html = "".join(
"{label} {system_all} / {system_stable} {data_all} / {data_stable} {all_change} / {stable_change} ".format(
label=html.escape(label), system_all=number(delta_mean(system), 1), system_stable=number(stable_mean(system), 1), data_all=number(delta_mean(data), 1), data_stable=number(stable_mean(data), 1),
all_change=percent_text(delta_mean(system), delta_mean(data)), stable_change=percent_text(stable_mean(system), stable_mean(data)),
)
for label, system, data in paired_rows(indexed)
)
prefetch_html = "".join(
"{label} {no_prefetch} {prefetch} {change} ".format(
label=html.escape(label), no_prefetch=number(stable_median(no_prefetch), 1), prefetch=number(stable_median(prefetch), 1), change=percent_text(stable_median(no_prefetch), stable_median(prefetch)),
)
for label, no_prefetch, prefetch in prefetch_rows(indexed)
)
prefetch_mean_html = "".join(
"{label} {no_prefetch} {prefetch} {change} ".format(
label=html.escape(label), no_prefetch=number(stable_mean(no_prefetch), 1), prefetch=number(stable_mean(prefetch), 1), change=percent_text(stable_mean(no_prefetch), stable_mean(prefetch)),
)
for label, no_prefetch, prefetch in prefetch_rows(indexed)
)
run_rows_html = "".join(
"{cohort} {run} {mode} {start} {wall} {rss} {lag} {vrp}/{vap}/{pp}/{warnings} {artifact} ".format(
cohort=html.escape(cohort), run=html.escape(str(run.get("runId"))), mode=html.escape(str(run.get("syncMode"))), start=html.escape(str(run.get("actualStartRfc3339Utc"))), wall=number(run.get("wallMs"), 1), rss=number(run.get("maxRssKb")), lag=number(run.get("scheduleLagMs"), 1),
vrp=number(run.get("vrps")), vap=number(run.get("vaps")), pp=number(run.get("publicationPoints")), warnings=number(run.get("warnings")), artifact="complete" if run.get("artifactsComplete") and not run.get("missingArtifacts") else "INCOMPLETE",
)
for cohort, run in run_rows(ordered)
)
evidence_rows_html = "".join(
"{cohort} {root}{summary} ".format(
cohort=html.escape(str(record.get("cohortId"))),
root=html.escape(str(record.get("packageRoot", "n/a"))),
summary=html.escape(f"{record.get('packageRoot', 'n/a')}/experiments/feature149-{record.get('cohortId')}/cohort-summary.json"),
)
for record in ordered
)
warning_values = [latest(record, "warnings") for record in ordered if isinstance(latest(record, "warnings"), (int, float))]
max_delta = max((run.get("wallMs", 0) for _, run in run_rows(ordered) if run.get("syncMode") == "delta"), default=0)
report_html = f'''Feature #149 性能实验报告
Feature #149:系统盘 / 数据盘缓存性能实验 远端 {html.escape(args.remote_host)} · source {html.escape(args.source_commit)} · archive SHA-256 {html.escape(args.package_sha256)} · 4 cohorts / 24 serial all5 runs
{card_html}
实验拓扑与时序 amd64 远端主机的 system cohort 将 portable package、state、数据和日志全部写在系统盘;data cohort 将对应内容全部写在 /data。四个 cohort 按 A-system → A-data → B-system → B-data 串行执行,每个 row 是 1 snapshot + 5 delta,相邻启动节拍 600 秒。
{timeline_svg(ordered)}
Milestone timeline {milestone_svg()}M1–M5 均已通过:磁盘初始化、同 checksum package 部署与 dry-run、A/B 两组正式运行、证据归档和报告收口。
主机、磁盘与 provenance {html.escape(args.remote_host)};system 为远端根文件系统(/dev/vda3),data 为 /data(/dev/vdb1、ext4、rpki-data)。同一 archive checksum 为 {html.escape(args.package_sha256)},源码 commit 为 {html.escape(args.source_commit)}。对象 cache 固定包含 ROA 与 child-certificate validation cache;两 profile 的唯一 cache 差异是 transport prefetch。
结论摘要 {''.join(f'{html.escape(line)} ' for line in conclusion_lines(indexed))}
Delta median wall clock {svg_chart(ordered)}颜色:蓝色 system,青绿色 data。全体 delta 的 median 为 {number(all_stats.get('median'), 1)} ms;最大 delta 为 {number(max_delta, 1)} ms,长尾包含网络同步窗口。
逐 cohort KPI cohort disk profile elapsed snapshot delta min/mean/median/p90/max stable median max RSS VRP VAP PP warnings {cohort_rows_html}
磁盘配对(all delta / stable delta median) profile system ms data ms data vs system(all / stable) {paired_html}
负值表示 data median 更快,正值表示更慢;snapshot 单样本另行列在 cohort KPI 表中。
磁盘配对(all delta / stable delta mean) profile system ms data ms data vs system(all / stable) {paired_mean_html}
这里的 mean 是对应 cohort 的 deltaWallMs 平均值;负值表示 data mean 更快。
Prefetch 开关对比(stable delta median) disk no prefetch ms prefetch ms prefetch vs no prefetch {prefetch_html}
Prefetch 开关对比(stable delta mean) disk no prefetch ms prefetch ms prefetch vs no prefetch {prefetch_mean_html}
逐 run 原始指标 cohort run mode actual start UTC wall ms max RSS KiB schedule lag ms VRP/VAP/PP/warnings artifacts {run_rows_html}
验收与异常诊断 4 个 cohort 均为 6/6 success、首轮 snapshot 后连续五轮 delta;summary 中每 run 的核心产物均完整,实际启动间隔校验为 600 秒。 最新 warnings 范围为 {number(min(warning_values) if warning_values else None)}–{number(max(warning_values) if warning_values else None)};VRP/VAP/PP 在 live 窗口内小幅变化,未出现输出塌缩或 recovery snapshot。 结果受 live RPKI 发布变化、RRDP/rsync 网络长尾和顺序时间窗口影响;不能仅凭四组 wall 值声称 IOPS 的严格因果效应。 cohort 远端 package/run root 远端 cohort summary {evidence_rows_html}
本地输入证据为:{'; '.join(f'{html.escape(str(path))}' for path in input_paths)}。
统计口径 snapshot 统计只包含每个 cohort 的首轮;all delta 统计包含 delta1–delta5 共 20 个样本;stable delta 统计包含 delta2–delta5 共 16 个样本。详细 cache 命中、stage timing、命令 argv、run-meta/run-summary 和完整产物仍在远端 run root。
'''
args.out_html.parent.mkdir(parents=True, exist_ok=True)
args.out_markdown.parent.mkdir(parents=True, exist_ok=True)
args.out_html.write_text(report_html, encoding="utf-8")
write_markdown(ordered, args.source_commit, args.package_sha256, args.remote_host, input_paths, args.out_markdown)
if __name__ == "__main__":
main()