Files
SystemSimulationApp/tests/manual/local_probe_profile.c
T
ljz 7611f13208 修复循环信号与事件采样并接入 LSTP 接触定位,补充八路验证及复用实验
相较上一版 Jacobian 确定性复用更新,本次补齐事件边界一致性、结果两侧采样及接触事件定位;保留已有物性复用和组件力学公式。

- 统一 UD00 信号求值与下一事件查询的绝对时间边界,修复循环边界浮点舍入导致的阶段错位、重复或漏报,并覆盖零时长、多阶段及长周期场景。
- 引入原生输出语义 v2:保留规则网格真实时间,补充内部时间事件和状态事件的左邻及事件后采样,按保存时间、状态和离散模式重放结果。
- 两条代码生成路径均发出 LSTP 接触描述,默认定位间隙过零及非负力模式的力截断;仅在接受事件时更新防重复记录,增加 contactEvents 诊断计数。
- 补充 MASS/LSTP 独立事件实验、八路全曲线与驱动阶段配对评估,以及 Amesim 不连续点输出对照和力差定位报告;MASS 新增释放机制仍保留为独立实验。
- 保存局部 probe、context 访问与回退、shadow replay、R288 real skip/typed replay 及阀门数值尾部诊断工具和报告;未证明净收益的实验不启用为生产默认优化。
- 更新原生运行说明和元件建模规范,补充信号边界、输出语义、接触事件和实验依赖回归测试。

验证:五组专项回归共 34 项全部通过;37 个待提交 Python 文件语法检查通过;git diff --cached --check 通过。
2026-09-17 23:50:13 +08:00

87 lines
5.2 KiB
C

/* No numerical work lives here. Runtime selection is outside the hot model. */
#include "local_probe_profile.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* PROFILE_TABLES */
PfBucket pf_buckets[LP_NC+2][PF_CATEGORIES],*pf_current;
uint64_t pf_previous_tick;
unsigned pf_row;
int pf_coarse;
static uint64_t evaluations[LP_NC+2];
uint64_t pf_operations[LP_NC][2];
static uint64_t calls,sampled,sampled_ticks,frequency,total_events;
static uint64_t sampled_qpc_ticks,tsc_start,tsc_end,clock_t0;
static double clock_q0;
static unsigned stride=16,offset,seed=1;
static FILE *matrix;
static const char *names[PF_CATEGORIES]={"other","perturbation_amount","state_copy_perturb",
"matrix_zero","difference_matrix_write","baseline_compute","initialization","gas_state_preparation",
"schedule_retained","schedule_context_fallback","context_compare","snapshot_capture_save",
"context_output_restore","node_energy","port_outputs","mechanical_equations",
"gas_mass_energy","remaining_outputs","pipe_diagnostics","finite_check","schedule_dispatch","whole_probe_fallback"};
void pf_initialize(void){
LARGE_INTEGER f;QueryPerformanceFrequency(&f);frequency=(uint64_t)f.QuadPart;
unsigned a,b,c,d;
if(!__get_cpuid(0x80000007,&a,&b,&c,&d) || !(d&(1u<<8))){fprintf(stderr,"invariant TSC required for diagnostic clock\n");abort();}
uint64_t q0=lp_tick();clock_t0=pf_clock();uint64_t q1=lp_tick();clock_q0=((double)q0+(double)q1)/2;
const char *s=getenv("PROBE_PROFILE_STRIDE"),*o=getenv("PROBE_PROFILE_OFFSET"),*v=getenv("PROBE_PROFILE_MATRICES");
const char *coarse=getenv("PROBE_PROFILE_COARSE");pf_coarse=coarse?atoi(coarse):0;
if(s)stride=(unsigned)strtoul(s,NULL,0);
if(o)offset=(unsigned)strtoul(o,NULL,0);
seed=offset+1;
if(v && atoi(v)){matrix=fopen("jacobians.bin","wb");if(!matrix)abort();setvbuf(matrix,NULL,_IOFBF,1024*1024);}
}
int pf_select(void){
/* One randomly positioned callback per consecutive stratum. The offset is
reproducible, and avoids locking onto a recurring Newton/event pattern. */
unsigned pos=(unsigned)(calls++% (stride?stride:1));
if(!stride)return 0;
if(!pos){seed^=seed<<13;seed^=seed>>17;seed^=seed<<5;offset=seed%stride;}
if(pos!=offset)return 0;
pf_row=0;return 1;
}
void pf_eval_count(void){evaluations[pf_row]++;}
void pf_open(void){pf_current=&pf_buckets[0][PF_OTHER];tsc_start=pf_clock();pf_previous_tick=tsc_start;}
void pf_close(void){tsc_end=pf_clock();pf_current->ticks+=tsc_end-pf_previous_tick;}
void pf_flush(uint64_t start,uint64_t end){
sampled++;sampled_qpc_ticks+=end-start;sampled_ticks+=tsc_end-tsc_start;
}
void pf_validate_matrix(double t,const double *y,const double *m){
if(matrix){fwrite(&t,8,1,matrix);fwrite(y,8,NSTATES,matrix);fwrite(m,8,NSTATES*NSTATES,matrix);}
}
static void array(FILE *f,const uint64_t *a,int n){fputc('[',f);for(int i=0;i<n;i++)fprintf(f,"%s%llu",i?",":"",(unsigned long long)a[i]);fputc(']',f);}
void pf_finish(void){
if(matrix){fclose(matrix);matrix=NULL;}
uint64_t q0=lp_tick(),t1=pf_clock(),q1=lp_tick();
double tsc_frequency=(double)(t1-clock_t0)/((((double)q0+(double)q1)/2-clock_q0)/frequency);
/* Calibration after integration. Same fenced clock and bucket accounting;
no correction is applied to raw ticks. This cannot remove serialization,
compiler-layout, cache, or other workload-dependent indirect effects. */
double calibration[9];PfBucket saved_buckets[LP_NC+2][PF_CATEGORIES];
memcpy(saved_buckets,pf_buckets,sizeof(saved_buckets));
for(int k=0;k<9;k++){
pf_row=0;pf_current=&pf_buckets[0][PF_OTHER];uint64_t begin=pf_clock();pf_previous_tick=begin;
for(int i=0;i<24576;i++)PF_MARK(i&1?PF_OTHER:PF_DISPATCH);
calibration[k]=(double)(pf_clock()-begin)/24576;
}
memcpy(pf_buckets,saved_buckets,sizeof(saved_buckets));
for(int r=0;r<LP_NC+2;r++)for(int c=0;c<PF_CATEGORIES;c++)total_events+=pf_buckets[r][c].intervals;
FILE *f=fopen("profile.json","wb");if(!f)abort();
fprintf(f,"{\"frequency\":%.9f,\"qpcFrequency\":%llu,\"sampledCallbackQpcTicks\":%llu,\"stride\":%u,\"callbacks\":%llu,\"sampledCallbacks\":%llu,\"sampledCallbackTicks\":%llu,\"markerCount\":%llu,\"calibrationTicksPerMarker\":[",
tsc_frequency,(unsigned long long)frequency,(unsigned long long)sampled_qpc_ticks,stride,(unsigned long long)calls,(unsigned long long)sampled,(unsigned long long)sampled_ticks,(unsigned long long)total_events);
for(int i=0;i<9;i++)fprintf(f,"%s%.9f",i?",":"",calibration[i]);
fprintf(f,"],\"categories\":[");for(int i=0;i<PF_CATEGORIES;i++)fprintf(f,"%s\"%s\"",i?",":"",names[i]);
fprintf(f,"],\"rows\":[");uint64_t sum=0;
for(int r=0;r<LP_NC+2;r++){
uint64_t rt[PF_CATEGORIES],ri[PF_CATEGORIES];
for(int c=0;c<PF_CATEGORIES;c++){rt[c]=pf_buckets[r][c].ticks;ri[c]=pf_buckets[r][c].intervals;}
fprintf(f,"%s{\"group\":%d,\"evaluations\":%llu,\"ticks\":",r?",":"",r-2,(unsigned long long)evaluations[r]);array(f,rt,PF_CATEGORIES);
fprintf(f,",\"intervals\":");array(f,ri,PF_CATEGORIES);
if(r>=2){fprintf(f,",\"operations\":");array(f,pf_operations[r-2],2);}fputc('}',f);
for(int c=0;c<PF_CATEGORIES;c++)sum+=rt[c];
}
fprintf(f,"],\"ledgerSumTicks\":%llu}\n",(unsigned long long)sum);fclose(f);
if(sum!=sampled_ticks)abort();
}