📄 stats.c
字号:
}#endif /* __GNUC__ *//* register a float statistical variable */struct stat_stat_t *stat_reg_float(struct stat_sdb_t *sdb, /* stat database */ char *name, /* stat variable name */ char *desc, /* stat variable description */ float *var, /* stat variable */ float init_val, /* stat variable initial value */ char *format) /* optional variable output format */{ struct stat_stat_t *stat; stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t)); if (!stat) fatal("out of virtual memory"); stat->name = mystrdup(name); stat->desc = mystrdup(desc); stat->format = format ? format : "%12.4f"; stat->sc = sc_float; stat->variant.for_float.var = var; stat->variant.for_float.init_val = init_val; /* link onto SDB chain */ add_stat(sdb, stat); /* initialize stat */ *var = init_val; return stat;}/* register a double statistical variable */struct stat_stat_t *stat_reg_double(struct stat_sdb_t *sdb, /* stat database */ char *name, /* stat variable name */ char *desc, /* stat variable description */ double *var, /* stat variable */ double init_val, /* stat variable initial value */ char *format) /* optional variable output format */{ struct stat_stat_t *stat; stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t)); if (!stat) fatal("out of virtual memory"); stat->name = mystrdup(name); stat->desc = mystrdup(desc); stat->format = format ? format : "%12.4f"; stat->sc = sc_double; stat->variant.for_double.var = var; stat->variant.for_double.init_val = init_val; /* link onto SDB chain */ add_stat(sdb, stat); /* initialize stat */ *var = init_val; return stat;}/* create an array distribution (w/ fixed size buckets) in stat database SDB, the array distribution has ARR_SZ buckets with BUCKET_SZ indicies in each bucked, PF specifies the distribution components to print for optional format FORMAT; the indicies may be optionally replaced with the strings from IMAP, or the entire distribution can be printed with the optional user-specified print function PRINT_FN */struct stat_stat_t *stat_reg_dist(struct stat_sdb_t *sdb, /* stat database */ char *name, /* stat variable name */ char *desc, /* stat variable description */ unsigned int init_val, /* dist initial value */ unsigned int arr_sz, /* array size */ unsigned int bucket_sz, /* array bucket size */ int pf, /* print format, use PF_* defs */ char *format, /* optional variable output format */ char **imap, /* optional index -> string map */ print_fn_t print_fn) /* optional user print function */{ unsigned int i; struct stat_stat_t *stat; unsigned int *arr; stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t)); if (!stat) fatal("out of virtual memory"); stat->name = mystrdup(name); stat->desc = mystrdup(desc); stat->format = format ? format : NULL; stat->sc = sc_dist; stat->variant.for_dist.init_val = init_val; stat->variant.for_dist.arr_sz = arr_sz; stat->variant.for_dist.bucket_sz = bucket_sz; stat->variant.for_dist.pf = pf; stat->variant.for_dist.imap = imap; stat->variant.for_dist.print_fn = print_fn; stat->variant.for_dist.overflows = 0; arr = (unsigned int *)calloc(arr_sz, sizeof(unsigned int)); if (!arr) fatal("out of virtual memory"); stat->variant.for_dist.arr = arr; /* link onto SDB chain */ add_stat(sdb, stat); /* initialize stat */ for (i=0; i < arr_sz; i++) arr[i] = init_val; return stat;}/* create a sparse array distribution in stat database SDB, while the sparse array consumes more memory per bucket than an array distribution, it can efficiently map any number of indicies from 0 to 2^32-1, PF specifies the distribution components to print for optional format FORMAT; the indicies may be optionally replaced with the strings from IMAP, or the entire distribution can be printed with the optional user-specified print function PRINT_FN */struct stat_stat_t *stat_reg_sdist(struct stat_sdb_t *sdb, /* stat database */ char *name, /* stat variable name */ char *desc, /* stat variable description */ unsigned int init_val, /* dist initial value */ int pf, /* print format, use PF_* defs */ char *format, /* optional variable output format */ print_fn_t print_fn) /* optional user print function */{ struct stat_stat_t *stat; struct bucket_t **sarr; stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t)); if (!stat) fatal("out of virtual memory"); stat->name = mystrdup(name); stat->desc = mystrdup(desc); stat->format = format ? format : NULL; stat->sc = sc_sdist; stat->variant.for_sdist.init_val = init_val; stat->variant.for_sdist.pf = pf; stat->variant.for_sdist.print_fn = print_fn; /* allocate hash table */ sarr = (struct bucket_t **)calloc(HTAB_SZ, sizeof(struct bucket_t *)); if (!sarr) fatal("out of virtual memory"); stat->variant.for_sdist.sarr = sarr; /* link onto SDB chain */ add_stat(sdb, stat); return stat;}/* add NSAMPLES to array or sparse array distribution STAT */voidstat_add_samples(struct stat_stat_t *stat,/* stat database */ unsigned int index, /* distribution index of samples */ int nsamples) /* number of samples to add to dist */{ switch (stat->sc) { case sc_dist: { unsigned int i; /* compute array index */ i = index / stat->variant.for_dist.bucket_sz; /* check for overflow */ if (i >= stat->variant.for_dist.arr_sz) stat->variant.for_dist.overflows += nsamples; else stat->variant.for_dist.arr[i] += nsamples; } break; case sc_sdist: { struct bucket_t *bucket; /* find bucket */ for (bucket = stat->variant.for_sdist.sarr[HTAB_HASH(index)]; bucket != NULL; bucket = bucket->next) { if (bucket->index == index) break; } if (!bucket) { /* add a new sample bucket */ bucket = (struct bucket_t *)calloc(1, sizeof(struct bucket_t)); if (!bucket) fatal("out of virtual memory"); bucket->next = stat->variant.for_sdist.sarr[HTAB_HASH(index)]; stat->variant.for_sdist.sarr[HTAB_HASH(index)] = bucket; bucket->index = index; bucket->count = stat->variant.for_sdist.init_val; } bucket->count += nsamples; } break; default: panic("stat variable is not an array distribution"); }}/* add a single sample to array or sparse array distribution STAT */voidstat_add_sample(struct stat_stat_t *stat,/* stat variable */ unsigned int index) /* index of sample */{ stat_add_samples(stat, index, 1);}/* register a double statistical formula, the formula is evaluated when the statistic is printed, the formula expression may reference any registered statistical variable and, in addition, the standard operators '(', ')', '+', '-', '*', and '/', and literal (i.e., C-format decimal, hexidecimal, and octal) constants are also supported; NOTE: all terms are immediately converted to double values and the result is a double value, see eval.h for more information on formulas */struct stat_stat_t *stat_reg_formula(struct stat_sdb_t *sdb,/* stat database */ char *name, /* stat variable name */ char *desc, /* stat variable description */ char *formula, /* formula expression */ char *format) /* optional variable output format */{ struct stat_stat_t *stat; stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t)); if (!stat) fatal("out of virtual memory"); stat->name = mystrdup(name); stat->desc = mystrdup(desc); stat->format = format ? format : "%12.4f"; stat->sc = sc_formula; stat->variant.for_formula.formula = mystrdup(formula); /* link onto SDB chain */ add_stat(sdb, stat); return stat;}/* compare two indicies in a sparse array hash table, used by qsort() */static intcompare_fn(void *p1, void *p2){ struct bucket_t **pb1 = p1, **pb2 = p2; /* compare indices */ if ((*pb1)->index < (*pb2)->index) return -1; else if ((*pb1)->index > (*pb2)->index) return 1; else /* ((*pb1)->index == (*pb2)->index) */ return 0;}/* print an array distribution */static voidprint_dist(struct stat_stat_t *stat, /* stat variable */ FILE *fd) /* output stream */{ unsigned int i, bcount, imax, imin; double btotal, bsum, bvar, bavg, bsqsum; int pf = stat->variant.for_dist.pf; /* count and sum entries */ bcount = 0; btotal = 0.0; bvar = 0.0; bsqsum = 0.0; imax = 0; imin = UINT_MAX; for (i=0; i<stat->variant.for_dist.arr_sz; i++) { bcount++; btotal += stat->variant.for_dist.arr[i]; /* on-line variance computation, tres cool, no!?! */ bsqsum += ((double)stat->variant.for_dist.arr[i] * (double)stat->variant.for_dist.arr[i]); bavg = btotal / MAX((double)bcount, 1.0); bvar = (bsqsum - ((double)bcount * bavg * bavg)) / (double)(((bcount - 1) > 0) ? (bcount - 1) : 1); } /* print header */ fprintf(fd, "\n"); fprintf(fd, "%-22s # %s\n", stat->name, stat->desc); fprintf(fd, "%s.array_size = %u\n", stat->name, stat->variant.for_dist.arr_sz); fprintf(fd, "%s.bucket_size = %u\n", stat->name, stat->variant.for_dist.bucket_sz); fprintf(fd, "%s.count = %u\n", stat->name, bcount); fprintf(fd, "%s.total = %.0f\n", stat->name, btotal); if (bcount > 0) { fprintf(fd, "%s.imin = %u\n", stat->name, 0U); fprintf(fd, "%s.imax = %u\n", stat->name, bcount); } else { fprintf(fd, "%s.imin = %d\n", stat->name, -1); fprintf(fd, "%s.imax = %d\n", stat->name, -1); } fprintf(fd, "%s.average = %8.4f\n", stat->name, btotal/MAX(bcount, 1.0)); fprintf(fd, "%s.std_dev = %8.4f\n", stat->name, sqrt(bvar)); fprintf(fd, "%s.overflows = %u\n", stat->name, stat->variant.for_dist.overflows); fprintf(fd, "# pdf == prob dist fn, cdf == cumulative dist fn\n"); fprintf(fd, "# %14s ", "index"); if (pf & PF_COUNT) fprintf(fd, "%10s ", "count"); if (pf & PF_PDF) fprintf(fd, "%6s ", "pdf"); if (pf & PF_CDF) fprintf(fd, "%6s ", "cdf"); fprintf(fd, "\n"); fprintf(fd, "%s.start_dist\n", stat->name); if (bcount > 0) { /* print the array */ bsum = 0.0; for (i=0; i<bcount; i++) { bsum += (double)stat->variant.for_dist.arr[i]; if (stat->variant.for_dist.print_fn) { stat->variant.for_dist.print_fn(stat, i, stat->variant.for_dist.arr[i], bsum, btotal); } else { if (stat->format == NULL) { if (stat->variant.for_dist.imap) fprintf(fd, "%-16s ", stat->variant.for_dist.imap[i]); else fprintf(fd, "%16u ", i * stat->variant.for_dist.bucket_sz); if (pf & PF_COUNT) fprintf(fd, "%10u ", stat->variant.for_dist.arr[i]); if (pf & PF_PDF) fprintf(fd, "%6.2f ", (double)stat->variant.for_dist.arr[i] / MAX(btotal, 1.0) * 100.0); if (pf & PF_CDF) fprintf(fd, "%6.2f ", bsum/MAX(btotal, 1.0) * 100.0); } else { if (pf == (PF_COUNT|PF_PDF|PF_CDF)) { if (stat->variant.for_dist.imap) fprintf(fd, stat->format, stat->variant.for_dist.imap[i], stat->variant.for_dist.arr[i], (double)stat->variant.for_dist.arr[i] / MAX(btotal, 1.0) * 100.0, bsum/MAX(btotal, 1.0) * 100.0); else fprintf(fd, stat->format, i * stat->variant.for_dist.bucket_sz, stat->variant.for_dist.arr[i], (double)stat->variant.for_dist.arr[i] / MAX(btotal, 1.0) * 100.0, bsum/MAX(btotal, 1.0) * 100.0); } else fatal("distribution format not yet implemented");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -