相较上一版 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 通过。
87 lines
5.2 KiB
C
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();
|
|
}
|