3x faster table_read() on big data

This commit is contained in:
stefan schippers 2023-02-12 13:36:03 +01:00
parent 6c22c47975
commit 1aaa48a75b
3 changed files with 152 additions and 12 deletions

View File

@ -608,6 +608,129 @@ void set_inst_prop(int i)
}
}
#define is_a_digit(c) ((c) >= '0' && (c) <= '9')
#define is_a_space(c) ((c) == ' ' || (c) == '\t')
/* fast convert (decimal) string to float */
float my_atof(const char *p)
{
static const float p10[]={
1e-1f, 1e-2f, 1e-3f, 1e-4f, 1e-5f, 1e-6f, 1e-7f, 1e-8f
};
int frac;
float sign, value, scale;
/* skip initial spaces */
while(is_a_space(*p)) p++;
/* sign */
sign = 1.0;
if(*p == '-') {
sign = -1.0;
p++;
} else if(*p == '+') {
p++;
}
/* Get digits */
for(value = 0.0; is_a_digit(*p); p++) {
value = value * 10.0f + (*p - '0');
}
/* get fractional part */
if(*p == '.') {
int cnt = 0;
p++;
while (is_a_digit(*p)) {
if(cnt >= 17) continue; /* after 17 skip additional fractional digits */
value += (*(p++) - '0') * p10[cnt++];
}
}
/* Exponent */
frac = 0;
scale = 1.0;
if((*p == 'e') || (*p == 'E')) {
unsigned int exponent;
/* Exponent sign */
p++;
if(*p == '-') {
frac = 1;
p++;
} else if(*p == '+') p++;
/* Get digits of exponent, if any. */
for(exponent = 0; is_a_digit(*p); p += 1) {
exponent = exponent * 10 + (*p - '0');
}
if(exponent > 38) exponent = 38;
/* Calculate scaling factor. */
while (exponent >= 12) { scale *= 1E12f; exponent -= 12; }
while (exponent >= 4) { scale *= 1E4f; exponent -= 4; }
while (exponent > 0) { scale *= 10.0f; exponent -= 1; }
}
return sign * (frac ? (value / scale) : (value * scale));
}
/* fast convert (decimal) string to double */
double my_atod(const char *p)
{
static const double p10[]={
1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9,
1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18
};
int frac;
double sign, value, scale;
/* skip initial spaces */
while(is_a_space(*p)) p++;
/* sign */
sign = 1.0;
if(*p == '-') {
sign = -1.0;
p++;
} else if(*p == '+') {
p++;
}
/* Get digits */
for(value = 0.0; is_a_digit(*p); p++) {
value = value * 10.0 + (*p - '0');
}
/* get fractional part */
if(*p == '.') {
int cnt = 0;
p++;
while (is_a_digit(*p)) {
if(cnt >= 17) continue; /* after 17 skip additional fractional digits */
value += (*(p++) - '0') * p10[cnt++];
}
}
/* Exponent */
frac = 0;
scale = 1.0;
if((*p == 'e') || (*p == 'E')) {
unsigned int exponent;
/* Exponent sign */
p++;
if(*p == '-') {
frac = 1;
p++;
} else if(*p == '+') p++;
/* Get digits of exponent, if any. */
for(exponent = 0; is_a_digit(*p); p += 1) {
exponent = exponent * 10 + (*p - '0');
}
if(exponent > 308) exponent = 308;
/* Calculate scaling factor. */
while (exponent >= 50) { scale *= 1E50; exponent -= 50; }
while (exponent >= 8) { scale *= 1E8; exponent -= 8; }
while (exponent > 0) { scale *= 10.0; exponent -= 1; }
}
return sign * (frac ? (value / scale) : (value * scale));
}
/* super fast count # of lines (and bytes) in a file */
int count_lines_bytes(int fd, size_t *lines, size_t *bytes)
{

View File

@ -383,20 +383,20 @@ static void read_binary_block(FILE *fd)
if(ac) {
for(v = 0; v < xctx->graph_nvars; v += 2) { /*AC analysis: calculate magnitude */
if( v == 0 ) /* sweep var */
xctx->graph_values[v][offset + p] = (float)sqrt( tmp[v] * tmp[v] + tmp[v + 1] * tmp[v + 1]);
xctx->graph_values[v][offset + p] = (SPICE_DATA)sqrt( tmp[v] * tmp[v] + tmp[v + 1] * tmp[v + 1]);
else /* magnitude */
/* avoid 0 for dB calculations */
if(tmp[v] == 0.0 && tmp[v + 1] == 0.0) xctx->graph_values[v][offset + p] = 1e-35f;
else xctx->graph_values[v][offset + p] =
(float)sqrt(tmp[v] * tmp[v] + tmp[v + 1] * tmp[v + 1]);
(SPICE_DATA)sqrt(tmp[v] * tmp[v] + tmp[v + 1] * tmp[v + 1]);
/* AC analysis: calculate phase */
if(tmp[v] == 0.0 && tmp[v + 1] == 0.0) xctx->graph_values[v + 1] [offset + p] = 0.0;
else xctx->graph_values[v + 1] [offset + p] =
(float)(atan2(tmp[v + 1], tmp[v]) * 180.0 / XSCH_PI);
(SPICE_DATA)(atan2(tmp[v + 1], tmp[v]) * 180.0 / XSCH_PI);
}
}
else for(v = 0; v < xctx->graph_nvars; v++) {
xctx->graph_values[v][offset + p] = (float)tmp[v];
xctx->graph_values[v][offset + p] = (SPICE_DATA)tmp[v];
}
}
my_free(_ALLOC_ID_, &tmp);
@ -761,6 +761,8 @@ int table_read(const char *f)
{
int res = 0;
FILE *fd;
int ufd;
size_t lines, bytes;
char *line = NULL, *line_ptr, *line_save;
const char *line_tok;
@ -768,6 +770,12 @@ int table_read(const char *f)
dbg(0, "table_read(): must clear current data file before loading new\n");
return 0;
}
/* quick inspect file and get upper bound of number of data lines */
ufd = open(f, O_RDONLY);
if(ufd < 0) goto err;
count_lines_bytes(ufd, &lines, &bytes);
close(ufd);
int_hash_init(&xctx->graph_raw_table, HASHSIZE);
fd = fopen(f, fopen_read_mode);
if(fd) {
@ -803,28 +811,37 @@ int table_read(const char *f)
field = 0;
while( (line_tok = strtok_r(line_ptr, " \t\n", &line_save)) ) {
line_ptr = NULL;
dbg(1,"%s ", line_tok);
/* dbg(1,"%s ", line_tok); */
if(nline == 0) { /* header line */
my_realloc(_ALLOC_ID_, &xctx->graph_names, (field + 1) * sizeof(char *));
xctx->graph_names[field] = NULL;
my_strcat(_ALLOC_ID_, &xctx->graph_names[field], line_tok);
int_hash_lookup(&xctx->graph_raw_table, xctx->graph_names[field], field, XINSERT_NOREPLACE);
xctx->graph_nvars = field + 1;
} else { /* data line */
my_realloc(_ALLOC_ID_, &xctx->graph_values[field], (npoints + 1) * sizeof(SPICE_DATA));
xctx->graph_values[field][npoints] = (float)atof(line_tok);
if(field >= xctx->graph_nvars) break;
#if SPICE_DATA == float
xctx->graph_values[field][npoints] = (SPICE_DATA)my_atof(line_tok);
#else
xctx->graph_values[field][npoints] = (SPICE_DATA)my_atod(line_tok);
#endif
}
field++;
xctx->graph_nvars = field;
}
if(nline) { /* skip header line for npoints calculation*/
npoints++;
dataset_points++;
}
xctx->graph_npoints[xctx->graph_datasets - 1] = dataset_points;
dbg(1, "\n");
/* dbg(1, "\n"); */
nline++;
if(nline == 1) {
int f;
xctx->graph_values = my_calloc(_ALLOC_ID_, xctx->graph_nvars + 1, sizeof(SPICE_DATA *));
for(f = 0; f <= xctx->graph_nvars; f++) { /* one extra column for wave expressions */
my_realloc(_ALLOC_ID_, &xctx->graph_values[f], lines * sizeof(SPICE_DATA));
}
}
clear:
my_free(_ALLOC_ID_, &line);
@ -842,8 +859,6 @@ int table_read(const char *f)
dbg(0, "Table file data read: %s\n", f);
dbg(0, "points=%d, vars=%d, datasets=%d\n",
xctx->graph_allpoints, xctx->graph_nvars, xctx->graph_datasets);
/* allocate extra column for custom calculated data (expressions) */
my_realloc(_ALLOC_ID_, &xctx->graph_values[xctx->graph_nvars], npoints * sizeof(SPICE_DATA));
} else {
dbg(0, "table_read(): no useful data found\n");
}
@ -1312,7 +1327,7 @@ int plot_raw_custom_data(int sweep_idx, int first, int last, const char *expr)
} /* switch(...) */
} /* if(stackptr2 > 0) */
} /* for(i = 0; i < stackptr1; i++) */
y[p] = (float)stack2[0];
y[p] = (SPICE_DATA)stack2[0];
} /* for(p = first ...) */
ravg_store(0, 0, 0, 0, 0.0); /* clear data */
return xctx->graph_nvars;

View File

@ -1399,6 +1399,8 @@ extern double round_to_n_digits(double x, int n);
extern double floor_to_n_digits(double x, int n);
extern double ceil_to_n_digits(double x, int n);
extern int count_lines_bytes(int fd, size_t *lines, size_t *bytes);
extern double my_atod(const char *p);
extern float my_atof(const char *p);
extern const char *subst_token(const char *s, const char *tok, const char *new_val);
extern void new_prop_string(int i, const char *old_prop,int fast, int dis_uniq_names);
extern void hash_name(char *token, int remove);