/* Standalone experiment support; never linked by the production builder. */ #define _WIN32_WINNT 0x0600 #include "local_probe.h" #include #include #include #include #include /* GENERATED_TABLES */ int lp_color=-1,lp_active=-1,lp_capture=0,lp_observe=LP_OBSERVE; uint64_t lp_mask; typedef struct { size_t count,capacity; NativePropertyTemperatures *temperatures; NativeJacobianScalars *jacobian; NativePropertyState states[LP_NPS]; NativePipeCache pipes[LP_NPC]; } Snapshot; typedef struct { Snapshot snapshots[LP_NB]; double p[LP_NP],h[LP_NQ],q[LP_NQ],w[NOUTPUTS],fb[LP_NFB]; double t,y[NSTATES];int ready; } Workspace; static Workspace *saved; static unsigned char needed[LP_NB],captured[LP_NB]; static FILE *matrix_file,*event_file; static uint64_t frequency,jac_ticks,jac_calls,newton_iterations,newton_failures,audit_count,audit_diff; static uint64_t executed[LP_NC][LP_NO],skipped[LP_NC][LP_NO],kernel_calls[LP_NC+1][LP_NK]; static uint64_t attempts[LP_NC],hits[LP_NC],context_misses[LP_NC],invalid_trials[LP_NC]; static uint64_t compared_bytes,copied_bytes,model_calls[LP_NC+1]; uint64_t lp_tick(void){LARGE_INTEGER t;QueryPerformanceCounter(&t);return (uint64_t)t.QuadPart;} void lp_jac_time(uint64_t start){jac_ticks+=lp_tick()-start;jac_calls++;} void lp_newton(long iterations,long failures){newton_iterations+=(uint64_t)iterations;newton_failures+=(uint64_t)failures;} void lp_start(void){ LARGE_INTEGER f;QueryPerformanceFrequency(&f);frequency=(uint64_t)f.QuadPart; const char *mask=getenv("LOCAL_PROBE_MASK");lp_mask=mask?strtoull(mask,NULL,0):0; if(lp_mask){saved=calloc(1,sizeof(*saved));if(!saved){fprintf(stderr,"local probe workspace allocation failed\n");abort();}} for(int g=0;g=0){needed[lp_before[r]]=1;needed[lp_after[r]]=1;} } event_file=fopen("events.bin","wb");if(!event_file)abort(); if(lp_observe){matrix_file=fopen("jacobians.bin","wb");if(!matrix_file)abort();setvbuf(matrix_file,NULL,_IOFBF,1024*1024);} } void lp_begin(double t,const double *y){ if(saved){saved->ready=0;saved->t=t;memcpy(saved->y,y,sizeof(saved->y));memset(captured,0,sizeof(captured));} } void lp_ready(int ok){if(saved)saved->ready=ok;} int lp_valid(double t,const double *y){ if(!saved || !saved->ready || memcmp(&t,&saved->t,sizeof(double)))return 0; for(int i=0;iy+i,sizeof(double))){invalid_trials[lp_color]++;return 0;} return 1; } void lp_snapshot(int index,NativePropertyCache *properties,NativePipeCache *pipes){ if(!needed[index] || captured[index])return; captured[index]=1; Snapshot *s=&saved->snapshots[index]; if(properties->count>LP_NPS || properties->capacity!=LP_NPS || properties->temperatures){fprintf(stderr,"unsupported local property context\n");abort();} s->count=properties->count;s->capacity=properties->capacity;s->temperatures=properties->temperatures;s->jacobian=properties->jacobian; memcpy(s->states,properties->states,s->count*sizeof(*s->states));memcpy(s->pipes,pipes,sizeof(s->pipes)); copied_bytes+=s->count*sizeof(*s->states)+sizeof(s->pipes); } void lp_save(double *p,double *h,double *q,double *w,double *fb){ memcpy(saved->p,p,sizeof(saved->p));memcpy(saved->h,h,sizeof(saved->h));memcpy(saved->q,q,sizeof(saved->q)); memcpy(saved->w,w,sizeof(saved->w));memcpy(saved->fb,fb,sizeof(saved->fb)); } int lp_reuse(int region,NativePropertyCache *properties,NativePipeCache *pipes,double *p,double *h,double *q,double *w,double *fb){ Snapshot *before=&saved->snapshots[lp_before[region]],*after=&saved->snapshots[lp_after[region]]; attempts[lp_color]++; int contextual=lp_before[region]!=lp_after[region]; if(contextual && (properties->count!=before->count || properties->capacity!=before->capacity || properties->temperatures!=before->temperatures || properties->jacobian!=before->jacobian)){context_misses[lp_color]++;return 0;} size_t n=before->count*sizeof(*before->states); if(contextual){compared_bytes+=n+sizeof(before->pipes); if(memcmp(properties->states,before->states,n) || memcmp(pipes,before->pipes,sizeof(before->pipes))){context_misses[lp_color]++;return 0;} } /* Preserve the exact baseline cache mutations, including seeded rho/h and computed isentropic fields; never synthesize a context from (p,T) alone. Jacobian scalar entries are immutable after baseline; only their telemetry counters differ when actual kernel requests are avoided. */ if(contextual){properties->count=after->count; memcpy(properties->states,after->states,after->count*sizeof(*after->states));memcpy(pipes,after->pipes,sizeof(after->pipes)); copied_bytes+=after->count*sizeof(*after->states)+sizeof(after->pipes); } double *dst[]={p,h,q,w,fb};double *src[]={saved->p,saved->h,saved->q,saved->w,saved->fb}; for(int i=lp_first_output[region];i0)executed[lp_active-1][lp_operation_id[position]]++;} #endif void lp_kernel(int kind){if(lp_active>=0 && lp_active<=LP_NC)kernel_calls[lp_active][kind]++;} void lp_compare(int ok,const double *dy,const double *w,int expected_ok,const double *expected_dy,const double *expected_w){ audit_count++; if(ok!=expected_ok || (ok && (memcmp(dy,expected_dy,NSTATES*sizeof(double)) || memcmp(w,expected_w,NOUTPUTS*sizeof(double))))){ audit_diff++;fprintf(stderr,"probe exact mismatch color=%d comparison=%llu\n",lp_color,(unsigned long long)audit_count); for(int i=0;i=0 && !local)for(int i=0;i