Files
SystemSimulationApp/docs/other/八路模型计算效率与网页阶段计时-2026-09-11.md
T
lujingze 3bc4be3c06 优化原生结果编码传输与浏览器缓存,记录八路性能基线
原生结果series通过字节索引直传,C端使用Ryu精确回读编码和64 KiB批量写出;网页采用Float64缓存和CSV工作线程,减少结果处理与保存等待。

补充八路AME曲线核查、全流程分阶段计时、独立编码基准和复现工具,固定后续优化采用修正八路及rtol=1e-8。C写出1.1808→0.1638 s,点击到可查看8.0100→6.9756 s。

验证:最终10项编码专项、29项相关后端回归通过;8份原生结果逐位一致,16次网页结果/CSV/刷新恢复通过。前端构建及缓存/CSV专项在本轮结果处理工作中通过。环境、原始大结果与临时构建不纳入Git。
2026-09-11 15:09:15 +00:00

211 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 八路模型计算效率与网页阶段计时(2026-09-11)
本轮以 `808c484` 的正式代码和 [test-mql-8-corrected.json](../../tests/data/test-mql-8-corrected.json) 为主案例。八路在当前默认精度下完整运行,未退回四路。本轮增加独立诊断脚本和运行记录,没有修改生产算法、工程参数或输出采样。后续遵循 [八路优先的优化验证约定](../standard/optimization-benchmark-model.md)。
## 运行范围与可复现条件
- 工程 SHA256:`670977bef67e62d9c66e8af497bada208bd72a7301be45128d185d47282cf288`;CLI XML SHA256:`2804b33f04cabb3c10fcc3cc0843c35de17efbe1b6ee5e5e821edd9a5515a23d`。对应 AME 为 `tests/data/test_mql.ame`,SHA256 `1ff0ea4284b9248260eeceb8b27cd0bc14dbccb43554ab8c0b49900d0b944c3d`。
- 157 元件、178 条连接、132 连续状态;返回 1784 个变量、1002 个原始采样点(含事件点),仿真 0~10 s,输出间隔 0.01 s。
- CVODE BDF / SUNDIALS 7.4.0,`rtol=1e-8`,`max_step=1e30`;自动首步。实际绝对误差限按状态生成:质量 `1e-14 kg`、内能 `1e-8 J`、速度 `1e-12 m/s`、位移 `1e-12 m`,并非对所有状态统一使用配置对象中的 `atol=1e-8`。数值雅可比、稠密线性求解和事件处理策略保持生产设置。
- Linux x86_64 虚拟机,Intel Xeon Silver 4210R @ 2.40 GHz,16 逻辑 CPU、约 30 GiB 内存;GCC 13.3.0、Python 3.12、Node 24.18.0、Chromium 151.0.7922.34。原生进程主要为单核计算,环境与构建哈希保存在原始记录。
- 各组预热一次、正式运行三次;中位数与范围单列。三算法组交错执行;网页对照组与分阶段插桩组串行执行,不同时运行诊断求解、绘图或大编译。样本数较少,组间百分之几的差异不作为显著优化结论。
## 管流算法效率与触顶情况
三算法使用同一 corrected 八路、物性复用实现和全系统积分精度。固定点版本仅在明确的 `5d5a2e1` 基线上恢复原半步松弛管流循环,其余生产数值逻辑保持一致;不是运行旧版整个应用。前次牛顿取自该提交,当前保护牛顿取自本轮正式内核。此组没有逐次调用计数插桩。
| 算法 | 纯求解中位数(范围)/ s | 进程全程中位数 / s | RHS 次数 | 接受 / 拒绝步 |
|---|---:|---:|---:|---:|
| 旧固定点,16 / 64 轮上限 | 12.0976(11.9926~12.1511) | 14.2514 | 119058 | 9647 / 679 |
| 前次牛顿 | 5.8183(5.7829~5.8944) | 7.9144 | 74265 | 6974 / 454 |
| 当前保护牛顿+二分回退 | 5.9138(5.9115~5.9323) | 7.9698 | 74265 | 6974 / 454 |
相对旧固定点,当前纯求解时间减少 **51.12%**、速度约 **2.05 倍**,进程全程减少 **44.08%**,RHS 次数减少 **37.62%**。相对前次牛顿,本组耗时增加约 1.64%,不能宣称保护机制带来额外提速;两版牛顿的完整采样、最终输出和状态逐值相同。
另用未经本轮插桩的正式构建独立运行一次预热、三次正式检查:纯求解中位数 **5.7972 s**(5.7897~5.8214),进程全程 **7.8504 s**(7.8437~7.8685),均完成 10 s;每次 RHS 74265、接受 6974、拒绝 454、雅可比 475、线性分解 1656、状态转换 1、求解器启动 4。该组构建缓存命中,输入准备 0.1493 s、构建/缓存核验 0.03294 s;这些准备时间在三个进程运行前发生一次,不包含在纯求解时间内。单独组的 5.80 s 不与上一组旧算法拼接计算加速比。
为区分算法本身和积分轨迹变化,另对三版内核进行独立计数诊断:先各自跑完整八路,再将当前轨迹的 **3,081,320 组实际管阻方程输入全部原样重放**给三个版本,不抽样、不去重。诊断耗时不用于上述性能比较。
| 同一组管阻输入的计数 | 旧固定点 | 前次牛顿 | 当前保护牛顿 |
|---|---:|---:|---:|
| 解析返回 / 迭代求解 | 0 / 3081320 | 2370685 / 710635 | 相同 |
| 累计循环轮数 | 49431317 | 3081555 | 相同 |
| 单次最多轮数 | 64 | 6 | 6 |
| 进入最后允许轮次 | 3037792(98.587%) | 0 | 0 |
| 耗尽额度且未满足各自停止条件 | 3010570(97.704%) | 0 | 0 |
| 实际返回值的统一相对残差 > 1e-9 | 3072455 | 0 | 0 |
| 二分回退 / 非有限返回 | 0 / 0 | 0 / 0 | 0 / 0 |
牛顿累计轮数减少 **93.766%**。710635 次迭代调用分别用 3 轮 74290 次、4 轮 361601 次、5 轮 236183 次、6 轮 38561 次。当前案例没有触发二分或失败路径,所以它验证了正常输入的效率和一致性,不能代替极端状态下的保护测试,也不能证明任意系统必然收敛。
“进入最后一轮”与“耗尽仍未满足条件”分开统计:固定点 PNL00R 的 64 轮分支有 1638 次进入最后一轮、但没有耗尽失败;真正耗尽的都来自其他管路的 16 轮分支。旧循环满足自身停止条件的 70750 次中,61885 次仍不满足当前统一方程残差门槛;相对残差超标不直接代表同等数量的大绝对流量误差。
各自完整积分轨迹上,旧固定点实际管阻调用 5041645 次、耗尽 4937544 次;两版牛顿均为 3081320 次、耗尽 0 次。零压差 247634 次和 PNL00R 直接层流 235766 次另计,未混入混合摩擦方程残差。当前插桩结果与独立正式构建的 `series/final/finalState` 逐值相同。
该八路在积分 RHS 中请求管流缓存 2970600 次,命中 **0**;另有 594120 次直接调用。物性复用与这项管流缓存不同;此结果只说明本例可进一步评估缓存查找的成本,不能直接推广到其他拓扑或据此删除缓存。
## 真实网页主流程与额外操作成本
使用正式 Vite 静态构建,经 Playwright 驱动 Chromium;无模拟 API、预制结果注入或重复读取响应体。独立对照服务 `127.0.0.1:8013` 不加载诊断插桩;分阶段服务 `127.0.0.1:8012` 仅在隔离 C 主程序中增加稀疏时钟,并包装实际后台函数。两个服务的求解器和元件文件逐字节相同,前端构建集合 SHA256 同为 `2faa6ce32ee9997187870d64af2bc235a830eb7b8def7749ddcb0eaeeed4831e`;计时脚本 SHA 也相同。
每组预热一次、正式三次。每轮从公开 JSON 导入入口加载同一 corrected 文件,公开导出工程后逐项验证全部参数、端点和仿真设置,然后点击运行;导入与核查不包含在点击运行计时中。每轮继续打开结果页、选择指定管路温度、下载 CSV 与结果文件,再刷新并核对恢复结果。结果页和温度曲线立即打开,允许浏览器 IndexedDB 异步保存与查看过程自然重叠。
下表单位为秒,格式为 **中位数(最小~最大)**。对照组是常规网页成本的主记录;“首次绘制机会”指可见 DOM 后经过两次 requestAnimationFrame,未测量 GPU 完成时间。
| 阶段 | 对照组 / s | 分阶段组 / s |
|---|---:|---:|
| 工程导入 change → 画布首次绘制机会 | 0.2527(0.2273~0.2862) | 0.2312(0.2251~0.2411) |
| 点击运行 → 完成状态 DOM | 9.8716(9.7697~9.8826) | 9.7777(9.7358~9.8408) |
| 点击运行 → 完成状态首次绘制机会 | 9.8989(9.7840~9.9104) | 9.8005(9.7596~9.8660) |
| 点击运行 → 结果页首次绘制机会(自动切页) | 10.1516(10.0600~10.1834) | 10.0589(10.0305~10.1056) |
| 点击运行 → 温度曲线首次绘制机会(自动选曲线) | 10.6899(10.5762~10.7431) | 10.6160(10.5916~10.6433) |
| 点击运行 → 观察到 IndexedDB 保存完成指针 | 12.2922(11.8303~12.4076) | 12.4344(11.5322~12.4967) |
| 进入结果页 → 首次绘制机会 | 0.1910(0.1893~0.1980) | 0.1927(0.1832~0.1946) |
| 选择温度 → 曲线首次绘制机会 | 0.0269(0.0262~0.0297) | 0.0276(0.0233~0.0293) |
| CSV 点击 → 下载并保存 | 5.6198(5.5717~5.6381) | 5.5732(5.4253~5.6625) |
| 结果文件点击 → 下载并保存 | 1.2308(1.2265~1.3213) | 1.2921(1.1552~1.5145) |
| 刷新导航 → 已恢复结果首次绘制机会 | 0.5885(0.5406~0.6592) | 0.5487(0.5074~0.5630) |
无插桩对照组的 C 纯求解中位数为 **6.0653 s**、进程全程 **7.9499 s**;独立 CLI 的 5.7972 s 属另一运行环境下的分组结果,不把差值直接归因于网页某项 CPU 工作。分阶段组点击到完成绘制为 9.8005 s,对照为 9.8989 s,相差约 -0.99%;本组三次样本未见明显端到端插桩增量,也不能把该负差当作加速。持久化和导出波动更大,逐次原始值均保留。
初次导航只记录每组一次:HTML `loadEventEnd` 对照 0.0971 s、分阶段 0.1086 s;Playwright 观察到工程导入控件时分别为 0.5628 / 0.6064 s,包含自动化观察与调度延迟,不是严格的首次可交互时间。首次工程导入到两帧观察点,对照预热为 0.3716 s;三次重复导入中位为 0.2527 s。页面加载、导入、仿真、查看与导出分别记录,未用自动化操作间隙拼成一个“纯网页耗时”。
“DOM 稳定”另取 120 ms 无变动再等两帧:结果页中位 0.3710 s、温度曲线 0.1736 s、刷新恢复 0.7575 s(对照)。这包含人为安静窗口,不能把它全称为渲染工作。下载完成包含 Playwright 通知、`saveAs` 与文件系统开销,不等于浏览器内序列化 CPU 时间。
## 后台内部各阶段
用每个请求的 `X-Simulation-Id` 将网页与后台记录一一关联。下表为分阶段组正式三次的秒数;所列主要阶段在单个请求内依次发生。各阶段分别取中位数,故其相加不保证等于总耗时中位数。
| 阶段 | 中位数(最小~最大)/ s |
|---|---:|
| XML 校验 | 0.0231(0.0222~0.0246) |
| 网络编译 | 0.0364(0.0361~0.0465) |
| 系统 C 代码生成 | 0.0542(0.0528~0.0548) |
| 构建缓存核验(3 次均命中) | 0.0321(0.0308~0.0331) |
| C 参数准备 | 0.0000503 |
| C 初始化与初始采样 | 0.0001(0.0001~0.0001) |
| C 纯积分 | 6.0855(6.0414~6.0994) |
| C 最终采样/状态处理 | 0.0000029 |
| C 最终及全采样输出投影 | 0.0855(0.0837~0.0861) |
| C 结果 JSON 格式化并写文件 | 1.1707(1.1656~1.1945) |
| Python 读文件并 UTF-8 解码 | 0.0360(0.0321~0.0429) |
| Python 解析原生 JSON | 0.5513(0.5429~0.5588) |
| 进程启动/等待/退出等未细分余量 | 0.0029(0.0025~0.0029) |
| 结果接口元数据组装 | 0.0330(0.0245~0.1175) |
| 最终 NDJSON 结果事件序列化 | 1.1928(1.1862~1.2106) |
| 序列化结束 → ASGI 最后响应体发送完成 | 0.1715(0.1489~0.1808) |
| HTTP 其余编排/调度余量 | 0.0124(0.0114~0.0155) |
后台 HTTP 全程中位 **9.5123 s**(9.4458~9.5845)。内部 C main 全程 7.3380 s,Python 原生执行与结果读取包装 7.9194 s,仿真 worker 全程 8.1380 s;这些是包含上表子阶段的父区间,**不能再次相加**。ASGI `send` 的累计 await 为 0.0701 s,可与生成结果的后台任务重叠,亦不代表客户端网络总时间。诊断产物保留另耗约 0.00066 s,已包含在原生执行包装中。
约 **2.95 s** 用于 C 的 JSON 写出、Python 读取解析及 HTTP 结果 JSON 序列化,约为后台总程的 31%;相比之下输出物理量投影仅约 0.086 s。这里先定位到文本结果处理成本,并未将整个差额笼统归为物性或求根。
正式网页八次运行均复用已构建的程序。唯一冷构建来自功能预检:编译/核验 **3.4154 s**,构建键 `bcb85b5dce729fe9b7a503919b720be03950ff31839877edd344377d4ee9cfc0` 与后续完整八路分阶段组相同;预检将运行终点设为 0.02 s,只改变运行时选项,未改变编译出的系统程序。这个单次冷编译时间可供首次运行成本参考,但本轮没有测得完整 0~10 s 的冷启动网页总时间,不把预检总时间冒用为正式结果。
## 浏览器内部、持久化和导出细分
分阶段组保留了原始 `fetch`、流读取、解码、JSON.parse、IndexedDB 事务和下载锚点的时间戳,没有克隆响应或重复解析。
| 观察区间 | 中位数 / s | 含义与边界 |
|---|---:|---|
| 点击运行 → 调用 fetch | 0.0234 | 含前端模型检查、快照/XML 和提交准备,未单独计 XML CPU |
| fetch → 收到响应头 | 0.0298 | 收到流式响应头,不表示仿真已经算完 |
| 响应头 → 读到流 EOF | 9.6765 | 包含后台计算、传输、消费者处理与调度 |
| 累计未完成的流 read 等待 | 9.4636 | 含后台结果尚未生成的等待,不能称为纯网络时间 |
| 最终结果的原始 JSON.parse | 0.1125 | 同步解析仅执行一次 |
| 全部流消息 JSON.parse | 0.1139 | 已含上一行 |
| UTF-8 decode 累计 | 0.0280 | 原始解码调用,不包含分片扫描/拼接 |
| 最终 JSON.parse 结束 → 完成 DOM | 0.0430 | 含应用处理和 React 调度,未独立测 React CPU |
| 结果解析结束 → IndexedDB 完成指针发布 | 2.6279 | 含批处理、事务等待与调度,可与看图重叠 |
| 首次保存事务 → 完成指针发布 | 2.5952 | 仍是异步区间;不是磁盘或主线程独占时间 |
| CSV 点击 → fetch | 0.2641 | 包含将整份结果再次 JSON.stringify 的提交准备 |
| CSV fetch → 响应头 | 4.6968 | 含浏览器请求准备、后台处理及网络/调度 |
| CSV 点击 → Blob 下载锚点 | 5.0143 | 浏览器已经取得并准备好下载数据 |
| 结果文件点击 → Blob 下载锚点 | 0.6113 | 包含结果文件序列化及 Blob 准备 |
最终流式响应约 **33.73 MB**;原生结果 JSON 为 32,725,293 字节,CSV 为 32,346,795 字节,结果文件约 33.85 MB(十进制 MB)。本次是本机回环 HTTP,未模拟远端带宽、TLS 或网络延迟;不能把这些网络相关耗时直接推广到远端部署。
CSV 后台另有独立请求,按请求顺序和时间戳关联,正式三次分段如下:
| CSV 后台阶段 | 中位数(最小~最大)/ s |
|---|---:|
| ASGI 开始 → 收完请求体 | 0.0262(0.0247~0.0285) |
| 收完请求体 → CSV 函数开始 | 0.7072(0.7010~0.7138) |
| CSV 校验、逐单元格式化与文本组装 | 2.3684(2.3616~2.3885) |
| CSV 函数结束 → HTTP 完成 | 0.1252(0.1221~0.1264) |
| CSV HTTP 全程(父区间) | 3.2264(3.2177~3.2494) |
“收完请求体→CSV 函数”约 0.707 s,涵盖路由层 JSON 解码、模型校验及调度,未再将每项 CPU 时间拆开。CSV 浏览器 fetch 到响应头比 ASGI 全程更长;跨进程请求准备、发送及调度的余量未进一步归因。CSV 的完整结果往返及文本组装成本已经实测,后续可据此单独优化。
## 本轮验证与下一步优先级
两组共 **8 次**网页运行均完成 10 s,且无 `pageerror`。每轮公开导出的工程参数与连接全部匹配固定输入;结果页、精确单位 K 的温度曲线、CSV、`.simresult` 下载和刷新恢复均通过。8 份 CSV 均为 1785 列 × 1002 数据行,合计 **14,308,560 个数值单元**与独立原生结果精确相等;全部 `series/final` 也精确相等,刷新前后完整结果一致。4 份后台稀疏插桩原生文件的 `series/final/finalState` 均与生产文件逐值相同。56 个唯一气体质量状态用 `math.fsum` 汇总,初始总质量 5.566893015 kg,最大漂移 **1.15463e-14 kg**;所有保存数值有限。
初次自动化预检曾误用旧控制台 CSS,另一次重复组在刷新后假定建模工程自动恢复而未提交新请求。这两类脚本失败保存在 `browser-stage-smoke/` 与 `browser-control-failed/`,明确排除正式统计。最终脚本使用当前 DockedSimulationConsole、每轮重新导入并核对工程,两个完整正式组均通过。0.02 s 的功能预检只证明操作流程,不混入八路完整计算效率。
依据本轮数据,后续优先考虑:
1. **先追踪八路早期压力/温度差和碰撞事件输出。** 参数对齐与局部求根成功不能代替整条曲线正确性;保留八路主案例,继续固定当前输入与精度。
2. **减少结果反复文本化。** 当前 C 写 JSON、Python 再解析、HTTP 再序列化合计约 2.95 s;优化这条路径时仍需保留全部变量、采样、浮点数值与输出合同。
3. **单独优化 CSV 与浏览器持久化。** CSV 全量回传后台并组装文本明显影响使用时间;持久化约 2 s 以上、且与查看曲线重叠,适合分别评估批大小、复制与调度,不能把保存等待计为绘图耗时。
4. **继续剖析 RHS/雅可比等求解成本。** 管流触顶已经为零,当前再削减迭代上限没有实测依据。可先评估本例零命中的管流缓存和 74265 次 RHS 的组成;更改雅可比或缓存策略后仍按同一八路、同精度和完整输出复核。
![八路算法与网页阶段耗时](assets/2026-09-11/mql8-efficiency-20260911-stage-costs.png)
图中三算法与浏览器操作取三次中位数;后台堆叠图选 HTTP 总耗时居中的单个请求,所有片段可相加。浏览器各操作区间不能相加;完整可缩放图为 [SVG](assets/2026-09-11/mql8-efficiency-20260911-stage-costs.svg)。
## 与当前 Amesim 归档的对照
本次找到可用的八路保存曲线。独立核对当前 AME 内的图纸、参数数据、编译 C、状态与变量索引及初值,未发现此前四路归档中那种图纸/缓存错配;完整说明见 [当前八路归档与曲线核查](test-mql-8当前AME归档与完整曲线核查-2026-09-11.md)。使用的是当前 AME SHA,未套用绑定另一归档的历史八路冻结基准。
选取全部 132 个连续状态对应的压力、温度、位移与速度,另加阀流量、接触力、限位力和间隙,共 **176 条曲线**;明确映射表压/绝压、SI 单位与接口方向,分别在双方原始保存网格上线性插值对照,不删去原生事件点。下表为 AME 保存网格上各类最差曲线的最大差及该曲线 RMS,不是把全类所有点混算的 RMS。
| 量 | 最大绝对差 | 对应曲线 RMS |
|---|---:|---:|
| 压力 | 163395.189 Pa | 7170.441 Pa |
| 温度 | 105.215279 K | 5.829065 K |
| 阀质量流量 | 0.002990901 kg/s | 0.000114014 kg/s |
| 接触力(AME 保存网格) | 5131.971 N | 225.218 N |
最大压力、温度和此表接触力差在 0.01 s,不能全归因于后续碰撞采样时刻不一致。原生另有 `t=0.9833956321732664 s` 的原始事件点,8 个接触力约 **4.035×10¹¹ N**;AME 只保存相邻 0.98 / 0.99 s 点,无法据其线性插值判断 Amesim 精确事件时刻或是否也有极窄峰。当前 AME 的 UD00 输入含 `1e17` 初始信号,双方公共质量元件都出现极大位移/速度,也不能把“数值有限”当成物理合理性证明。本轮未修改这些 AME 参数。
因此,**八路运行与计时记录完成,不等于八路曲线一致性验收通过**。目前没有八路专用接受阈值,也缺少足够密的 AME 事件输出;保留差异供后续核查,不为通过而放宽门槛或换四路。
Amesim **耗时对比跳过**:当前环境没有可调用的 Amesim,归档也没有可信 CPU/墙钟记录;`.ameperf` 中的时间是仿真事件时刻。归档名义容差为 `1e-7`,本轮为 `1e-8`,也不能冒称同精度速度比较。没有重跑 Amesim,没有从 10 s 仿真终点或文件时间戳推算耗时。
## 记录、脚本与复现
所有输入快照、编译程序、完整曲线、下载文件和浏览器截图都放在 Git 忽略目录 `test/`,环境仍在 `.venv/native/`,未纳入 Git。报告引用的相对路径在仓库本地可打开;这些大型运行产物不随 Git 克隆传递。
- [三算法原始基准](../../test/mql8-efficiency-20260911/native-benchmark/summary.json)、[三算法汇总](../../test/mql8-efficiency-20260911/native-summary.json)、[正式构建独立基准](../../test/mql8-efficiency-20260911/native-production/summary.json)。
- [完整管阻计数与同输入重放](../../test/solver-newton-20260911/pipe-iteration-profile-8/summary.json)、[插桩与生产逐值核对](../../test/solver-newton-20260911/pipe-iteration-profile-8/production-parity.json)。
- [阶段汇总 JSON](../../test/mql8-efficiency-20260911/stage-summary.json)、[阶段汇总 CSV](../../test/mql8-efficiency-20260911/stage-summary.csv)、[网页对照组](../../test/mql8-efficiency-20260911/browser-control/summary.json)、[网页分阶段组](../../test/mql8-efficiency-20260911/browser-profiled/summary.json)。
- [网页与 CSV 全量相等核查](../../test/mql8-efficiency-20260911/equality.json)、[后台插桩逐值核查](../../test/mql8-efficiency-20260911/backend-profile-production-parity.json)、[质量守恒](../../test/mql8-efficiency-20260911/mass-conservation.json);每个后台请求在 `test/mql8-efficiency-20260911/backend-profile/requests/<simulationId>/` 保存执行 XML、原生 JSON、日志和阶段时间。
- [后台分阶段诊断脚本](../../tests/manual/backend_stage_profile.py)、[真实浏览器计时脚本](../../tests/manual/browser_stage_profile.mjs)、[管阻计数脚本](../../tests/manual/profile_pipe_iterations.py)。[网页结果复核脚本](../../tests/manual/compare_browser_stage_outputs.py)。这些都是手动诊断入口,生产服务无需加载。
```bash
# 八路三算法基准;目录必须为新目录
.venv/bin/python tests/manual/benchmark_native_pipe_solver.py \
tests/data/test-mql-8-corrected.json --output-dir test/new-mql8-variants --runs 3
# 正式构建独立基准
.venv/bin/python -m app.simulation.native_codegen tests/data/test-mql-8-corrected.json \
--output-dir test/new-mql8-production --runs 3 --timeout 120
# 后台阶段记录服务;需要已有 frontend/dist,选空闲端口
.venv/bin/python tests/manual/backend_stage_profile.py \
--output-dir test/new-mql8-backend --port 8012
# 另一个终端:--plain 为无诊断插桩的对照服务
.venv/bin/python tests/manual/backend_stage_profile.py --plain \
--output-dir test/new-mql8-control --port 8013 \
--frontend-dist test/new-mql8-backend/frontend
# Chromium 所需依赖仅使用仓库现有忽略环境
export LD_LIBRARY_PATH="$PWD/.venv/native/browser-libs/usr/lib/x86_64-linux-gnu${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
.tools/node-v24.18.0-linux-x64/bin/node tests/manual/browser_stage_profile.mjs \
--output test/new-mql8-browser-control --url http://127.0.0.1:8013 --mode control --runs 3
.tools/node-v24.18.0-linux-x64/bin/node tests/manual/browser_stage_profile.mjs \
--output test/new-mql8-browser-profiled --url http://127.0.0.1:8012 --mode profiled --runs 3
```