Files
SystemSimulationApp/docs/other/求解器时间剖析与计数调查-2026-09-16.md
T
ljz 1aac220084 优化 Jacobian 确定性复用并补充性能剖析与平台依赖文档
在单次 Jacobian 构建内按完整输入精确复用储气物性、PH 反算、密度和管路求根结果,保持原有求值副作用、差分政策与失败回退。八路模型求解 CPU 中位数减少 19.27%,循环和不循环的完整原始采样均与恢复基线一致。

增加独立的跨平台时间剖析工具,记录互斥阶段耗时、Newton/LU 统计、矩阵复用与内核复用,保存 UD00 两种工况的调查报告和机器可读汇总。

补充 Windows/Linux 运行、测试、原生编译和剖析所需依赖文档及索引,不修改依赖清单、版本锁或安装环境。

验证:8 项新增专项回归通过;2270 次完整 Jacobian 核对零差异;16 次剖析配对及预热运行保持完整数值一致。既有固定样本哈希失败和 Linux 实机验收限制见报告。
2026-09-16 13:39:53 +08:00

164 lines
11 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-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)。