在单次 Jacobian 构建内按完整输入精确复用储气物性、PH 反算、密度和管路求根结果,保持原有求值副作用、差分政策与失败回退。八路模型求解 CPU 中位数减少 19.27%,循环和不循环的完整原始采样均与恢复基线一致。 增加独立的跨平台时间剖析工具,记录互斥阶段耗时、Newton/LU 统计、矩阵复用与内核复用,保存 UD00 两种工况的调查报告和机器可读汇总。 补充 Windows/Linux 运行、测试、原生编译和剖析所需依赖文档及索引,不修改依赖清单、版本锁或安装环境。 验证:8 项新增专项回归通过;2270 次完整 Jacobian 核对零差异;16 次剖析配对及预热运行保持完整数值一致。既有固定样本哈希失败和 Linux 实机验收限制见报告。
66 lines
2.9 KiB
Python
66 lines
2.9 KiB
Python
"""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()
|