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

20 KiB
Raw Blame History

八路网页求解全流程成本评估(2026-09-11)

本轮评估上一轮结果处理优化后的当前版本,目标是分清前端预处理、后端准备与计算、结果输出、浏览器后处理的成本。使用 test-mql-8-corrected.json,没有修改生产算法、物理输入、积分精度或输出点数。此前实现与前后加速见 结果处理优化报告。

当前主要成本集中在后端数值积分和 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、frontend-cpu-statistics.json、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、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、事件采样/轮询均很小,当前不适合优先投入。

当前八路模型的阶段成本

可缩放图:cost-breakdown.svg。三个面板分别使用后端网页组、独立原生诊断组和前端网页组;前端各行存在重叠,不能相加。

数据完整性与边界

三组共 12 次网页运行全部成功,无页面错误;完整曲线、最终输出及 21,462,840 个CSV数值单元均与既有C原生结果逐值精确相等,刷新恢复一致。每次 nfev=74265、接受步6974、错误测试失败454、Jacobian计数475、线性求解准备1656、状态跳变1、求解器启动4,均与原模型一致。数值比较不含本来就变化的计时诊断。证据见 equality.json。CSV文本SHA本轮各组也相同。

本轮没有可调用的 Amesim 运行环境及同工况可靠墙钟/CPU耗时,因此不作 Amesim 速度比较;此前已记录的 Amesim 曲线差异结论保持原状。本报告是当前网页路径的性能评估,不新增曲线一致性验收结论。

前端等待与后端执行同时发生,C积分内又包含RHS、雅可比和线性求解;后台响应发送与前端接收/解码也可重叠。表中父子区间及不同线程区间不能直接相加。独立阶段中位数的和也未必等于总耗时中位数。占比需在同一次运行、同一父区间内先计算,再汇总。

文件位置

以下命令使用新的输出目录复现;已有输出目录保留原始记录,不覆盖。后台服务需各自保持运行,网页各组与原生诊断串行执行。

# 无插桩服务 / 后台分阶段服务(分别运行)
.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须与生产资产哈希相同。只重新分类现有数据可执行:

.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

原生内部诊断使用生产模型缓存和已记录的请求参数;本轮命令:

.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语法检查、离线分类自检和汇总一致性检查通过;没有为本轮只读评估重新改动生产组件或降低精度。