在单次 Jacobian 构建内按完整输入精确复用储气物性、PH 反算、密度和管路求根结果,保持原有求值副作用、差分政策与失败回退。八路模型求解 CPU 中位数减少 19.27%,循环和不循环的完整原始采样均与恢复基线一致。 增加独立的跨平台时间剖析工具,记录互斥阶段耗时、Newton/LU 统计、矩阵复用与内核复用,保存 UD00 两种工况的调查报告和机器可读汇总。 补充 Windows/Linux 运行、测试、原生编译和剖析所需依赖文档及索引,不修改依赖清单、版本锁或安装环境。 验证:8 项新增专项回归通过;2270 次完整 Jacobian 核对零差异;16 次剖析配对及预热运行保持完整数值一致。既有固定样本哈希失败和 Linux 实机验收限制见报告。
11 KiB
11 KiB
求解器时间剖析与计数调查
日期:2026-09-16。
结论
方向二优化后的当前求解器,主要成本仍是 Jacobian 基准/扰动求值、普通 residual 求值,以及接受步物性检查。两种工况下它们合计占完整原生运行约 78%–81%。Dense LU 分解与线性求解合计约 5%–6%;Newton 控制、事件检测及步长/阶数控制所占比例很小。
本轮交付独立诊断工具和调查结果。计时加入 test/ 下的源码副本,当前生产求解器未额外修改。方向一仍保存在 stash@{0}(06b161c309644bb01aa402ff79f34749ff8e889a)。
工况、测量与数值保持
- 当前八路模型:132 个状态、1784 个输出;Windows 11,CVODE 7.4 BDF。
- 两个 UD00 均不循环、两个 UD00 均循环,分别运行 0–21.7 s,覆盖 10.8 / 21.6 s 边界。
- 采样间隔 0.01 s,rtol 1e-8,保持既有 atol,max_step 1e30。
- 所有构建结束后,每种工况各进行一组预热和三组正常/插桩串行配对测量;预热排除。
- 16 次运行的完整结果 JSON(仅排除计时字段)、全部状态/输出二进制、警告及原有计数均通过一致性检查。
- 两种工况每次重复的新计数也完全一致。原始源码哈希及生成 C/头文件已核对。
- 计时器嵌套、提前返回、goto 清理及源码锚点保护测试:2 项通过。
以下 Total simulation 指原生进程内从初始化到结果写出和清理的完整工作,不含构建、进程启动、API 和浏览器。各阶段采用单调墙钟,使用扣除子调用后的互斥时间;三次取平均,分项可加总。求解/进程总时长中位数另列。
时间树
UD00 不循环
Total simulation 7.656251 s (100%)
├── symbolic factorization N/A(Dense LU)
├── error estimation 独立计时 未分离,包含在下方 CVODE controller 组
├── residual evaluation 2.087807 s 27.27%
├── Jacobian assembly (含探针) 2.739999 s 35.79%
├── numerical factorization 0.236525 s 3.09%
├── linear solve 0.179552 s 2.35%
├── linear setup / 矩阵缩放等 0.106778 s 1.39%
├── Newton overhead 0.012538 s 0.16%
├── CVODE controller / error estimation 等 0.021977 s 0.29%
├── event detection 0.001957 s 0.03%
├── accepted-step property checks 1.171337 s 15.30%
├── sampling / storage 0.009698 s 0.13%
├── output replay 0.298776 s 3.90%
├── result encoding / 写出 0.777299 s 10.15%
├── poll / progress 0.006268 s 0.08%
└── framework / other 0.005739 s 0.07%
其中积分循环平均耗时为 6.578949 s。
UD00 循环
Total simulation 9.711949 s (100%)
├── symbolic factorization N/A(Dense LU)
├── error estimation 独立计时 未分离,包含在下方 CVODE controller 组
├── residual evaluation 2.832336 s 29.16%
├── Jacobian assembly (含探针) 3.431087 s 35.33%
├── numerical factorization 0.329359 s 3.39%
├── linear solve 0.240836 s 2.48%
├── linear setup / 矩阵缩放等 0.143107 s 1.47%
├── Newton overhead 0.016226 s 0.17%
├── CVODE controller / error estimation 等 0.028732 s 0.30%
├── event detection 0.002641 s 0.03%
├── accepted-step property checks 1.620996 s 16.69%
├── sampling / storage 0.009675 s 0.10%
├── output replay 0.297087 s 3.06%
├── result encoding / 写出 0.743466 s 7.66%
├── poll / progress 0.008575 s 0.09%
└── framework / other 0.007827 s 0.08%
其中积分循环平均耗时为 8.670143 s。
关键边界
- residual 行是普通 RHS 加非线性 residual 的代数组装,不包含 Jacobian 探针。
- Jacobian 行包含基准/扰动模型求值和矩阵装配;普通 residual 与它不重复相加。
- symbolic factorization 不适用于当前稠密 LU,并非已经测出一个稀疏符号分解耗时为零。
- 误差估计在预编译 SUNDIALS 内部无独立计时入口,记录为 null;CVODE controller 还包含预测、历史更新、步长/阶数控制等,不能把整组冒称为误差估计。
- Newton overhead 已扣除 residual、Jacobian、线性 setup、分解和回代;包括剩余收敛判断、控制和接口开销。
- 事件检测已扣除物性检查及普通采样。result encoding 包含 JSON 序列化和文件写出,不能解释为纯编码算法的 CPU 耗时。
求解计数
| 参数 | 不循环 | 循环 |
|---|---|---|
accepted_steps |
11006 | 15733 |
application_accepted_steps |
11006 | 15731 |
same_time_returns |
0 | 2 |
rejected_steps |
1063 | 1563 |
error_test_failures |
884 | 1334 |
nonlinear_step_failures |
179 | 229 |
residual_evaluations |
20048 | 28023 |
nonlinear_residual_calls |
20037 | 28003 |
jacobian_probe_evaluations |
30044 | 38472 |
jacobian_evaluations |
1073 | 1374 |
jacobian_reuses |
2214 | 3326 |
LU_factorizations |
3287 | 4700 |
LU_solves |
20037 | 28003 |
newton_solve_calls |
12069 | 17296 |
newton_iterations |
20037 | 28003 |
newton_failures |
978 | 1218 |
event_count |
1 | 4 |
scheduled_boundary_count |
3 | 5 |
event_detection_calls |
11006 | 15731 |
accepted_property_checks |
11007 | 15732 |
solver_starts |
5 | 10 |
all_counted_model_evaluations |
50092 | 66495 |
sample_count |
2172 | 2175 |
两种工况的 linear_setup_failures、LU_factorization_failures、LU_solve_failures、linear_rhs_evaluations、计数接口错误均为 0。
三处容易误读的计数
- rejected_steps 不等于旧 rejectedSteps。 旧字段仅含误差检验失败:884 / 1334;加上非线性求解导致的步失败 179 / 229,本次完整拒绝尝试计数为 1063 / 1563。Newton 内部失败 978 / 1218 可能通过刷新 J 重试恢复,不全部导致拒绝步。
- 循环的内部成功步 15733 与应用接受步 15731 都保留。 差额对应两次 same_time_returns;原应用对时间未推进的返回不执行接受步事件/采样流程。这不是插桩造成的轨迹变化。
- jacobian_reuses 是矩阵复用。 统计成功线性 setup 前后 J 刷新计数未增加的次数,分别为 2214 / 3326;它与计算新 J 时的物性内核复用不同。LU_solves 直接统计 Dense solve 调用,不能以 Krylov 迭代次数代替。
额外一致性关系在本次两种工况均成立:
- Newton solve 调用数 = CVODE 内部成功步 + 两类拒绝步。
- LU 分解次数 = Jacobian 刷新 setup + 沿用 J 的 setup。
- 原 nfev = 普通 RHS + Jacobian 探针(本模型无额外摩擦求值)。
- 累加计数段数 = solver_starts;覆盖所有事件及预定时间边界的 ReInit。
方向二内核复用
| 内核 | 不循环:计算 / 复用 | 循环:计算 / 复用 |
|---|---|---|
| gas | 180304 / 1502160 | 230872 / 1923560 |
| ph | 105403 / 732566 | 136587 / 940359 |
| density | 531697 / 2979837 | 685389 / 3819723 |
| pipe | 235272 / 1063254 | 301626 / 1368464 |
这些内核计数仅覆盖新 Jacobian 的基准/分组探针,不代表整个运行的全部物性调用。
插桩扰动
| 工况 | 原求解中位数 | 插桩求解中位数 | 观测差值 | 原进程中位数 | 插桩进程中位数 |
|---|---|---|---|---|---|
| noncyclic | 6.583621 s | 6.638836 s | +0.84% | 7.777796 s | 7.830035 s |
| cyclic | 8.631554 s | 8.620837 s | -0.12% | 9.813596 s | 9.760674 s |
观测扰动约为百分之一或以内;负差值属于运行波动,不代表插桩带来优化。没有从各阶段强行扣除估算的计时器成本,小于毫秒级的项目不宜过度解释。时间树采用三次平均,此表采用中位数,且进程时长含启动,三者不应直接相减当作某个新阶段。
下一步优化判断
- Jacobian 仍是第一热点。 约 35%–36% 的完整运行时间位于该阶段;扣除子调用的装配/分组管理仅约 0.022 / 0.028 s,绝大多数成本仍在模型探针。下一步应继续研究受扰动依赖范围及昂贵内核的导数计算;单纯优化矩阵填充循环收益有限。
- 普通 residual 与接受步物性检查值得分别优化。 普通 residual 占约 27%–29%,物性检查占约 15%–17%。这支持减少诊断用途完整重算的方向,但不等于已暂存的方向一方案具有正收益;必须对具体裁剪/计算调度的新增成本再次实测。
- 完整运行还存在结果处理成本。 输出回放与 JSON 写出合计约 11%–14%。若目标是用户等待时间,应把这部分一起衡量;若目标只限积分内核,则排除这部分。
- 本规模下暂不优先更换线性求解器。 分解+回代约 5%–6%,加上线性 setup 其他工作约 7%。这限定了只优化线性代数的当前收益空间;不能推广到状态数更大的模型。
- 事件与控制框架当前不是主要瓶颈。 Newton 控制和 CVODE controller 各不足 0.3%,事件检测约 0.03%。应首先减少昂贵物理求值成本,而不是从这些小项着手。
工具、证据与限制
- 使用与参数口径
- 可复用调查工具
- 随文保存的机器可读汇总
- 完整原始证据:项目
test/solver-profile-20260916/,含冻结程序、每次原始文件、profile.json、measurement.json、summary.json 和构建日志。该目录按项目约定被 Git 忽略。 - 本轮没有重新执行全仓库、Amesim 或浏览器全流程验收;这里的正确性结论是插桩与当前生产版本的完整数值保持。
- Windows 实测通过;计时与构建代码提供 Linux 路径,真实 Linux 运行未验收。
- 使用同一 SUNDIALS 库的 Newton 实现和公共操作表;诊断版显式挂接 Newton 便于观测,并用完整数值/计数对照检验等价性,不访问 CVODE 私有结构。
计数定义参考 SUNDIALS 7.4 CVODE 可选输出接口。