11 KiB
SystemSimulationApp 仿真性能评估(2026-08-15)
代码基线:
model-development@6a06489,随后只加入本报告所述的可选埋点和基准工具。 本次评估的是前端流式接口实际使用的 System XML 求解路径;所有时间均为本机实测,不代表其他机器的绝对性能。
1. 结论
- 压力—流量闭合是当前首要热点。 深度审计中,三个气动短算例有 71%~85% 的计时落在
PressureFlowSolver.solve()的包含时间内。它同时包含残差组装及其触发的物性调用,不能与物性时间相加。 - 物性调用存在很高的完全相同输入重复率。 按每次代数闭合重置精确输入影子集合后,空气链路、空气分支和氦气阶跃的重复率分别为 91.2%、96.5% 和 82.3%。空气公式很便宜,不能只凭重复率加缓存;Peng–Robinson 氦气更值得优化。
- 现有两项氦气 LRU 精确缓存有效。 冷缓存审计中,
properties_from_mU命中率 95.5%,temperature_from_pressure_enthalpy命中率 78.6%;21 次配对端到端测试中,暖缓存比每次清空缓存快约 7.9%。这些缓存已经存在于评估基线,本次没有新增或改变缓存算法。 - 长仿真的时间主要花在积分阶段。 10 s 氦气均压算例耗时约 10.6~11.5 s,其中标准埋点测得积分占 90.5%,初始化约 4.2%,逐采样点后处理约 5.0%。
- 结果 JSON 暂不是这些算例的首要矛盾。 四个短算例的最终 NDJSON 结果约 29~59 KiB,编码中位数约 0.4~1.2 ms;501 个采样点的长算例约 507 KiB,编码约 18.5 ms。
- 首次仿真有明显冷启动。 新 Python 进程第一次短算例约 0.71 s,预热后同类算例约 0.06~0.13 s。剖析表明首次进入 SciPy 求解路径的惰性导入占了主要差额;这是服务首请求延迟,不是稳态吞吐。
- 用户提供的 demo XML 尚不能形成完整性能样本。 它仍在
0.000175 s左右因Initial guess is outside of provided bounds失败;深度埋点确认错误发生在压力—流量闭合。本批只记录失败路径,没有顺带改变求解器容错行为。
2. 埋点实现与污染控制
性能开关由进程启动环境变量 SIMULATIONAPP_PROFILE 决定:
| 模式 | 用途 | 记录内容 | 适合场景 |
|---|---|---|---|
off |
正常运行,默认值 | 不在响应中加入性能数据;装饰器在模块加载时直接返回原函数 | 正式仿真和最终性能对比 |
standard |
低开销阶段统计 | XML 校验、网络编译、系统构造、初始化、积分、后处理、结果组装 | 日常定位“大阶段” |
audit |
深度审计 | 再展开 RHS、代数闭合、压力流量、stream、刷新、导数和物性内核 | 短算例诊断、调用频率与缓存评估 |
一次运行使用一个 ContextVar 隔离的 PerformanceTrace,不会把不同仿真任务的阶段计数混在一起。成功或失败的求解结果在 profiling 模式下都会把快照放入 diagnostics.performance。主要字段为:
- 阶段:
calls、inclusiveNs、selfNs、maxNs、errors; - 物性:上述时间字段,以及介质、操作、缓存查询/命中/未命中;
- audit 专有:闭合内精确输入唯一数/重复数、逆解迭代总数/最大值/收敛与未收敛次数;
propertyOutermostNs:只累计最外层物性调用,避免把嵌套 PR 内核时间重复相加。
标准模式只保留低频的大阶段计时。21 次氦气阶跃配对运行中,标准模式相对关闭模式的中位开销为 1.9%;四个短算例分开校准为 0.5%~2.9%。audit 会逐次生成精确指纹并计时,短算例可慢到约 2.5~5 倍,因此 audit 数据用于定位和计数,最终优化收益必须回到 off 模式复测。
将当前代码的 off 模式与备份提交 6a06489 同时运行 21 次氦气阶跃,墙钟中位数差为约 0.3%,处于本机噪声范围。也就是说,默认关闭时没有观察到稳定的热路径退化。
3. 测试方法
环境:Windows 11、Python 3.12.3、SciPy 1.18.0、64 位 Intel 处理器。仓库没有 PyInstaller/Nuitka 等可执行文件构建链,本次直接使用项目实际启动后端的 .venv-win 解释器。把同一 Python 代码再包成单文件只会混入解包和启动成本,不会使这里的求解内核更接近生产路径。
基准工具入口:
.venv-win\Scripts\python.exe -m app.simulation.benchmark_performance `
--mode audit --warmups 1 --runs 3 `
--factory "helium_step=tests.test_amesim_pnvo001_signal_xml:high_pressure_helium_step_project" `
--output app/data/performance-evaluations/helium-step.json
工具默认传入取消检查回调,从而走与前端流式仿真相同的低层逐步积分路径。它记录墙钟、进程 CPU、最终 NDJSON 编码、输入 SHA-256 和完整性能快照。原始 JSON 写入被 Git 忽略的 app/data/performance-evaluations/,避免把机器相关的大量样本提交到仓库。
本次代表算例:
| 算例 | 内容 | 暖机后 off 墙钟中位数 |
重复次数 |
|---|---|---|---|
air_chain |
空气气缸—节流孔—管路—储罐 | 62.4 ms | 9 |
air_branched |
空气分支网络 | 130.3 ms | 9 |
helium_step |
高压 PR 氦气、信号阶跃阀 | 65.2 ms | 9 |
mechanical_contact |
MECMAS21/LSTP00A 弹性接触 | 33.0 ms | 9 |
helium_long |
10 s PR 氦气均压、501 个输出点 | 10.63 s | 1 |
短算例先暖机 2 次再测 9 次;缓存 A/B 使用两个同时启动的独立进程各暖机 5 次、测量 21 次,以尽量抵消瞬时系统负载。长算例只测 1 次,因此它只用于判断数量级与阶段占比。
4. 深度阶段结果
下表时间是 audit 中位数,会包含审计自身开销;调用数和相对热点比绝对时间更可靠。
| 算例 | RHS | 完整闭合 | 压力流量求解 | 压力流量包含时间占 audit 总时间 | 物性调用 | 闭合内精确重复率 |
|---|---|---|---|---|---|---|
air_chain |
33 | 37 | 74 | 77.0% | 4,265 | 91.2% |
air_branched |
23 | 26 | 56 | 84.6% | 7,378 | 96.5% |
helium_step |
79 | 102 | 235 | 71.2% | 11,121 | 82.3% |
mechanical_contact |
74 | 78 | 156 | 29.5% | 0 | 不适用 |
当前热流耦合不是旧文档所写的固定 2~3 次压力求解。每次闭合先做 1 次压力求解,然后最多执行 25 轮 stream → pressure-flow 固定点;也就是说理论上最多 26 次。本次四个算例的平均压力求解次数/闭合分别为 2.00、2.15、2.30 和 2.00。优化时应编译依赖/脏标记并减少不必要的全网 pass,但不能直接删除第二轮,否则会重新引入求值历史依赖并破坏有限差分 Jacobian。
5. 物性调用与缓存结果
氦气阶跃的冷缓存 audit 代表运行:
| 操作 | 调用 | 命中/未命中 | 命中率 | 真实逆解次数 | 平均迭代 | 最大迭代 | 未收敛 |
|---|---|---|---|---|---|---|---|
properties_from_mU |
1,930 | 1,843 / 87 | 95.5% | 87 | 3.99 | 5 | 0 |
temperature_from_pressure_enthalpy |
398 | 313 / 85 | 78.6% | 85 | 5.00 | 5 | 0 |
暖机后以相同配置重复运行,这两项在代表快照中均为 100% 命中,说明当前精确 LRU 能跨同配置运行复用确定性轨迹。关闭埋点的端到端配对结果为:暖缓存中位数 77.05 ms,每次清空缓存为 83.69 ms;换算为暖缓存约快 7.9%。
audit 的自身时间排序还显示:isentropic_density_pressure_factor 调用 398 次,density 业务入口及 PR 密度内核各调用 1,198 次,PR compressibility_roots 调用 1,200 次。同一 (p,T) 周围存在“等熵因子内部求密度,随后流量公式再次求密度”的重复机会。这里应优先复用同一闭合内的精确结果或合并 API;不要用四舍五入/容差键缓存,否则会在残差函数中制造平台并影响 ODE/least-squares 的有限差分。
空气算例虽然精确重复率更高,但理想气体公式本身只有少量算术。对这些廉价函数增加字典查询可能比重算更慢,应先做专门 A/B,不应套用氦气结论。
6. 输出与失败样本
| 算例 | 最终结果大小 | NDJSON 编码中位数 |
|---|---|---|
air_chain |
29.2 KiB | 0.39 ms |
air_branched |
59.1 KiB | 1.21 ms |
helium_step |
55.5 KiB | 1.10 ms |
mechanical_contact |
51.4 KiB | 0.62 ms |
helium_long |
507.4 KiB | 18.48 ms |
用户 demo 的输入 SHA-256 为 27048a99da0a21922d75785b760c3b5d04be3349b8aef6fbfedfd811d87ef1d5。audit 失败运行记录到 80 次 RHS、83 次闭合、165 次压力流量求解,最后一项各有 1 次错误;这与此前定位的低压试探态越过 least_squares 初值边界一致。由于没有到达 10 s 终点,不能把其 1.08 s 失败耗时当作完整模型性能。
7. 后续优化顺序
- 先优化压力流量执行计划。 继续预编译组件/连接残差归属、显式赋值顺序和热流耦合脏标记;增加快路径命中率、非线性
nfev累计耗时,区分“全网扫描慢”与“非线性迭代慢”。 - 再减少 PR 物性重复。 复用组件当前
(m,U,V)的状态恢复结果,合并等熵因子与密度读取;沿用精确键、有界容量和按仿真隔离原则。现有 LRU 已带来约 8% 的短算例收益,不应回退。 - 处理冷启动。 若首请求延迟重要,可在 worker 启动时显式导入 SciPy 求解模块或运行一个极小、无业务副作用的预热模型;不要把约 0.65 s 冷启动归因到每次仿真。
- 长算例再看后处理复用。 当前代表长算例的积分占 90.5%,所以积分/闭合仍优先;当采样更密或变量更多时,再评估复用已接受状态闭合、按需变量和降采样。
- 把 demo 数值容错作为独立修复。 统一压力可行域与初值投影、将试探态错误转为可恢复拒步,并在闭合前刷新外部容积缓存;该改动需要单独回归,不能混入性能优化提交。
8. 本次评估边界
- 没有固定 CPU 亲和性或关闭后台程序,短算例绝对时间存在数毫秒波动,因此以中位数和配对实验为主。
- audit 会显著改变廉价函数的单次耗时;不能把 audit 的物性毫秒数直接当成关闭埋点后的真实占比。
- 当前 LRU 命中/未命中来自调用前后的全局
cache_info()差值;本报告均为单任务运行。多个 audit 仿真线程同时调用同一缓存时,阶段/物性调用仍按 trace 隔离,但缓存命中差值可能交错,不能用来做并发结论。 - 直接抛出
HTTPException的校验/执行异常会结束 trace,但当前不会把快照附到错误响应;demo 属于返回failed部分结果的路径,所以本报告能够取得其失败快照。 - 本批没有测峰值 RSS、1/2/4 并发吞吐、浏览器解析/绘图或 8/32 单元拓扑扩展曲线。
- 没有为评估引入新的近似缓存、容差调整或求解器算法变更;所有性能结论都与数值优化改动解耦。