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
20 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)
本轮评估上一轮结果处理优化后的当前版本,目标是分清前端预处理、后端准备与计算、结果输出、浏览器后处理的成本。使用 [test-mql-8-corrected.json](../../tests/data/test-mql-8-corrected.json),没有修改生产算法、物理输入、积分精度或输出点数。此前实现与前后加速见 [结果处理优化报告](八路结果处理与网页保存优化-2026-09-11.md)。
**当前主要成本集中在后端数值积分和 C 结果写出。** 无插桩正式三次中位数:点击运行到结果可查看 **7.99 s**,到浏览器保存完成 **8.11 s**。分阶段组内逐次计算,积分占点击到可查看时间约 **76.4%**,C结果编码与写出占约 **14.8%**。前端点击后的预处理仅约 **19.6 ms**,不属于当前优先优化的大项。
## 测量条件与可复现证据
- 模型 SHA256 为 `670977bef67e62d9c66e8af497bada208bd72a7301be45128d185d47282cf288`;157 元件、178 条连接、132 状态,1784 输出变量和时间列,1002 个原始采样。
- 0~10 s,输出间隔0.01 s,CVODE BDF,`rtol=1e-8`、`max_step=1e30`,状态绝对误差下限保持原值;事件和采样策略均不变。
- Git 基线 `808c484` 加上一轮尚未提交的结果处理优化。所有上一轮生产源码清单中的文件哈希一致;本轮只增加/完善手动测量工具与报告。环境继续使用已有 `.venv`、`.venv/native`、Node24.18.0、Chromium151.0.7922.34;没有安装新依赖。
- 使用真实生产页面,经本机回环 HTTP 提交。每轮公开导入、导出并核对八路工程参数、连接和仿真配置,再点击运行,进入结果页显示温度曲线,保存 CSV 和结果文件,刷新恢复。
- 无插桩组、分阶段组各预热一次、正式三次;串行运行,计时期间不安排大型构建、其他仿真或全量文件比对。端到端体验以无插桩组为准。分阶段组用于定位成本,不把其耗时套入无插桩组拆账。
- 分阶段后台只在隔离的 C `main.c` 副本增加少量墙钟/CPU时钟,数值实现未改;Python 包装原函数,观察子进程创建、退出及实际读取/响应边界,不额外轮询。C写出 CPU 时钟包括用户态和内核态,不能单独区分格式化、内存访问与系统调用。
- 分阶段网页包装原有 fetch、reader、decoder、JSON.parse、IndexedDB 和 Worker 调用,保持每份响应仅读取、解码和解析一次。另有独立 CDP CPU 采样诊断,不混入正式端到端结果。
“结果可查看”指页面观察到成功完成且运行按钮恢复可用;“绘制机会”指再经过两次 requestAnimationFrame,不等于直接测得 GPU 绘制时间。“浏览器保存完成”指实际 IndexedDB 事务提交后发布恢复指针;无插桩组通过16 ms轮询观察,含调度延迟。“下载保存完成”包括 Playwright 通知及 `saveAs` 的文件系统成本。
## 网页端到端体验
下表为无插桩组预热后三次中位数及范围,单位秒。导入工程发生在点击运行之前,不计入仿真总耗时。
| 用户过程 | 中位数(最小~最大)/ s |
|---|---:|
| 点击运行 → 结果可查看 | 7.992(7.927~8.104) |
| 点击运行 → 完成状态绘制机会 | 8.015(7.944~8.122) |
| 点击运行 → 浏览器保存完成观察 | 8.108(8.043~8.218) |
| CSV点击 → 下载保存完成 | 0.912(0.884~0.984) |
| 结果页签点击 → 绘制机会 | 0.193(0.181~0.240) |
| 温度变量点击 → 曲线绘制机会 | 0.029(0.028~0.029) |
| 刷新 → 结果绘制机会 | 0.437(0.427~0.452) |
| 结果文件点击 → 下载保存完成 | 1.154(1.033~1.223) |
工程导入到绘制机会为 0.238(0.231~0.247) s。三次完整运行的 C 纯求解中位数为 6.143 s;每次均完成10 s物理区间。
首次打开无插桩页面至自动化确认导入控件已附加约0.530 s,属于一次独立导航观察,含自动化确认延迟;不等同首帧或完整应用就绪时间,未计入上面的点击运行用时。
## 前端预处理、接收与后处理
分阶段组三次正式运行;所有值为毫秒。各行可能重叠。
| 过程 | 中位数(最小~最大)/ ms | 口径 |
|---|---:|---|
| 点击→提交fetch:校验、快照、XML和请求准备 | 19.6(18.8~31.9) | 毫秒;同步预处理与提交设置的整体窗口 |
| fetch→响应头可供读取 | 29.9(28.7~30.0) | 毫秒;包括请求处理、传输和浏览器调度 |
| 流UTF-8解码同步调用之和 | 32.2(30.8~33.0) | 毫秒;与接收过程重叠 |
| 最终结果JSON.parse | 107.0(105.5~119.6) | 毫秒;原始单次同步解析 |
| 解析结束→完成DOM | 48.2(42.4~58.2) | 毫秒;发布状态、渲染准备与调度 |
| 进入结果页→绘制机会 | 182.0(181.1~196.7) | 毫秒;包含系统图准备 |
| 温度曲线选择→绘制机会 | 35.7(34.4~36.3) | 毫秒;单条温度曲线 |
| 最后分块交付→开始解析 | 36.6(33.3~45.3) | 含最后一次解码、扫描、拼接、trim及调度,不能全归于join |
| 解析结束→缓存指针发布 | 135.5(127.0~176.5) | 包含数据打包、让出主线程、数据库打开/提交、页面工作 |
| 保存事务窗口(每次1次) | 63.1(50.0~84.5) | 包含同步提交及异步等待,是上一行子区间 |
从最后一次分块交付到完成DOM为 197.0(191.8~207.3) ms;这比整段 headers→EOF 更接近最终结果到达后的页面处理窗口。后者约 7.866 s,绝大部分与后台执行同时发生,不能称为前端解析用时。
CSV 点击到 Blob 下载触发为 494.9(487.4~495.9) ms;Worker start→finish投递为 77.3(69.1~86.2) ms,finish投递→完成消息到达为 382.9(377.8~386.7) ms。前一段主线程分批准备与Worker执行重叠,后一段包含Worker编码/Blob生成/消息投递和调度。没有单独测量Worker线程CPU。CSV完整下载体验仍以无插桩组为准。
### 主线程 CPU 采样补充
另对真实页面做1 ms间隔的CDP主线程采样,预热一次、正式三次。使用临时生成的hidden source map映射回源码;临时构建的JS与实际服务的生产JS逐字节一致,未替换页面资产。采样组点击→可查看中位8.152 s,独立于上面的无插桩/分阶段组。下表为采样归属估计,精度受约1 ms采样与时钟校准误差限制,不能当作逐函数秒表。
| 观察窗口 | 可识别的主要工作,采样归属中位 / ms |
|---|---|
| 点击→fetch(该诊断组27.1 ms) | 模型校验15.0;XML构造7.8;XML原生序列化2.3;项目快照1.2;端点/合同处理1.1 |
| 响应头→大结果开始解析 | NDJSON扫描/拼接/分发40.2;UTF-8解码29.2;React更新69.3;其余含进度显示和测量工作 |
| 大结果解析开始→保存指针(255.3 ms) | JSON解析归属103.5;IndexedDB请求提交62.2;打包/保存逻辑11.3;React7.9;GC12.7 |
| 进入结果页→绘制机会(207.6 ms) | React运行时77.7;ReactFlow系统图52.6;结果视图数据准备9.3;系统图几何处理5.9 |
| 选择温度→曲线绘制机会(28.4 ms) | 结果视图8.0;React7.1;曲线数据准备2.6 |
| CSV点击→文件保存 | 主线程分批准备和传输36.6;其余可识别主线程工作包括视图与React;不含Worker线程CPU |
IndexedDB“请求提交”类别包含相应JS调用下的原生同步处理,不代表后台磁盘线程耗时。CPU样本中的JSON解析归属与同步wrapper实测是两种观察,不能相加;其余分类和不同窗口也不能直接相加成总耗时。
响应头到最终结果解析前约7.947 s的窗口,采样明确空闲约5.592 s,V8 `(program)` 未归属约2.086 s,可识别JS及其下原生调用约0.265 s。其中仍有约0.127 s未归到具体业务函数,含DOM观测/自动化;**不能把2.086 s未知时间或整段7.947 s计作前端业务CPU**。GC、idle、program、unknown-runtime单列,函数active统计排除这些样本。
结果页准备比单条温度曲线的数据准备更显著;采样主要落在React/ReactFlow与DOM操作,不足以将其直接称为GPU绘制耗时。刷新恢复另有独立profile,使用刷新后的document时间轴。
采用离线修订的v2分类,不使用会混淆系统样本的初始汇总字段。证据:[cpu-resummary-v2.json](../../test/web-cost-20260911/browser-deep/cpu-resummary-v2.json)、[frontend-cpu-statistics.json](../../test/web-cost-20260911/frontend-cpu-statistics.json)、[sourcemap-verification.json](../../test/web-cost-20260911/sourcemap-verification.json)。原始 `.cpuprofile`、`trace.json` 与网页计时结果均保持原样。
## 后端准备、求解、输出与响应
分阶段组三次正式运行;单位秒。包含“其中”的行是父区间子项,不应重复累计。
| 阶段 | 中位数(最小~最大)/ s |
|---|---:|
| XML校验 | 0.0225(0.0220~0.0236) |
| 网络编译:组件和连接 | 0.0372(0.0365~0.0454) |
| C模型代码生成 | 0.0601(0.0540~0.0863) |
| 构建缓存校验(命中) | 0.0349(0.0341~0.0417) |
| 子进程创建Popen调用 | 0.0006(0.0006~0.0007) |
| C初始状态和首样本准备 | 0.0001(0.0001~0.0001) |
| C数值积分,含求解器内部工作 | 6.0645(6.0614~6.1547) |
| 输出投影:由状态计算全部输出 | 0.0852(0.0852~0.0861) |
| C结果JSON及索引格式化/写出 | 1.1752(1.1620~1.1862) |
| Python结果索引读取、校验和片段整理 | 0.0440(0.0334~0.0466) |
| 其中:原始结果文件读字节 | 0.0230(0.0112~0.0254) |
| 其中:小索引和元数据JSON解析 | 0.0012(0.0011~0.0015) |
| 响应元数据组装 | 0.0164(0.0164~0.0175) |
| 响应包装:元数据编码与字节片段组织 | 0.0354(0.0340~0.0357) |
| ASGI send累计await | 0.0794(0.0396~0.0845) |
| 后台HTTP总窗口(父区间) | 7.6916(7.6678~7.7199) |
XML校验、网络编译、C代码生成、缓存检查的同次合计为 0.1630(0.1565~0.1789) s。C初始状态准备只包含 `model_init` 和首样本,CVODE对象创建、初始化和重启仍属于积分区间。
C输出投影CPU为 0.0852(0.0851~0.0860) s;JSON写出CPU为 **1.1749(1.1619~1.1859) s**,与墙钟 1.1752 s 几乎一致。这支持优先调查数值格式化、逐值stdio调用和内存访问;不能将整段1.18 s称为磁盘等待,也不能把CPU/墙钟差直接当成测得的I/O耗时。
响应数值原始片段约32.64 MB,整条HTTP响应约34.48 MB,CSV约31.82 MB(十进制MB)。当前后端已避免Python大数组解析/重编码,但C逐值 `fprintf("%s%.17g", …)` 的成本仍保留。
`processWallSeconds` 包括退出后的Python结果读取;本轮另记录子进程从创建到已有poll/wait首次观察到退出的寿命,不能混称C求解时间。ASGI send窗口也不是纯网络耗时;本机回环测试不代表远端网络。
**首次编译单独记录:** 分阶段组首轮缓存未命中,构建耗时 **3.446 s**,点击到可查看 **11.447 s**。这是一次冷构建观察,不纳入三次缓存命中的正式中位数,也不当成稳定冷启动统计。修改会影响生成代码的模型内容后,可能重新发生该成本。
### 积分内部的计算分布
另做独立原生诊断:复用真正生产缓存可执行文件作control,隔离副本只在调用边界增加嵌套时钟并读取CVODE计数。每个变体预热一次、正式三次,交替串行运行;不是在网页中再开第二个求解任务。
表中为**排他墙钟时间**,同一次运行中已扣除子调用;每次所有排他区间之和精确等于积分父区间。中位数列来自三次运行,不再相加假装某次总耗时。
| 积分内部工作 | 排他时间中位 / s | 同次积分占比的中位数 |
|---|---:|---:|
| 模型RHS:物性、管流局部求根及组件方程等全部模型求值 | 5.559250 | 93.7191% |
| Dense矩阵分解 | 0.180638 | 3.0452% |
| Dense线性方程回代求解 | 0.110131 | 1.8620% |
| CVODE剩余内部工作(已扣RHS、poll、Dense) | 0.069325 | 1.1660% |
| 超时/取消/进度轮询 | 0.007586 | 0.1279% |
| 积分外层准备、循环和清理余量 | 0.001608 | 0.0272% |
| 接受步与事件处理自身(已扣采样和插值) | 0.001412 | 0.0237% |
| 保存采样状态 | 0.000806 | 0.0136% |
| 稠密输出插值 | 0.000293 | 0.0049% |
诊断积分中位 **5.931924 s**,配对生产control为 **5.874992 s**;逐对计算的插桩增幅中位约 **0.91%**(0.68%~1.71%)。原始summary的 `instrumentationOverheadFraction` 采用两组中位数之比,估计为0.97%;两者计算口径不同。此处为独立进程诊断,其绝对耗时不直接替代网页组的6.06 s;用作积分内部占比定位。时钟/统计维护成本仍在诊断结果中。
**关键发现是雅可比所需的方程求值次数。** 每次实际读取CVODE统计均为:
| 计数 | 实测值 |
|---|---:|
| 常规RHS求值 | 11,565 |
| 线性求解器有限差分RHS求值 | 62,700 |
| 合计模型RHS | 74,265 |
| 雅可比计算次数 × 状态数 | 475 × 132 = 62,700 |
| 非线性迭代 / 非线性收敛失败 | 11,557 / 414 |
| Dense分解 / 线性回代调用 | 1,656 / 11,557 |
| 分段计数 / 求解器启动 | 4 / 4 |
有限差分占全部RHS**调用次数的84.43%**。结合全部RHS耗时占积分的93.72%,应优先研究如何减少重复模型求值。没有单独计时“差分RHS子集”,不能据此声称差分恰好占84.43%的积分时间,更不能承诺减少同等比例的总耗时。Dense代数自身合计约4.91%,单独更换矩阵分解实现的潜在收益较受限;雅可比结构改变带来的RHS次数减少属于另一项收益。
414是CVODE本级非线性收敛失败计数,后续通过重试完成仿真,不是管路局部Newton达到上限的次数。本轮未继续拆分RHS中的物性、管路求根和组件方程,不能将5.56 s全部归给管路求根。
所有8次原生运行的完整series、final、finalState和求解计数(只排除两个solve计时字段)与生产control精确一致。工具和原始证据:[native_compute_profile.py](../../tests/manual/native_compute_profile.py)、[native-compute-profile/summary.json](../../test/web-cost-20260911/native-compute-profile/summary.json)。
## 下一步优化顺序
1. **计算核心:验证减少雅可比差分所需RHS求值。** 研究生成模型的状态依赖结构、可复用的导数和稀疏差分/着色方案;保持当前精度、事件与物理参数,单独验证全曲线和守恒。这是本轮看到的最大计算成本来源,但尚未实现或证明某种替代方案的收益。
2. **结果处理:优先优化C数值编码与写出。** 当前仍约1.18 s,明显大于Python读回和网页JSON解析。可比较更高效且精确回读的数值编码、批量输出,或直接数值缓冲传输;需保留原始采样和数值精度。本轮没有改变传输合同。
3. **前端后处理:针对结果解析和缓存提交做小幅改进。** JSON.parse约0.11 s,数据打包/IDB提交约0.1 s量级;若优先改善主线程响应,可研究转移解析、减少数组复制。预期端到端空间小于上面两项,收益需实测。
4. **模型编辑后的首次运行:单独调查构建缓存。** 本轮冷构建一次约3.45 s;若用户经常改参数/拓扑导致缓存失效,应单独分析编译单元复用和参数是否必须进入生成代码,不能只看缓存命中数据。
5. **前端预处理和小项暂缓。** 点击后的整体准备约20 ms;Python元数据解析约1 ms、进程启动不足1 ms、事件采样/轮询均很小,当前不适合优先投入。
![当前八路模型的阶段成本](assets/2026-09-11/web-cost-20260911-cost-breakdown.png)
可缩放图:[cost-breakdown.svg](assets/2026-09-11/web-cost-20260911-cost-breakdown.svg)。三个面板分别使用后端网页组、独立原生诊断组和前端网页组;前端各行存在重叠,不能相加。
## 数据完整性与边界
三组共 **12 次网页运行**全部成功,无页面错误;完整曲线、最终输出及 **21,462,840 个CSV数值单元**均与既有C原生结果逐值精确相等,刷新恢复一致。每次 `nfev=74265`、接受步6974、错误测试失败454、Jacobian计数475、线性求解准备1656、状态跳变1、求解器启动4,均与原模型一致。数值比较不含本来就变化的计时诊断。证据见 [equality.json](../../test/web-cost-20260911/equality.json)。CSV文本SHA本轮各组也相同。
本轮没有可调用的 Amesim 运行环境及同工况可靠墙钟/CPU耗时,因此不作 Amesim 速度比较;此前已记录的 Amesim 曲线差异结论保持原状。本报告是当前网页路径的性能评估,不新增曲线一致性验收结论。
前端等待与后端执行同时发生,C积分内又包含RHS、雅可比和线性求解;后台响应发送与前端接收/解码也可重叠。表中父子区间及不同线程区间不能直接相加。独立阶段中位数的和也未必等于总耗时中位数。占比需在同一次运行、同一父区间内先计算,再汇总。
## 文件位置
- 本报告:[八路网页求解全流程成本评估-2026-09-11.md](八路网页求解全流程成本评估-2026-09-11.md)。
- 全部原始产物:[test/web-cost-20260911/](../../test/web-cost-20260911/),此目录被 Git 忽略。
- 无插桩网页记录:[browser-control/summary.json](../../test/web-cost-20260911/browser-control/summary.json)。
- 分阶段网页记录:[browser-profiled/summary.json](../../test/web-cost-20260911/browser-profiled/summary.json);各轮目录有 `trace.json`、`restore-trace.json`、结果、CSV与截图。
- 后端记录:[backend-profiled/requests/](../../test/web-cost-20260911/backend-profiled/requests/),以网页记录的 `simulationId` 关联;每项有真实输入XML、C原始结果、worker日志和 `stages.json`。
- 汇总:[summary.json](../../test/web-cost-20260911/summary.json)、[timings.csv](../../test/web-cost-20260911/timings.csv);源码与环境:[source-manifest.json](../../test/web-cost-20260911/source-manifest.json)。
- 手动工具:[backend_stage_profile.py](../../tests/manual/backend_stage_profile.py)、[browser_stage_profile.mjs](../../tests/manual/browser_stage_profile.mjs)、[summarize_web_cost.py](../../tests/manual/summarize_web_cost.py)。
以下命令使用新的输出目录复现;已有输出目录保留原始记录,不覆盖。后台服务需各自保持运行,网页各组与原生诊断串行执行。
```bash
# 无插桩服务 / 后台分阶段服务(分别运行)
.venv/bin/python tests/manual/backend_stage_profile.py --plain --port 8024 --output-dir test/web-cost-repeat/backend-control
.venv/bin/python tests/manual/backend_stage_profile.py --port 8023 --output-dir test/web-cost-repeat/backend-profiled
# 网页组:先control,然后profiled;各预热1次、正式3次
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 --url http://127.0.0.1:8024 --output test/web-cost-repeat/browser-control --mode control --runs 3
.tools/node-v24.18.0-linux-x64/bin/node tests/manual/browser_stage_profile.mjs --url http://127.0.0.1:8023 --output test/web-cost-repeat/browser-profiled --mode profiled --runs 3
.venv/bin/python tests/manual/summarize_web_cost.py --root test/web-cost-repeat
```
深度采样增加 `--deep --cpu-interval-us 1000 --source-map-dir PATH`,使用独立输出目录;source map的生成JS须与生产资产哈希相同。只重新分类现有数据可执行:
```bash
.tools/node-v24.18.0-linux-x64/bin/node tests/manual/browser_stage_profile.mjs --summarize-cpu-only test/web-cost-20260911/browser-deep --source-map-dir test/web-cost-20260911/frontend-sourcemaps/assets
```
原生内部诊断使用生产模型缓存和已记录的请求参数;本轮命令:
```bash
.venv/bin/python tests/manual/native_compute_profile.py \
--cache-dir app/data/native-builds/00a1cc841fb4496044c99e13066bbd18784aef134893c3c30b5b984c7aef8eec \
--request-stages test/web-cost-20260911/backend-profiled/requests/e18c2e0e-b2e7-4219-9f5a-c09a26cde4fa/stages.json \
--output-dir test/native-cost-repeat --run --warmups 1 --repeats 3
```
原生工具目前针对Linux/GCC;所有新产物均位于已忽略的 `test/` 中。手动工具Python语法检查、Node语法检查、离线分类自检和汇总一致性检查通过;没有为本轮只读评估重新改动生产组件或降低精度。