优化 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

+65
View File
@@ -0,0 +1,65 @@
"""Check diagnostic scope accounting, including nested returns and goto cleanup."""
import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
from app.simulation.native_codegen.build import toolchain, platform_build_inputs, _command
from tests.manual.profile_native_solver import instrument, PARTITION
ROOT = Path(__file__).resolve().parents[1]
HERE = ROOT / 'tests/manual'
HARNESS = r'''
#include "solver_profile.h"
static int early(void) { PROFILE_SCOPE(P_RHS);return 7; }
static void nested(void) {
PROFILE_SCOPE(P_INTEGRATION);
{ PROFILE_SCOPE(P_EVENT);if(early()==7)goto finished; }
finished:
profile_add(C_STEPS,0,3);
profile_add(C_ERROR_FAILS,-1,1);
}
int main(void) {
PROFILE_SCOPE(P_TOTAL);nested();profile_end(&profile_scope);profile_dump();return 0;
}
'''
class SolverProfileTests(unittest.TestCase):
def test_nested_early_return_and_goto_partition(self):
compiler, sundials, _ = toolchain()
flags, _, _, executable = platform_build_inputs(sundials)
with tempfile.TemporaryDirectory() as name:
directory = Path(name)
(directory / 'harness.c').write_text(HARNESS, encoding='utf-8')
_command([compiler, *flags, '-I', str(HERE), str(directory / 'harness.c'),
str(HERE / 'solver_profile.c'), '-o', str(directory / executable)], log=[])
environment = dict(os.environ, NATIVE_SOLVER_PROFILE=str(directory / 'profile.json'))
subprocess.run([str(directory / executable)], env=environment, check=True, timeout=20)
result = json.loads((directory / 'profile.json').read_bytes())
scopes = result['scopes']
self.assertEqual(result['counterErrors'], 1)
self.assertEqual(result['counters']['accepted_steps'], 3)
self.assertEqual(result['counters']['error_test_failures'], 0)
for key in ('total', 'integration', 'event_detection', 'rhs'):
self.assertEqual(scopes[key]['calls'], 1)
self.assertEqual(set(scopes), {key for group in PARTITION.values() for key in group})
self.assertEqual(len(scopes), sum(map(len, PARTITION.values())))
self.assertAlmostEqual(sum(s['exclusiveSeconds'] for s in scopes.values()),
scopes['total']['inclusiveSeconds'], places=9)
self.assertTrue(all(s['exclusiveSeconds'] >= 0 for s in scopes.values()))
def test_instrumentation_rejects_missing_anchors(self):
with tempfile.TemporaryDirectory() as name:
directory = Path(name)
(directory / 'include').mkdir()
(directory / 'runtime').mkdir()
(directory / 'runtime/common.c').write_text('/* incompatible runtime */')
with self.assertRaisesRegex(RuntimeError, 'Cannot identify unique function'):
instrument(directory)
if __name__ == '__main__':
unittest.main()