From 710fc541072fc17c0df197a2fe23768aca20a9b6 Mon Sep 17 00:00:00 2001 From: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com> Date: Fri, 30 Oct 2026 02:57:40 +0800 Subject: [PATCH 1/2] ci: measure hosted subprocess start-up latency refs #81 #144 #40 A dispatch-only job times a hundred plain PowerShell 5.1 starts and fifty node --version starts on windows-2025, reporting percentiles and counts over the fixed fixture deadlines without changing any deadline. --- .github/workflows/conpty-compat.yml | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/.github/workflows/conpty-compat.yml b/.github/workflows/conpty-compat.yml index 246506ad..4458782f 100644 --- a/.github/workflows/conpty-compat.yml +++ b/.github/workflows/conpty-compat.yml @@ -243,3 +243,57 @@ jobs: retention-days: 14 if-no-files-found: warn path: build/test-artifacts/ + + windows-2025-startup-latency: + # Bounded measurement for #81 / #144 / #40: how long does a plain + # PowerShell 5.1 or Node start-up take on this hosted image, and how often + # does it cross the fixed fixture deadlines. No deadlines are changed. + runs-on: windows-2025 + timeout-minutes: 30 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 + with: + python-version: '3.12' + - name: Measure subprocess start-up latency + shell: pwsh + run: | + @' + import json, platform, subprocess, sys, time + def samples(command, count, timeout): + rows = [] + for _ in range(count): + started = time.monotonic() + try: + result = subprocess.run(command, capture_output=True, timeout=timeout) + rows.append({"elapsed": round(time.monotonic() - started, 4), "returncode": result.returncode, "timeout": False}) + except subprocess.TimeoutExpired: + rows.append({"elapsed": round(time.monotonic() - started, 4), "returncode": None, "timeout": True}) + return rows + def summary(rows): + times = sorted(row["elapsed"] for row in rows) + def at(fraction): + return times[min(len(times) - 1, int(len(times) * fraction))] + return {"count": len(rows), "min": times[0], "p50": at(0.5), "p90": at(0.9), "p99": at(0.99), + "max": times[-1], "over_1s": sum(1 for t in times if t >= 1.0), + "over_5s": sum(1 for t in times if t >= 5.0), + "over_10s": sum(1 for t in times if t >= 10.0), + "timeouts": sum(1 for row in rows if row["timeout"])} + ps = samples(["powershell.exe", "-NoLogo", "-NoProfile", "-NonInteractive", "-Command", "exit 0"], 100, 15) + node = samples(["node", "--version"], 50, 15) + report = {"schema": "termforge-startup-latency-v1", "platform": platform.platform(), + "powershell": summary(ps), "node": summary(node), + "powershell_samples": ps, "node_samples": node} + print(json.dumps({k: v for k, v in report.items() if not k.endswith("_samples")})) + with open("startup-latency.json", "w", encoding="utf-8") as stream: + json.dump(report, stream, indent=2) + '@ | Out-File -Encoding utf8 startup-latency.py + python startup-latency.py + - name: Preserve latency evidence + if: always() + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: startup-latency-r2 + retention-days: 14 + if-no-files-found: warn + path: startup-latency.json From 39b9038667a3119a90ddf56c7c6ab61b85884ee1 Mon Sep 17 00:00:00 2001 From: JavaZeroo <71128095+JavaZeroo@users.noreply.github.com> Date: Fri, 30 Oct 2026 03:00:22 +0800 Subject: [PATCH 2/2] ci: publish hosted start-up latency evidence refs #81 #144 #40 Adds the dispatch job output as fixed results: 100 PowerShell 5.1 starts (p50 110ms, max 1.83s) and 50 node starts (p50 16ms, max 0.74s), none near the 10-12s fixture deadlines. --- .../README.md | 31 ++++++++++ .../validation.json | 60 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 research/ui/results/2026-10-30-hosted-startup-latency/README.md create mode 100644 research/ui/results/2026-10-30-hosted-startup-latency/validation.json diff --git a/research/ui/results/2026-10-30-hosted-startup-latency/README.md b/research/ui/results/2026-10-30-hosted-startup-latency/README.md new file mode 100644 index 00000000..00c150cb --- /dev/null +++ b/research/ui/results/2026-10-30-hosted-startup-latency/README.md @@ -0,0 +1,31 @@ +# hosted windows-2025 的子进程启动耗时(#81/#144/#40 佐证) + +本片回答一个可测子问题:在托管镜像上,**纯进程启动**本身要多久,与 10–12 秒的固定期限相差多少。 + +## 方法 + +dispatch-only 作业 `windows-2025-startup-latency`([工作流](../../../../.github/workflows/conpty-compat.yml)): + +- `powershell.exe -NoLogo -NoProfile -NonInteractive -Command "exit 0"` × **100** 次; +- `node --version` × **50** 次; +- 每次新进程,15 秒超时,记录耗时、返回码、是否超时;统计 min/p50/p90/p99/max 与 ≥1s/≥5s/≥10s 计数。 + +## 结果(run 40935653206,windows-2025) + +| 项 | 次数 | min | p50 | p90 | p99 | max | ≥1s | ≥5s | ≥10s | 超时 | +|---|---|---|---|---|---|---|---|---|---|---| +| PowerShell 5.1 | 100 | 0.109 s | 0.110 s | 0.125 s | 1.828 s | 1.828 s | 1 | 0 | 0 | 0 | +| Node | 50 | 0.000 s | 0.016 s | 0.016 s | 0.735 s | 0.735 s | 0 | 0 | 0 | 0 | + +## 解释 + +- 空闲镜像上,PowerShell 5.1 启动中位数 **110 ms**、最慢 **1.828 s**;Node 更快(中位 16 ms、最慢 735 ms); +- 因此 `ps51` 在 CI 里出现 **10219 ms** 的 `timed_out`(#81)不能归因于启动成本;Node 夹具的 10 秒超时(#144)同理; +- 三处(ps51 10.2 s、纯 PowerShell 12 s、Node 10 s)都属于"纯启动/纯脚本、几乎无输出、刚好越过期限",与本次测得的正常分布相差 1–2 个数量级,指向**宿主级停顿**(安全扫描、VM 调度、存储阻塞)。 + +## 边界 + +- 只测空闲镜像;未在完整 CTest 同时段、安全软件扫描中或并行负载下测量; +- 未修改任何期限、夹具或准备流程; +- 不能据此断定停顿的具体来源,只排除"启动成本"这一解释; +- 与 #144 的 Node 夹具计时(warm 63 ms、冷启动 1.47 s)互相印证。 diff --git a/research/ui/results/2026-10-30-hosted-startup-latency/validation.json b/research/ui/results/2026-10-30-hosted-startup-latency/validation.json new file mode 100644 index 00000000..e6b7b0f1 --- /dev/null +++ b/research/ui/results/2026-10-30-hosted-startup-latency/validation.json @@ -0,0 +1,60 @@ +{ + "schema": "termforge-hosted-startup-latency-v1", + "issues": [ + 81, + 144, + 40 + ], + "run": 40935653206, + "job": "windows-2025-startup-latency", + "platform": "windows-2025 hosted", + "commands": { + "powershell": [ + "powershell.exe", + "-NoLogo", + "-NoProfile", + "-NonInteractive", + "-Command", + "exit 0" + ], + "node": [ + "node", + "--version" + ] + }, + "counts": { + "powershell": 100, + "node": 50 + }, + "results": { + "powershell": { + "min": 0.109, + "p50": 0.11, + "p90": 0.125, + "p99": 1.828, + "max": 1.828, + "over_1s": 1, + "over_5s": 0, + "over_10s": 0, + "timeouts": 0 + }, + "node": { + "min": 0, + "p50": 0.016, + "p90": 0.016, + "p99": 0.735, + "max": 0.735, + "over_1s": 0, + "over_5s": 0, + "over_10s": 0, + "timeouts": 0 + } + }, + "interpretation": "Pure start-up cost is 1-2 orders of magnitude below the fixed fixture deadlines, so the observed 10-12 s timeouts cannot be explained by start-up cost.", + "limitations": [ + "idle image only; not under full CTest concurrency or AV scanning", + "no deadline or fixture change", + "does not identify the stall source, only excludes start-up cost" + ], + "performance_claim": false +}