优化 Jacobian 确定性复用并补充性能剖析与平台依赖文档

在单次 Jacobian 构建内按完整输入精确复用储气物性、PH 反算、密度和管路求根结果,保持原有求值副作用、差分政策与失败回退。八路模型求解 CPU 中位数减少 19.27%,循环和不循环的完整原始采样均与恢复基线一致。

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

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

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

No files matched your search

+72
View File
@@ -0,0 +1,72 @@
# 原生求解器时间剖析
诊断入口:`tests/manual/profile_native_solver.py`。它冻结当前正常构建,在 `test/` 下的独立源码副本加入计时,生成分阶段耗时、求解计数、完整数值对照和插桩开销。适用于当前具有自动着色 Jacobian 的 BDF 模型;不支持的模型明确拒绝,不把无法观测的阶段报告为零。
```powershell
.\.venv-win\Scripts\python.exe tests/manual/profile_native_solver.py --run
```
默认使用 `tests/data/test-mql-8-corrected.json`,将所有 UD00 分别设为不循环、循环,仿真至 21.7 s,每个版本预热一次并测量三次。可用 `--input`、`--output`、`--stop`、`--warmups`、`--repeats` 调整。输出目录须是项目 `test/` 下的新目录,以保护既有证据。所有构建先完成,随后串行计时。省略 `--run` 只准备构建。
已有完整测量可用 `--output test/solver-profile-20260916 --report-only` 重新检查计数和生成汇总,不重新编译或运行仿真。
## 计时口径
- 总计时覆盖原生进程内的初始化、积分、采样写盘、输出回放、JSON 编码及资源释放,排除构建、进程启动、API 和浏览器。
- 采用单调墙钟:Windows 为 QueryPerformanceCounter,Linux 为 CLOCK_MONOTONIC。阶段耗时不是 CPU 采样百分比,不能与 CPU 秒数直接混用。
- 每个作用域记录包含子调用的 `inclusiveSeconds`,以及扣除子调用后的 `exclusiveSeconds`。只有互斥的 exclusive 值可相加。
- 三次阶段耗时取算术平均,确保分项之和等于总耗时;完整求解和进程耗时另报中位数。计时/统计开销仍包含在诊断结果中,以正常构建的配对运行估计扰动。
- Jacobian 阶段包含基准和分组差分的模型求值;这些求值不重复计入普通 residual 阶段。保留探针、装配及普通 RHS 的子作用域数据。
- Dense LU 没有稀疏矩阵的 symbolic factorization,记为不适用。
- 当前预编译 SUNDIALS 关闭内部 profiler。误差估计无法独立直接计时,记录为 `null`,包含在 `cvode_controller_including_error_estimation` 中。该组还包括预测、历史更新、步长/阶数控制及其他未观测内部工作,不将其整体冒称为误差估计。
- `newton_overhead` 为 Newton solve 扣除 residual、线性 setup、LU 和线性求解后的剩余时间,包括收敛判断、迭代控制及接口开销,不涵盖所有外层 CVODE 控制成本。
- 事件计时扣除了接受步物性检查、普通采样和存储;保留事件探测、定位所用插值及模式更新。物性检查独立列出,以免淹没在框架耗时中。
## 观测接口与数值核对
使用 SUNDIALS 公共 SUNLinearSolver / SUNNonlinearSolver 操作表包裹原函数。诊断副本显式挂接同一库的 `SUNNonlinSol_Newton`,保持库的 Newton 实现及默认策略,便于计时与观测线性 setup。没有读取 CVODE 私有内存布局。正常构建仍使用原来的隐式默认创建过程。
每次运行比较正常构建与诊断构建的完整结果 JSON(仅排除原有两个耗时字段),并核对状态/输出二进制文件 SHA。任何数值、警告、事件或原有求解计数变化均中止调查。计数读取在每次 CVodeReInit 之前及最终清理时累计,检查累计段数等于 solver_starts,避免仅报告最后一段。
工具对单个独立进程内的一次 BDF 求解设计;诊断全局状态不作为并发库接口使用。生产源码、生产可执行文件和模型公式不被插桩脚本改写。
## 参数定义
| 参数 | 定义 |
|---|---|
| `accepted_steps` | 累加 CVodeGetNumSteps,CVODE 成功内部步数 |
| `application_accepted_steps` | 原应用接受步数,可能受同时间返回处理影响,另行保留 |
| `same_time_returns` | CVODE 成功返回但返回时间与上一次相同的次数;此时应用保留求解器历史并继续推进 |
| `error_test_failures` | 局部误差检验失败次数,对应原 `rejectedSteps` |
| `nonlinear_step_failures` | 因非线性求解失败而拒绝的步尝试 |
| `rejected_steps` | 上述两类步失败之和,不等同于原 `rejectedSteps` |
| `residual_evaluations` | CVODE 普通 RHS 次数,包含初值/步长准备;排除 Jacobian 差分探针和事件求值 |
| `nonlinear_residual_calls` | 实际 Newton 非线性 residual 回调次数,其代数部分的时间也计入 residual 阶段 |
| `jacobian_probe_evaluations` | 自定义 Jacobian 基准/扰动 RHS 次数 |
| `linear_rhs_evaluations` | CVODE 内置线性差分 RHS 次数,与自定义探针分别记录 |
| `jacobian_evaluations` | Jacobian 矩阵刷新次数 |
| `jacobian_reuses` | 成功的线性 setup 中,没有新增 Jacobian 计算、沿用已有 J 的次数;直接比较该次 setup 前后的累计刷新计数 |
| `jacobian_kernel_reuse` | 新计算一个 J 时,对 gas/PH/density/pipe 确定性结果的计算/复用次数;与矩阵复用不同 |
| `linear_setups` | CVODE 线性求解器 setup 调用次数,对应原 `nlu` 的实际口径 |
| `LU_factorizations` | 原 Dense setup 的实际调用次数,失败次数另记 |
| `LU_solves` | 原 Dense solve 的实际调用次数,失败次数另记;不使用直接法恒为零的 Krylov 迭代数代替 |
| `newton_iterations` | 累加 CVodeGetNumNonlinSolvIters |
| `newton_failures` | 累加 CVodeGetNumNonlinSolvConvFails;一次步尝试内可能刷新 J 重试,不等于拒绝步数 |
| `newton_solve_calls` | Newton solve 入口次数,与 Newton 迭代数分别记录 |
| `event_count` | 原状态转换计数,同一时刻多个转换可合为一次;不是被发现的每个零点数量 |
| `scheduled_boundary_count` | UD00 等预定时间边界导致的额外重启次数,独立于状态转换事件 |
| `event_detection_calls` | 接受步事件检查入口次数 |
| `all_counted_model_evaluations` | 原 nfev,含普通 RHS、自定义 Jacobian 探针与摩擦事件求值;不含全部诊断/输出回放求值 |
| `accepted_property_checks` | 接受步及初始化物性检查入口次数 |
计数含义参考 [SUNDIALS 7.4 CVODE 可选输出接口](https://sundials.readthedocs.io/en/v7.4.0/cvode/Usage/index.html#optional-output-functions)。实际统计以本项目的调用边界和上述分项定义为准。
## 输出
- `prepared.json`:平台、编译器、模型参数、冻结构建哈希、原始/插桩源码哈希。
- `noncyclic/`、`cyclic/`:正常构建、诊断构建及各次运行的完整结果。
- 每次诊断的 `profile.json`:原始作用域次数、inclusive/exclusive 耗时和累计计数。
- `measurement.json`、`measurements.json`:计时、原始数据哈希及数值一致性检查结果。
- `summary.json`:互斥耗时分解、计数、分项平均值、总耗时中位数及观测扰动。
计时器及锚点保护测试:`python -m unittest tests.test_solver_profile -v`。Windows 与 Linux 使用同一源码;实际平台验收情况应以具体调查报告为准。