优化原生结果编码传输与浏览器缓存,记录八路性能基线
原生结果series通过字节索引直传,C端使用Ryu精确回读编码和64 KiB批量写出;网页采用Float64缓存和CSV工作线程,减少结果处理与保存等待。 补充八路AME曲线核查、全流程分阶段计时、独立编码基准和复现工具,固定后续优化采用修正八路及rtol=1e-8。C写出1.1808→0.1638 s,点击到可查看8.0100→6.9756 s。 验证:最终10项编码专项、29项相关后端回归通过;8份原生结果逐位一致,16次网页结果/CSV/刷新恢复通过。前端构建及缓存/CSV专项在本轮结果处理工作中通过。环境、原始大结果与临时构建不纳入Git。
This commit is contained in:
1 parent
808c484f5b
commit
3bc4be3c06
55 files changed
+20522
-141
No files matched your search
@@ -0,0 +1,83 @@
|
||||
#include "json_numbers.h"
|
||||
#include "ryu/ryu.h"
|
||||
#include <float.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
_Static_assert(sizeof(double)==8 && DBL_MANT_DIG==53 && DBL_MAX_EXP==1024,
|
||||
"Native JSON numbers require IEEE-754 binary64");
|
||||
|
||||
int native_json_format_double(char output[NATIVE_JSON_DOUBLE_CAPACITY], double value) {
|
||||
uint64_t bits;
|
||||
memcpy(&bits,&value,sizeof(bits));
|
||||
uint64_t magnitude=bits & UINT64_C(0x7fffffffffffffff);
|
||||
if (magnitude>=UINT64_C(0x7ff0000000000000)) return 0;
|
||||
if (magnitude==0) {
|
||||
if (bits>>63) { memcpy(output,"-0.0",4); return 4; }
|
||||
output[0]='0'; return 1;
|
||||
}
|
||||
int length=d2s_buffered_n(value,output);
|
||||
/* Ryu returns shortest significant digits in scientific notation. Use
|
||||
ordinary notation only when its JSON token is shorter. This moves an
|
||||
exact decimal point; it never recomputes or rounds the floating value. */
|
||||
char digits[17];
|
||||
int negative=output[0]=='-', count=0, pos=negative;
|
||||
while (output[pos]!='E') {
|
||||
if (output[pos]!='.') digits[count++]=output[pos];
|
||||
pos++;
|
||||
}
|
||||
pos++;
|
||||
int exponent_negative=output[pos]=='-';
|
||||
if (exponent_negative) pos++;
|
||||
int exponent=0;
|
||||
while (pos<length) exponent=exponent*10+(output[pos++]-'0');
|
||||
if (exponent_negative) exponent=-exponent;
|
||||
int point=exponent+1;
|
||||
int fixed_length=negative+(point<=0 ? 2-point+count : point>=count ? point : count+1);
|
||||
if (fixed_length>=length) return length;
|
||||
pos=0;
|
||||
if (negative) output[pos++]='-';
|
||||
if (point<=0) {
|
||||
output[pos++]='0'; output[pos++]='.';
|
||||
for (int i=0;i<-point;i++) output[pos++]='0';
|
||||
memcpy(output+pos,digits,(size_t)count); pos+=count;
|
||||
} else {
|
||||
for (int i=0;i<count;i++) {
|
||||
if (i==point) output[pos++]='.';
|
||||
output[pos++]=digits[i];
|
||||
}
|
||||
for (int i=count;i<point;i++) output[pos++]='0';
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int write_bytes(FILE *file, const char *data, size_t length) {
|
||||
return fwrite(data,1,length,file)==length && !ferror(file);
|
||||
}
|
||||
|
||||
int native_json_write_number(FILE *file, double value) {
|
||||
if (!file || ferror(file)) return 0;
|
||||
char text[NATIVE_JSON_DOUBLE_CAPACITY];
|
||||
int length=native_json_format_double(text,value);
|
||||
return length>0 && write_bytes(file,text,(size_t)length);
|
||||
}
|
||||
|
||||
int native_json_write_array(FILE *file, const double *values, size_t count, size_t stride) {
|
||||
if (!file || ferror(file) || (count && !values)) return 0;
|
||||
if (count>1 && (!stride || stride>(size_t)PTRDIFF_MAX/sizeof(double)/(count-1))) return 0;
|
||||
char buffer[65536];
|
||||
size_t used=1;
|
||||
buffer[0]='[';
|
||||
for (size_t i=0;i<count;i++) {
|
||||
if (used>sizeof(buffer)-NATIVE_JSON_DOUBLE_CAPACITY-2) {
|
||||
if (!write_bytes(file,buffer,used)) return 0;
|
||||
used=0;
|
||||
}
|
||||
if (i) buffer[used++]=',';
|
||||
int length=native_json_format_double(buffer+used,values[i*stride]);
|
||||
if (!length) return 0;
|
||||
used+=(size_t)length;
|
||||
}
|
||||
buffer[used++]=']';
|
||||
return write_bytes(file,buffer,used);
|
||||
}
|
||||
+47
-15
@@ -1,4 +1,5 @@
|
||||
#include "runtime.h"
|
||||
#include "json_numbers.h"
|
||||
#include <sundials/sundials_config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -30,7 +31,19 @@ static int probe(void) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int write_result(NativeRun *r, const char *path) {
|
||||
static int write_result_index(const char *path, long series_start, long series_end,
|
||||
long result_bytes, size_t sample_count) {
|
||||
if(series_start<0 || series_end<series_start || result_bytes<series_end) return 0;
|
||||
FILE *index=fopen(path,"wb"); if(!index) return 0;
|
||||
int ok=fprintf(index,"{\"version\":1,\"seriesStart\":%ld,\"seriesEnd\":%ld,"
|
||||
"\"resultBytes\":%ld,\"sampleCount\":%zu}\n",
|
||||
series_start,series_end,result_bytes,sample_count)>=0;
|
||||
if(ferror(index)) ok=0;
|
||||
if(fclose(index)) ok=0;
|
||||
return ok;
|
||||
}
|
||||
static int write_result(NativeRun *r, const char *path, const char *index_path) {
|
||||
if(index_path && !strcmp(path,index_path)) return 0;
|
||||
double dy[NSTATES], final[NOUTPUTS];
|
||||
int final_ok=model_eval(r->final_time,r->final_state,dy,final);
|
||||
size_t length=r->count*NOUTPUTS;
|
||||
@@ -53,30 +66,48 @@ static int write_result(NativeRun *r, const char *path) {
|
||||
r->options.bdf?"BDF":"RK45",r->options.bdf?"CVODE":"Dormand-Prince 5(4)",SUNDIALS_VERSION,
|
||||
r->final_time,r->solve_seconds,r->solve_cpu_seconds,r->nfev,r->accepted,r->rejected,
|
||||
r->events,r->starts,r->njev,r->nlu,r->max_accepted_step);
|
||||
/* Binary-mode positions delimit the complete series object, including
|
||||
both braces. The optional index avoids scanning or parsing its values. */
|
||||
long series_start=-1,series_end=-1,result_bytes=-1;
|
||||
if(index_path) {
|
||||
series_start=ftell(f);
|
||||
if(series_start>0) series_start--; else series_start=-1;
|
||||
}
|
||||
int output_ok=1;
|
||||
if (r->count) {
|
||||
fprintf(f,"\"time\":[");
|
||||
for (size_t i=0;i<r->count;i++) fprintf(f,"%s%.17g",i?",":"",r->times[i]);
|
||||
fputc(']',f);
|
||||
for (int j=0;j<NOUTPUTS;j++) {
|
||||
fputc(',',f); json_string(f,model_output_keys[j]); fprintf(f,":[");
|
||||
for (size_t i=0;i<r->count;i++) fprintf(f,"%s%.17g",i?",":"",values[i*NOUTPUTS+j]);
|
||||
fputc(']',f);
|
||||
fprintf(f,"\"time\":");
|
||||
output_ok=native_json_write_array(f,r->times,r->count,1);
|
||||
for (int j=0;j<NOUTPUTS && output_ok;j++) {
|
||||
fputc(',',f); json_string(f,model_output_keys[j]); fputc(':',f);
|
||||
output_ok=native_json_write_array(f,values+j,r->count,NOUTPUTS);
|
||||
}
|
||||
}
|
||||
fprintf(f,"},\"final\":{");
|
||||
if (final_ok) for (int j=0;j<NOUTPUTS;j++) {
|
||||
fputc('}',f);
|
||||
if(index_path) series_end=ftell(f);
|
||||
fprintf(f,",\"final\":{");
|
||||
if (final_ok) for (int j=0;j<NOUTPUTS && output_ok;j++) {
|
||||
if (j) fputc(',',f);
|
||||
json_string(f,model_output_keys[j]); fprintf(f,":%.17g",final[j]);
|
||||
json_string(f,model_output_keys[j]); fputc(':',f);
|
||||
output_ok=native_json_write_number(f,final[j]);
|
||||
}
|
||||
fprintf(f,"},\"finalState\":"); vector(f,r->final_state,NSTATES);
|
||||
fprintf(f,"}\n"); int ok=!ferror(f); if (fclose(f)) ok=0;
|
||||
fprintf(f,"},\"finalState\":");
|
||||
if (output_ok) output_ok=native_json_write_array(f,r->final_state,NSTATES,1);
|
||||
fprintf(f,"}\n"); int ok=output_ok && !ferror(f);
|
||||
if(index_path) {
|
||||
result_bytes=ftell(f);
|
||||
if(series_start<0 || series_end<0 || result_bytes<0) ok=0;
|
||||
}
|
||||
if (fclose(f)) ok=0;
|
||||
/* Publish the index only after the complete result was successfully
|
||||
flushed and closed. An index I/O failure is a failed result write. */
|
||||
if(ok && index_path) ok=write_result_index(index_path,series_start,series_end,result_bytes,r->count);
|
||||
free(values); return ok;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
NativeRun r={0};
|
||||
r.options=(NativeOptions){0,10,.02,.001,1e-6,300,0,1,NULL};
|
||||
const char *output="result.json";
|
||||
const char *output="result.json", *index_path=NULL;
|
||||
for (int i=1;i<argc;i++) {
|
||||
const char *arg=argv[i];
|
||||
if (!strcmp(arg,"--probe")) return probe();
|
||||
@@ -88,6 +119,7 @@ int main(int argc, char **argv) {
|
||||
if (i+1==argc) return 64;
|
||||
const char *value=argv[++i];
|
||||
if (!strcmp(arg,"--output")) output=value;
|
||||
else if (!strcmp(arg,"--result-index")) index_path=value;
|
||||
else if (!strcmp(arg,"--cancel-file")) r.options.cancel_path=value;
|
||||
else if (!strcmp(arg,"--method")) {
|
||||
if (strcmp(value,"RK45") && strcmp(value,"BDF")) return 64;
|
||||
@@ -113,7 +145,7 @@ int main(int argc, char **argv) {
|
||||
((r.options.stop-r.options.start)/r.options.sample_step>1000000 ||
|
||||
((r.options.stop-r.options.start)/r.options.sample_step+1024)*(NSTATES+NOUTPUTS)*sizeof(double)>268435456)) return 64;
|
||||
native_solve(&r);
|
||||
int saved=write_result(&r,output);
|
||||
int saved=write_result(&r,output,index_path);
|
||||
int code=saved?(r.status==2?2:0):3;
|
||||
native_run_free(&r); return code;
|
||||
}
|
||||
Reference in new issue
Block a user