在单次 Jacobian 构建内按完整输入精确复用储气物性、PH 反算、密度和管路求根结果,保持原有求值副作用、差分政策与失败回退。八路模型求解 CPU 中位数减少 19.27%,循环和不循环的完整原始采样均与恢复基线一致。 增加独立的跨平台时间剖析工具,记录互斥阶段耗时、Newton/LU 统计、矩阵复用与内核复用,保存 UD00 两种工况的调查报告和机器可读汇总。 补充 Windows/Linux 运行、测试、原生编译和剖析所需依赖文档及索引,不修改依赖清单、版本锁或安装环境。 验证:8 项新增专项回归通过;2270 次完整 Jacobian 核对零差异;16 次剖析配对及预热运行保持完整数值一致。既有固定样本哈希失败和 Linux 实机验收限制见报告。
164 lines
11 KiB
Markdown
164 lines
11 KiB
Markdown
# 求解器时间剖析与计数调查
|
||
|
||
日期: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 不循环
|
||
|
||
```text
|
||
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 循环
|
||
|
||
```text
|
||
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。
|
||
|
||
### 三处容易误读的计数
|
||
|
||
1. **rejected_steps 不等于旧 rejectedSteps。** 旧字段仅含误差检验失败:884 / 1334;加上非线性求解导致的步失败 179 / 229,本次完整拒绝尝试计数为 1063 / 1563。Newton 内部失败 978 / 1218 可能通过刷新 J 重试恢复,不全部导致拒绝步。
|
||
2. **循环的内部成功步 15733 与应用接受步 15731 都保留。** 差额对应两次 same_time_returns;原应用对时间未推进的返回不执行接受步事件/采样流程。这不是插桩造成的轨迹变化。
|
||
3. **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 |
|
||
|
||
观测扰动约为百分之一或以内;负差值属于运行波动,不代表插桩带来优化。没有从各阶段强行扣除估算的计时器成本,小于毫秒级的项目不宜过度解释。时间树采用三次平均,此表采用中位数,且进程时长含启动,三者不应直接相减当作某个新阶段。
|
||
|
||
## 下一步优化判断
|
||
|
||
1. **Jacobian 仍是第一热点。** 约 35%–36% 的完整运行时间位于该阶段;扣除子调用的装配/分组管理仅约 0.022 / 0.028 s,绝大多数成本仍在模型探针。下一步应继续研究受扰动依赖范围及昂贵内核的导数计算;单纯优化矩阵填充循环收益有限。
|
||
2. **普通 residual 与接受步物性检查值得分别优化。** 普通 residual 占约 27%–29%,物性检查占约 15%–17%。这支持减少诊断用途完整重算的方向,但不等于已暂存的方向一方案具有正收益;必须对具体裁剪/计算调度的新增成本再次实测。
|
||
3. **完整运行还存在结果处理成本。** 输出回放与 JSON 写出合计约 11%–14%。若目标是用户等待时间,应把这部分一起衡量;若目标只限积分内核,则排除这部分。
|
||
4. **本规模下暂不优先更换线性求解器。** 分解+回代约 5%–6%,加上线性 setup 其他工作约 7%。这限定了只优化线性代数的当前收益空间;不能推广到状态数更大的模型。
|
||
5. **事件与控制框架当前不是主要瓶颈。** Newton 控制和 CVODE controller 各不足 0.3%,事件检测约 0.03%。应首先减少昂贵物理求值成本,而不是从这些小项着手。
|
||
|
||
## 工具、证据与限制
|
||
|
||
- [使用与参数口径](../standard/native-solver-profiling.md)
|
||
- [可复用调查工具](../../tests/manual/profile_native_solver.py)
|
||
- [随文保存的机器可读汇总](assets/2026-09-16/solver-profile-summary.json)
|
||
- 完整原始证据:项目 `test/solver-profile-20260916/`,含冻结程序、每次原始文件、profile.json、measurement.json、summary.json 和构建日志。该目录按项目约定被 Git 忽略。
|
||
- 本轮没有重新执行全仓库、Amesim 或浏览器全流程验收;这里的正确性结论是插桩与当前生产版本的完整数值保持。
|
||
- Windows 实测通过;计时与构建代码提供 Linux 路径,真实 Linux 运行未验收。
|
||
- 使用同一 SUNDIALS 库的 Newton 实现和公共操作表;诊断版显式挂接 Newton 便于观测,并用完整数值/计数对照检验等价性,不访问 CVODE 私有结构。
|
||
|
||
计数定义参考 [SUNDIALS 7.4 CVODE 可选输出接口](https://sundials.readthedocs.io/en/v7.4.0/cvode/Usage/index.html#optional-output-functions)。
|