Files
SystemSimulationApp/tests/manual/solver_profile.c
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

63 lines
2.8 KiB
C

#include "solver_profile.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#endif
static struct { unsigned long long calls; double inclusive, exclusive; } totals[P_COUNT];
static unsigned long long counters[C_COUNT], errors;
static ProfileScope *parent;
static double profile_now(void) {
#ifdef _WIN32
static LARGE_INTEGER frequency;
LARGE_INTEGER value;
if(!frequency.QuadPart) QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&value);
return (double)value.QuadPart/(double)frequency.QuadPart;
#else
struct timespec value; clock_gettime(CLOCK_MONOTONIC,&value);
return value.tv_sec+value.tv_nsec*1e-9;
#endif
}
ProfileScope profile_begin(int id) {
ProfileScope s={.id=id,.active=1,.parent=parent};
s.start=profile_now();return s;
}
void profile_link(ProfileScope *s) {parent=s;}
void profile_end(ProfileScope *s) {
if(!s->active)return;
double elapsed=profile_now()-s->start;
if(parent!=s || elapsed<s->children) {fputs("Invalid profiling scope\n",stderr);exit(74);}
totals[s->id].calls++;
totals[s->id].inclusive+=elapsed;
totals[s->id].exclusive+=elapsed-s->children;
parent=s->parent;
if(parent)parent->children+=elapsed;
s->active=0;
}
void profile_add(int id,int status,long int value) {
if(status || value<0)errors++;
else counters[id]+=(unsigned long long)value;
}
void profile_dump(void) {
const char *path=getenv("NATIVE_SOLVER_PROFILE");
if(!path || parent) {fputs("Missing profile destination or unclosed scope\n",stderr);exit(74);}
FILE *f=fopen(path,"wb");if(!f){perror(path);exit(73);}
const char *names[]={"total","integration","cvode_controller","rhs","nonlinear_residual",
"jacobian","jacobian_probe","linear_setup","numerical_factorization","linear_solve",
"newton","event_detection","accepted_property_checks","sampling","append","flush",
"output_replay","result_encoding","poll"};
const char *count_names[]={"accepted_steps","residual_evaluations","linear_rhs_evaluations",
"jacobian_evaluations","linear_setups","error_test_failures","newton_iterations",
"newton_failures","nonlinear_step_failures","counter_segments","jacobian_reuses",
"jacobian_refresh_setups","linear_setup_failures","LU_factorization_failures",
"LU_solve_failures","event_model_evaluations","scheduled_boundary_count"};
fprintf(f,"{\"version\":1,\"counterErrors\":%llu,\"counters\":{",errors);
for(int i=0;i<C_COUNT;i++)fprintf(f,"%s\"%s\":%llu",i?",":"",count_names[i],counters[i]);
fputs("},\"scopes\":{",f);
for(int i=0;i<P_COUNT;i++)fprintf(f,"%s\"%s\":{\"calls\":%llu,\"inclusiveSeconds\":%.17g,\"exclusiveSeconds\":%.17g}",
i?",":"",names[i],totals[i].calls,totals[i].inclusive,totals[i].exclusive);
fputs("}}\n",f);int ok=!ferror(f);if(fclose(f))ok=0;if(!ok)exit(73);
}