"I am a person who works hard and plays hard."

Yuan Wei
Second Year Graduate Student Department of Computer Science
University of Virginia Charlottesville, VA 22903
Email: yw3f@cs.virginia.edu


Source Code Analysis

Main Page   Compound List   File List   Compound Members   File Members  

stats.c

Go to the documentation of this file.
00001 /*
00002  * stats.c - statistical package routines
00003  *
00004  * This file is a part of the SimpleScalar tool suite written by
00005  * Todd M. Austin as a part of the Multiscalar Research Project.
00006  *  
00007  * The tool suite is currently maintained by Doug Burger and Todd M. Austin.
00008  * 
00009  * Copyright (C) 1994, 1995, 1996, 1997, 1998 by Todd M. Austin
00010  *
00011  * This source file is distributed "as is" in the hope that it will be
00012  * useful.  The tool set comes with no warranty, and no author or
00013  * distributor accepts any responsibility for the consequences of its
00014  * use. 
00015  * 
00016  * Everyone is granted permission to copy, modify and redistribute
00017  * this tool set under the following conditions:
00018  * 
00019  *    This source code is distributed for non-commercial use only. 
00020  *    Please contact the maintainer for restrictions applying to 
00021  *    commercial use.
00022  *
00023  *    Permission is granted to anyone to make or distribute copies
00024  *    of this source code, either as received or modified, in any
00025  *    medium, provided that all copyright notices, permission and
00026  *    nonwarranty notices are preserved, and that the distributor
00027  *    grants the recipient permission for further redistribution as
00028  *    permitted by this document.
00029  *
00030  *    Permission is granted to distribute this file in compiled
00031  *    or executable form under the same conditions that apply for
00032  *    source code, provided that either:
00033  *
00034  *    A. it is accompanied by the corresponding machine-readable
00035  *       source code,
00036  *    B. it is accompanied by a written offer, with no time limit,
00037  *       to give anyone a machine-readable copy of the corresponding
00038  *       source code in return for reimbursement of the cost of
00039  *       distribution.  This written offer must permit verbatim
00040  *       duplication by anyone, or
00041  *    C. it is distributed by someone who received only the
00042  *       executable form, and is accompanied by a copy of the
00043  *       written offer of source code that they received concurrently.
00044  *
00045  * In other words, you are welcome to use, share and improve this
00046  * source file.  You are forbidden to forbid anyone else to use, share
00047  * and improve what you give them.
00048  *
00049  * INTERNET: dburger@cs.wisc.edu
00050  * US Mail:  1210 W. Dayton Street, Madison, WI 53706
00051  *
00052  * $Id: stats.c,v 1.1.1.1 2000/05/26 15:18:59 taustin Exp $
00053  *
00054  * $Log: stats.c,v $
00055  * Revision 1.1.1.1  2000/05/26 15:18:59  taustin
00056  * SimpleScalar Tool Set
00057  *
00058  *
00059  * Revision 1.3  1999/12/31 18:53:47  taustin
00060  * quad_t naming conflicts removed
00061  *
00062  * Revision 1.2  1998/08/27 16:39:40  taustin
00063  * implemented host interface description in host.h
00064  * added target interface support
00065  * added support for MS VC++ compilation
00066  * added support for qword's
00067  *
00068  * Revision 1.1  1997/03/11  01:34:15  taustin
00069  * Initial revision
00070  *
00071  *
00072  */
00073 
00074 #include <stdio.h>
00075 #include <stdlib.h>
00076 #include <limits.h>
00077 #include <math.h>
00078 
00079 #include "host.h"
00080 #include "misc.h"
00081 #include "machine.h"
00082 #include "eval.h"
00083 #include "stats.h"
00084 
00085 /* evaluate a stat as an expression */
00086 struct eval_value_t
00087 stat_eval_ident(struct eval_state_t *es)/* an expression evaluator */
00088 {
00089   struct stat_sdb_t *sdb = es->user_ptr;
00090   struct stat_stat_t *stat;
00091   static struct eval_value_t err_value = { et_int, { 0 } };
00092   struct eval_value_t val;
00093 
00094   /* locate the stat variable */
00095   for (stat = sdb->stats; stat != NULL; stat = stat->next)
00096     {
00097       if (!strcmp(stat->name, es->tok_buf))
00098         {
00099           /* found it! */
00100           break;
00101         }
00102     }
00103   if (!stat)
00104     {
00105       /* could not find stat variable */
00106       eval_error = ERR_UNDEFVAR;
00107       return err_value;
00108     }
00109   /* else, return the value of stat */
00110 
00111   /* convert the stat variable value to a typed expression value */
00112   switch (stat->sc)
00113     {
00114     case sc_int:
00115       val.type = et_int;
00116       val.value.as_int = *stat->variant.for_int.var;
00117       break;
00118     case sc_uint:
00119       val.type = et_uint;
00120       val.value.as_uint = *stat->variant.for_uint.var;
00121       break;
00122 #ifdef HOST_HAS_QWORD
00123     case sc_qword:
00124       /* FIXME: cast to double, eval package doesn't support long long's */
00125       val.type = et_double;
00126 #ifdef _MSC_VER /* FIXME: MSC does not implement qword_t to dbl conversion */
00127       val.value.as_double = (double)(sqword_t)*stat->variant.for_qword.var;
00128 #else /* !_MSC_VER */
00129       val.value.as_double = (double)*stat->variant.for_qword.var;
00130 #endif /* _MSC_VER */
00131       break;
00132     case sc_sqword:
00133       /* FIXME: cast to double, eval package doesn't support long long's */
00134       val.type = et_double;
00135       val.value.as_double = (double)*stat->variant.for_sqword.var;
00136       break;
00137 #endif /* HOST_HAS_QWORD */
00138     case sc_float:
00139       val.type = et_float;
00140       val.value.as_float = *stat->variant.for_float.var;
00141       break;
00142     case sc_double:
00143       val.type = et_double;
00144       val.value.as_double = *stat->variant.for_double.var;
00145       break;
00146     case sc_dist:
00147     case sc_sdist:
00148       fatal("stat distributions not allowed in formula expressions");
00149       break;
00150     case sc_formula:
00151       {
00152         /* instantiate a new evaluator to avoid recursion problems */
00153         struct eval_state_t *es = eval_new(stat_eval_ident, sdb);
00154         char *endp;
00155 
00156         val = eval_expr(es, stat->variant.for_formula.formula, &endp);
00157         if (eval_error != ERR_NOERR || *endp != '\0')
00158           {
00159             /* pass through eval_error */
00160             val = err_value;
00161           }
00162         /* else, use value returned */
00163         eval_delete(es);
00164       }
00165       break;
00166     default:
00167       panic("bogus stat class");
00168     }
00169 
00170   return val;
00171 }
00172 
00173 /* create a new stats database */
00174 struct stat_sdb_t *
00175 stat_new(void)
00176 {
00177   struct stat_sdb_t *sdb;
00178 
00179   sdb = (struct stat_sdb_t *)calloc(1, sizeof(struct stat_sdb_t));
00180   if (!sdb)
00181     fatal("out of virtual memory");
00182 
00183   sdb->stats = NULL;
00184   sdb->evaluator = eval_new(stat_eval_ident, sdb);
00185 
00186   return sdb;
00187 }
00188 
00189 /* delete a stats database */
00190 void
00191 stat_delete(struct stat_sdb_t *sdb)     /* stats database */
00192 {
00193   int i;
00194   struct stat_stat_t *stat, *stat_next;
00195   struct bucket_t *bucket, *bucket_next;
00196 
00197   /* free all individual stat variables */
00198   for (stat = sdb->stats; stat != NULL; stat = stat_next)
00199     {
00200       stat_next = stat->next;
00201       stat->next = NULL;
00202 
00203       /* free stat */
00204       switch (stat->sc)
00205         {
00206         case sc_int:
00207         case sc_uint:
00208 #ifdef HOST_HAS_QWORD
00209         case sc_qword:
00210         case sc_sqword:
00211 #endif /* HOST_HAS_QWORD */
00212         case sc_float:
00213         case sc_double:
00214         case sc_formula:
00215           /* no other storage to deallocate */
00216           break;
00217         case sc_dist:
00218           /* free distribution array */
00219           free(stat->variant.for_dist.arr);
00220           stat->variant.for_dist.arr = NULL;
00221           break;
00222         case sc_sdist:
00223           /* free all hash table buckets */
00224           for (i=0; i<HTAB_SZ; i++)
00225             {
00226               for (bucket = stat->variant.for_sdist.sarr[i];
00227                    bucket != NULL;
00228                    bucket = bucket_next)
00229                 {
00230                   bucket_next = bucket->next;
00231                   bucket->next = NULL;
00232                   free(bucket);
00233                 }
00234               stat->variant.for_sdist.sarr[i] = NULL;
00235             }
00236           /* free hash table array */
00237           free(stat->variant.for_sdist.sarr);
00238           stat->variant.for_sdist.sarr = NULL;
00239           break;
00240         default:
00241           panic("bogus stat class");
00242         }
00243       /* free stat variable record */
00244       free(stat);
00245     }
00246   sdb->stats = NULL;
00247   eval_delete(sdb->evaluator);
00248   sdb->evaluator = NULL;
00249   free(sdb);
00250 }
00251 
00252 /* add stat variable STAT to stat database SDB */
00253 static void
00254 add_stat(struct stat_sdb_t *sdb,        /* stat database */
00255          struct stat_stat_t *stat)      /* stat variable */
00256 {
00257   struct stat_stat_t *elt, *prev;
00258 
00259   /* append at end of stat database list */
00260   for (prev=NULL, elt=sdb->stats; elt != NULL; prev=elt, elt=elt->next)
00261     /* nada */;
00262 
00263   /* append stat to stats chain */
00264   if (prev != NULL)
00265     prev->next = stat;
00266   else /* prev == NULL */
00267     sdb->stats = stat;
00268   stat->next = NULL;
00269 }
00270 
00271 /* register an integer statistical variable */
00272 struct stat_stat_t *
00273 stat_reg_int(struct stat_sdb_t *sdb,    /* stat database */
00274              char *name,                /* stat variable name */
00275              char *desc,                /* stat variable description */
00276              int *var,                  /* stat variable */
00277              int init_val,              /* stat variable initial value */
00278              char *format)              /* optional variable output format */
00279 {
00280   struct stat_stat_t *stat;
00281 
00282   stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t));
00283   if (!stat)
00284     fatal("out of virtual memory");
00285 
00286   stat->name = mystrdup(name);
00287   stat->desc = mystrdup(desc);
00288   stat->format = format ? format : "%12d";
00289   stat->sc = sc_int;
00290   stat->variant.for_int.var = var;
00291   stat->variant.for_int.init_val = init_val;
00292 
00293   /* link onto SDB chain */
00294   add_stat(sdb, stat);
00295 
00296   /* initialize stat */
00297   *var = init_val;
00298 
00299   return stat;
00300 }
00301 
00302 /* register an unsigned integer statistical variable */
00303 struct stat_stat_t *
00304 stat_reg_uint(struct stat_sdb_t *sdb,   /* stat database */
00305               char *name,               /* stat variable name */
00306               char *desc,               /* stat variable description */
00307               unsigned int *var,        /* stat variable */
00308               unsigned int init_val,    /* stat variable initial value */
00309               char *format)             /* optional variable output format */
00310 {
00311   struct stat_stat_t *stat;
00312 
00313   stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t));
00314   if (!stat)
00315     fatal("out of virtual memory");
00316 
00317   stat->name = mystrdup(name);
00318   stat->desc = mystrdup(desc);
00319   stat->format = format ? format : "%12u";
00320   stat->sc = sc_uint;
00321   stat->variant.for_uint.var = var;
00322   stat->variant.for_uint.init_val = init_val;
00323 
00324   /* link onto SDB chain */
00325   add_stat(sdb, stat);
00326 
00327   /* initialize stat */
00328   *var = init_val;
00329 
00330   return stat;
00331 }
00332 
00333 #ifdef HOST_HAS_QWORD
00334 /* register a qword integer statistical variable */
00335 struct stat_stat_t *
00336 stat_reg_qword(struct stat_sdb_t *sdb,  /* stat database */
00337               char *name,               /* stat variable name */
00338               char *desc,               /* stat variable description */
00339               qword_t *var,             /* stat variable */
00340               qword_t init_val,         /* stat variable initial value */
00341               char *format)             /* optional variable output format */
00342 {
00343   struct stat_stat_t *stat;
00344 
00345   stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t));
00346   if (!stat)
00347     fatal("out of virtual memory");
00348 
00349   stat->name = mystrdup(name);
00350   stat->desc = mystrdup(desc);
00351   stat->format = format ? format : "%12lu";
00352   stat->sc = sc_qword;
00353   stat->variant.for_qword.var = var;
00354   stat->variant.for_qword.init_val = init_val;
00355 
00356   /* link onto SDB chain */
00357   add_stat(sdb, stat);
00358 
00359   /* initialize stat */
00360   *var = init_val;
00361 
00362   return stat;
00363 }
00364 
00365 /* register a signed qword integer statistical variable */
00366 struct stat_stat_t *
00367 stat_reg_sqword(struct stat_sdb_t *sdb, /* stat database */
00368                char *name,              /* stat variable name */
00369                char *desc,              /* stat variable description */
00370                sqword_t *var,           /* stat variable */
00371                sqword_t init_val,       /* stat variable initial value */
00372                char *format)            /* optional variable output format */
00373 {
00374   struct stat_stat_t *stat;
00375 
00376   stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t));
00377   if (!stat)
00378     fatal("out of virtual memory");
00379 
00380   stat->name = mystrdup(name);
00381   stat->desc = mystrdup(desc);
00382   stat->format = format ? format : "%12ld";
00383   stat->sc = sc_sqword;
00384   stat->variant.for_sqword.var = var;
00385   stat->variant.for_sqword.init_val = init_val;
00386 
00387   /* link onto SDB chain */
00388   add_stat(sdb, stat);
00389 
00390   /* initialize stat */
00391   *var = init_val;
00392 
00393   return stat;
00394 }
00395 #endif /* HOST_HAS_QWORD */
00396 
00397 /* register a float statistical variable */
00398 struct stat_stat_t *
00399 stat_reg_float(struct stat_sdb_t *sdb,  /* stat database */
00400                char *name,              /* stat variable name */
00401                char *desc,              /* stat variable description */
00402                float *var,              /* stat variable */
00403                float init_val,          /* stat variable initial value */
00404                char *format)            /* optional variable output format */
00405 {
00406   struct stat_stat_t *stat;
00407 
00408   stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t));
00409   if (!stat)
00410     fatal("out of virtual memory");
00411 
00412   stat->name = mystrdup(name);
00413   stat->desc = mystrdup(desc);
00414   stat->format = format ? format : "%12.4f";
00415   stat->sc = sc_float;
00416   stat->variant.for_float.var = var;
00417   stat->variant.for_float.init_val = init_val;
00418 
00419   /* link onto SDB chain */
00420   add_stat(sdb, stat);
00421 
00422   /* initialize stat */
00423   *var = init_val;
00424 
00425   return stat;
00426 }
00427 
00428 /* register a double statistical variable */
00429 struct stat_stat_t *
00430 stat_reg_double(struct stat_sdb_t *sdb, /* stat database */
00431                 char *name,             /* stat variable name */
00432                 char *desc,             /* stat variable description */
00433                 double *var,            /* stat variable */
00434                 double init_val,        /* stat variable initial value */
00435                 char *format)           /* optional variable output format */
00436 {
00437   struct stat_stat_t *stat;
00438 
00439   stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t));
00440   if (!stat)
00441     fatal("out of virtual memory");
00442 
00443   stat->name = mystrdup(name);
00444   stat->desc = mystrdup(desc);
00445   stat->format = format ? format : "%12.4f";
00446   stat->sc = sc_double;
00447   stat->variant.for_double.var = var;
00448   stat->variant.for_double.init_val = init_val;
00449 
00450   /* link onto SDB chain */
00451   add_stat(sdb, stat);
00452 
00453   /* initialize stat */
00454   *var = init_val;
00455 
00456   return stat;
00457 }
00458 
00459 /* create an array distribution (w/ fixed size buckets) in stat database SDB,
00460    the array distribution has ARR_SZ buckets with BUCKET_SZ indicies in each
00461    bucked, PF specifies the distribution components to print for optional
00462    format FORMAT; the indicies may be optionally replaced with the strings from
00463    IMAP, or the entire distribution can be printed with the optional
00464    user-specified print function PRINT_FN */
00465 struct stat_stat_t *
00466 stat_reg_dist(struct stat_sdb_t *sdb,   /* stat database */
00467               char *name,               /* stat variable name */
00468               char *desc,               /* stat variable description */
00469               unsigned int init_val,    /* dist initial value */
00470               unsigned int arr_sz,      /* array size */
00471               unsigned int bucket_sz,   /* array bucket size */
00472               int pf,                   /* print format, use PF_* defs */
00473               char *format,             /* optional variable output format */
00474               char **imap,              /* optional index -> string map */
00475               print_fn_t print_fn)      /* optional user print function */
00476 {
00477   unsigned int i;
00478   struct stat_stat_t *stat;
00479   unsigned int *arr;
00480 
00481   stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t));
00482   if (!stat)
00483     fatal("out of virtual memory");
00484 
00485   stat->name = mystrdup(name);
00486   stat->desc = mystrdup(desc);
00487   stat->format = format ? format : NULL;
00488   stat->sc = sc_dist;
00489   stat->variant.for_dist.init_val = init_val;
00490   stat->variant.for_dist.arr_sz = arr_sz;
00491   stat->variant.for_dist.bucket_sz = bucket_sz;
00492   stat->variant.for_dist.pf = pf;
00493   stat->variant.for_dist.imap = imap;
00494   stat->variant.for_dist.print_fn = print_fn;
00495   stat->variant.for_dist.overflows = 0;
00496 
00497   arr = (unsigned int *)calloc(arr_sz, sizeof(unsigned int));
00498   if (!arr)
00499     fatal("out of virtual memory");
00500   stat->variant.for_dist.arr = arr;
00501 
00502   /* link onto SDB chain */
00503   add_stat(sdb, stat);
00504 
00505   /* initialize stat */
00506   for (i=0; i < arr_sz; i++)
00507     arr[i] = init_val;
00508 
00509   return stat;
00510 }
00511 
00512 /* create a sparse array distribution in stat database SDB, while the sparse
00513    array consumes more memory per bucket than an array distribution, it can
00514    efficiently map any number of indicies from 0 to 2^32-1, PF specifies the
00515    distribution components to print for optional format FORMAT; the indicies
00516    may be optionally replaced with the strings from IMAP, or the entire
00517    distribution can be printed with the optional user-specified print function
00518    PRINT_FN */
00519 struct stat_stat_t *
00520 stat_reg_sdist(struct stat_sdb_t *sdb,  /* stat database */
00521                char *name,              /* stat variable name */
00522                char *desc,              /* stat variable description */
00523                unsigned int init_val,   /* dist initial value */
00524                int pf,                  /* print format, use PF_* defs */
00525                char *format,            /* optional variable output format */
00526                print_fn_t print_fn)     /* optional user print function */
00527 {
00528   struct stat_stat_t *stat;
00529   struct bucket_t **sarr;
00530 
00531   stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t));
00532   if (!stat)
00533     fatal("out of virtual memory");
00534 
00535   stat->name = mystrdup(name);
00536   stat->desc = mystrdup(desc);
00537   stat->format = format ? format : NULL;
00538   stat->sc = sc_sdist;
00539   stat->variant.for_sdist.init_val = init_val;
00540   stat->variant.for_sdist.pf = pf;
00541   stat->variant.for_sdist.print_fn = print_fn;
00542 
00543   /* allocate hash table */
00544   sarr = (struct bucket_t **)calloc(HTAB_SZ, sizeof(struct bucket_t *));
00545   if (!sarr)
00546     fatal("out of virtual memory");
00547   stat->variant.for_sdist.sarr = sarr;
00548 
00549   /* link onto SDB chain */
00550   add_stat(sdb, stat);
00551 
00552   return stat;
00553 }
00554 
00555 /* add NSAMPLES to array or sparse array distribution STAT */
00556 void
00557 stat_add_samples(struct stat_stat_t *stat,/* stat database */
00558                  md_addr_t index,       /* distribution index of samples */
00559                  int nsamples)          /* number of samples to add to dist */
00560 {
00561   switch (stat->sc)
00562     {
00563     case sc_dist:
00564       {
00565         unsigned int i;
00566 
00567         /* compute array index */
00568         i = index / stat->variant.for_dist.bucket_sz;
00569 
00570         /* check for overflow */
00571         if (i >= stat->variant.for_dist.arr_sz)
00572           stat->variant.for_dist.overflows += nsamples;
00573         else
00574           stat->variant.for_dist.arr[i] += nsamples;
00575       }
00576       break;
00577     case sc_sdist:
00578       {
00579         struct bucket_t *bucket;
00580         int hash = HTAB_HASH(index);
00581 
00582         if (hash < 0 || hash >= HTAB_SZ)
00583           panic("hash table index overflow");
00584 
00585         /* find bucket */
00586         for (bucket = stat->variant.for_sdist.sarr[hash];
00587              bucket != NULL;
00588              bucket = bucket->next)
00589           {
00590             if (bucket->index == index)
00591               break;
00592           }
00593         if (!bucket)
00594           {
00595             /* add a new sample bucket */
00596             bucket = (struct bucket_t *)calloc(1, sizeof(struct bucket_t));
00597             if (!bucket)
00598               fatal("out of virtual memory");
00599             bucket->next = stat->variant.for_sdist.sarr[hash];
00600             stat->variant.for_sdist.sarr[hash] = bucket;
00601             bucket->index = index;
00602             bucket->count = stat->variant.for_sdist.init_val;
00603           }
00604         bucket->count += nsamples;
00605       }
00606       break;
00607     default:
00608       panic("stat variable is not an array distribution");
00609     }
00610 }
00611 
00612 /* add a single sample to array or sparse array distribution STAT */
00613 void
00614 stat_add_sample(struct stat_stat_t *stat,/* stat variable */
00615                 md_addr_t index)        /* index of sample */
00616 {
00617   stat_add_samples(stat, index, 1);
00618 }
00619 
00620 /* register a double statistical formula, the formula is evaluated when the
00621    statistic is printed, the formula expression may reference any registered
00622    statistical variable and, in addition, the standard operators '(', ')', '+',
00623    '-', '*', and '/', and literal (i.e., C-format decimal, hexidecimal, and
00624    octal) constants are also supported; NOTE: all terms are immediately
00625    converted to double values and the result is a double value, see eval.h
00626    for more information on formulas */
00627 struct stat_stat_t *
00628 stat_reg_formula(struct stat_sdb_t *sdb,/* stat database */
00629                  char *name,            /* stat variable name */
00630                  char *desc,            /* stat variable description */
00631                  char *formula,         /* formula expression */
00632                  char *format)          /* optional variable output format */
00633 {
00634   struct stat_stat_t *stat;
00635 
00636   stat = (struct stat_stat_t *)calloc(1, sizeof(struct stat_stat_t));
00637   if (!stat)
00638     fatal("out of virtual memory");
00639 
00640   stat->name = mystrdup(name);
00641   stat->desc = mystrdup(desc);
00642   stat->format = format ? format : "%12.4f";
00643   stat->sc = sc_formula;
00644   stat->variant.for_formula.formula = mystrdup(formula);
00645 
00646   /* link onto SDB chain */
00647   add_stat(sdb, stat);
00648 
00649   return stat;
00650 }
00651 
00652 
00653 /* compare two indicies in a sparse array hash table, used by qsort() */
00654 static int
00655 compare_fn(void *p1, void *p2)
00656 {
00657   struct bucket_t **pb1 = p1, **pb2 = p2;
00658 
00659   /* compare indices */
00660   if ((*pb1)->index < (*pb2)->index)
00661     return -1;
00662   else if ((*pb1)->index > (*pb2)->index)
00663     return 1;
00664   else /* ((*pb1)->index == (*pb2)->index) */
00665     return 0;
00666 }
00667 
00668 /* print an array distribution */
00669 static void
00670 print_dist(struct stat_stat_t *stat,    /* stat variable */
00671            FILE *fd)                    /* output stream */
00672 {
00673   unsigned int i, bcount, imax, imin;
00674   double btotal, bsum, bvar, bavg, bsqsum;
00675   int pf = stat->variant.for_dist.pf;
00676 
00677   /* count and sum entries */
00678   bcount = 0; btotal = 0.0; bvar = 0.0; bsqsum = 0.0;
00679   imax = 0; imin = UINT_MAX;
00680   for (i=0; i<stat->variant.for_dist.arr_sz; i++)
00681     {
00682       bcount++;
00683       btotal += stat->variant.for_dist.arr[i];
00684       /* on-line variance computation, tres cool, no!?! */
00685       bsqsum += ((double)stat->variant.for_dist.arr[i] *
00686                  (double)stat->variant.for_dist.arr[i]);
00687       bavg = btotal / MAX((double)bcount, 1.0);
00688       bvar = (bsqsum - ((double)bcount * bavg * bavg)) / 
00689         (double)(((bcount - 1) > 0) ? (bcount - 1) : 1);
00690     }
00691 
00692   /* print header */
00693   fprintf(fd, "\n");
00694   fprintf(fd, "%-22s # %s\n", stat->name, stat->desc);
00695   fprintf(fd, "%s.array_size = %u\n",
00696           stat->name, stat->variant.for_dist.arr_sz);
00697   fprintf(fd, "%s.bucket_size = %u\n",
00698           stat->name, stat->variant.for_dist.bucket_sz);
00699 
00700   fprintf(fd, "%s.count = %u\n", stat->name, bcount);
00701   fprintf(fd, "%s.total = %.0f\n", stat->name, btotal);
00702   if (bcount > 0)
00703     {
00704       fprintf(fd, "%s.imin = %u\n", stat->name, 0U);
00705       fprintf(fd, "%s.imax = %u\n", stat->name, bcount);
00706     }
00707   else
00708     {
00709       fprintf(fd, "%s.imin = %d\n", stat->name, -1);
00710       fprintf(fd, "%s.imax = %d\n", stat->name, -1);
00711     }
00712   fprintf(fd, "%s.average = %8.4f\n", stat->name, btotal/MAX(bcount, 1.0));
00713   fprintf(fd, "%s.std_dev = %8.4f\n", stat->name, sqrt(bvar));
00714   fprintf(fd, "%s.overflows = %u\n",
00715           stat->name, stat->variant.for_dist.overflows);
00716 
00717   fprintf(fd, "# pdf == prob dist fn, cdf == cumulative dist fn\n");
00718   fprintf(fd, "# %14s ", "index");
00719   if (pf & PF_COUNT)
00720     fprintf(fd, "%10s ", "count");
00721   if (pf & PF_PDF)
00722     fprintf(fd, "%6s ", "pdf");
00723   if (pf & PF_CDF)
00724     fprintf(fd, "%6s ", "cdf");
00725   fprintf(fd, "\n");
00726 
00727   fprintf(fd, "%s.start_dist\n", stat->name);
00728 
00729   if (bcount > 0)
00730     {
00731       /* print the array */
00732       bsum = 0.0;
00733       for (i=0; i<bcount; i++)
00734         {
00735           bsum += (double)stat->variant.for_dist.arr[i];
00736           if (stat->variant.for_dist.print_fn)
00737             {
00738               stat->variant.for_dist.print_fn(stat,
00739                                               i,
00740                                               stat->variant.for_dist.arr[i],
00741                                               bsum,
00742                                               btotal);
00743             }
00744           else
00745             {
00746               if (stat->format == NULL)
00747                 {
00748                   if (stat->variant.for_dist.imap)
00749                     fprintf(fd, "%-16s ", stat->variant.for_dist.imap[i]);
00750                   else
00751                     fprintf(fd, "%16u ",
00752                             i * stat->variant.for_dist.bucket_sz);
00753                   if (pf & PF_COUNT)
00754                     fprintf(fd, "%10u ", stat->variant.for_dist.arr[i]);
00755                   if (pf & PF_PDF)
00756                     fprintf(fd, "%6.2f ",
00757                             (double)stat->variant.for_dist.arr[i] /
00758                             MAX(btotal, 1.0) * 100.0);
00759                   if (pf & PF_CDF)
00760                     fprintf(fd, "%6.2f ", bsum/MAX(btotal, 1.0) * 100.0);
00761                 }
00762               else
00763                 {
00764                   if (pf == (PF_COUNT|PF_PDF|PF_CDF))
00765                     {
00766                       if (stat->variant.for_dist.imap)
00767                         fprintf(fd, stat->format,
00768                                 stat->variant.for_dist.imap[i],
00769                                 stat->variant.for_dist.arr[i],
00770                                 (double)stat->variant.for_dist.arr[i] /
00771                                 MAX(btotal, 1.0) * 100.0,
00772                                 bsum/MAX(btotal, 1.0) * 100.0);
00773                       else
00774                         fprintf(fd, stat->format,
00775                                 i * stat->variant.for_dist.bucket_sz,
00776                                 stat->variant.for_dist.arr[i],
00777                                 (double)stat->variant.for_dist.arr[i] /
00778                                 MAX(btotal, 1.0) * 100.0,
00779                                 bsum/MAX(btotal, 1.0) * 100.0);
00780                     }
00781                   else
00782                     fatal("distribution format not yet implemented");
00783                 }
00784               fprintf(fd, "\n");
00785             }
00786         }
00787     }
00788 
00789   fprintf(fd, "%s.end_dist\n", stat->name);
00790 }
00791 
00792 /* print a sparse array distribution */
00793 static void
00794 print_sdist(struct stat_stat_t *stat,   /* stat variable */
00795             FILE *fd)                   /* output stream */
00796 {
00797   unsigned int i, bcount;
00798   md_addr_t imax, imin;
00799   double btotal, bsum, bvar, bavg, bsqsum;
00800   struct bucket_t *bucket;
00801   int pf = stat->variant.for_sdist.pf;
00802 
00803   /* count and sum entries */
00804   bcount = 0; btotal = 0.0; bvar = 0.0; bsqsum = 0.0;
00805   imax = 0; imin = UINT_MAX;
00806   for (i=0; i<HTAB_SZ; i++)
00807     {
00808       for (bucket = stat->variant.for_sdist.sarr[i];
00809            bucket != NULL;
00810            bucket = bucket->next)
00811         {
00812           bcount++;
00813           btotal += bucket->count;
00814           /* on-line variance computation, tres cool, no!?! */
00815           bsqsum += ((double)bucket->count * (double)bucket->count);
00816           bavg = btotal / (double)bcount;
00817           bvar = (bsqsum - ((double)bcount * bavg * bavg)) / 
00818             (double)(((bcount - 1) > 0) ? (bcount - 1) : 1);
00819           if (bucket->index < imin)
00820             imin = bucket->index;
00821           if (bucket->index > imax)
00822             imax = bucket->index;
00823         }
00824     }
00825 
00826   /* print header */
00827   fprintf(fd, "\n");
00828   fprintf(fd, "%-22s # %s\n", stat->name, stat->desc);
00829   fprintf(fd, "%s.count = %u\n", stat->name, bcount);
00830   fprintf(fd, "%s.total = %.0f\n", stat->name, btotal);
00831   if (bcount > 0)
00832     {
00833       myfprintf(fd, "%s.imin = 0x%p\n", stat->name, imin);
00834       myfprintf(fd, "%s.imax = 0x%p\n", stat->name, imax);
00835     }
00836   else
00837     {
00838       fprintf(fd, "%s.imin = %d\n", stat->name, -1);
00839       fprintf(fd, "%s.imax = %d\n", stat->name, -1);
00840     }
00841   fprintf(fd, "%s.average = %8.4f\n", stat->name, btotal/bcount);
00842   fprintf(fd, "%s.std_dev = %8.4f\n", stat->name, sqrt(bvar));
00843   fprintf(fd, "%s.overflows = 0\n", stat->name);
00844 
00845   fprintf(fd, "# pdf == prob dist fn, cdf == cumulative dist fn\n");
00846   fprintf(fd, "# %14s ", "index");
00847   if (pf & PF_COUNT)
00848     fprintf(fd, "%10s ", "count");
00849   if (pf & PF_PDF)
00850     fprintf(fd, "%6s ", "pdf");
00851   if (pf & PF_CDF)
00852     fprintf(fd, "%6s ", "cdf");
00853   fprintf(fd, "\n");
00854 
00855   fprintf(fd, "%s.start_dist\n", stat->name);
00856 
00857   if (bcount > 0)
00858     {
00859       unsigned int bindex;
00860       struct bucket_t **barr;
00861 
00862       /* collect all buckets */
00863       barr = (struct bucket_t **)calloc(bcount, sizeof(struct bucket_t *));
00864       if (!barr)
00865         fatal("out of virtual memory");
00866       for (bindex=0,i=0; i<HTAB_SZ; i++)
00867         {
00868           for (bucket = stat->variant.for_sdist.sarr[i];
00869                bucket != NULL;
00870                bucket = bucket->next)
00871             {
00872               barr[bindex++] = bucket;
00873             }
00874         }
00875 
00876       /* sort the array by index */
00877       qsort(barr, bcount, sizeof(struct bucket_t *), (void *)compare_fn);
00878 
00879       /* print the array */
00880       bsum = 0.0;
00881       for (i=0; i<bcount; i++)
00882         {
00883           bsum += (double)barr[i]->count;
00884           if (stat->variant.for_sdist.print_fn)
00885             {
00886               stat->variant.for_sdist.print_fn(stat,
00887                                                barr[i]->index,
00888                                                barr[i]->count,
00889                                                bsum,
00890                                                btotal);
00891             }
00892           else
00893             {
00894               if (stat->format == NULL)
00895                 {
00896                   myfprintf(fd, "0x%p ", barr[i]->index);
00897                   if (pf & PF_COUNT)
00898                     fprintf(fd, "%10u ", barr[i]->count);
00899                   if (pf & PF_PDF)
00900                     fprintf(fd, "%6.2f ",
00901                             (double)barr[i]->count/MAX(btotal, 1.0) * 100.0);
00902                   if (pf & PF_CDF)
00903                     fprintf(fd, "%6.2f ", bsum/MAX(btotal, 1.0) * 100.0);
00904                 }
00905               else
00906                 {
00907                   if (pf == (PF_COUNT|PF_PDF|PF_CDF))
00908                     {
00909                       myfprintf(fd, stat->format,
00910                                 barr[i]->index, barr[i]->count,
00911                                 (double)barr[i]->count/MAX(btotal, 1.0)*100.0,
00912                                 bsum/MAX(btotal, 1.0) * 100.0);
00913                     }
00914                   else if (pf == (PF_COUNT|PF_PDF))
00915                     {
00916                       myfprintf(fd, stat->format,
00917                                 barr[i]->index, barr[i]->count,
00918                                 (double)barr[i]->count/MAX(btotal, 1.0)*100.0);
00919                     }
00920                   else if (pf == PF_COUNT)
00921                     {
00922                       myfprintf(fd, stat->format,
00923                                 barr[i]->index, barr[i]->count);
00924                     }
00925                   else
00926                     fatal("distribution format not yet implemented");
00927                 }
00928               fprintf(fd, "\n");
00929             }
00930         }
00931 
00932       /* all done, release bucket pointer array */
00933       free(barr);
00934     }
00935 
00936   fprintf(fd, "%s.end_dist\n", stat->name);
00937 }
00938 
00939 /* print the value of stat variable STAT */
00940 void
00941 stat_print_stat(struct stat_sdb_t *sdb, /* stat database */
00942                 struct stat_stat_t *stat,/* stat variable */
00943                 FILE *fd)               /* output stream */
00944 {
00945   struct eval_value_t val;
00946 
00947   switch (stat->sc)
00948     {
00949     case sc_int:
00950       fprintf(fd, "%-22s ", stat->name);
00951       myfprintf(fd, stat->format, *stat->variant.for_int.var);
00952       fprintf(fd, " # %s", stat->desc);
00953       break;
00954     case sc_uint:
00955       fprintf(fd, "%-22s ", stat->name);
00956       myfprintf(fd, stat->format, *stat->variant.for_uint.var);
00957       fprintf(fd, " # %s", stat->desc);
00958       break;
00959 #ifdef HOST_HAS_QWORD
00960     case sc_qword:
00961       {
00962         char buf[128];
00963 
00964         fprintf(fd, "%-22s ", stat->name);
00965         mysprintf(buf, stat->format, *stat->variant.for_qword.var);
00966         fprintf(fd, "%s # %s", buf, stat->desc);
00967       }
00968       break;
00969     case sc_sqword:
00970       {
00971         char buf[128];
00972 
00973         fprintf(fd, "%-22s ", stat->name);
00974         mysprintf(buf, stat->format, *stat->variant.for_sqword.var);
00975         fprintf(fd, "%s # %s", buf, stat->desc);
00976       }
00977       break;
00978 #endif /* HOST_HAS_QWORD */
00979     case sc_float:
00980       fprintf(fd, "%-22s ", stat->name);
00981       myfprintf(fd, stat->format, (double)*stat->variant.for_float.var);
00982       fprintf(fd, " # %s", stat->desc);
00983       break;
00984     case sc_double:
00985       fprintf(fd, "%-22s ", stat->name);
00986       myfprintf(fd, stat->format, *stat->variant.for_double.var);
00987       fprintf(fd, " # %s", stat->desc);
00988       break;
00989     case sc_dist:
00990       print_dist(stat, fd);
00991       break;
00992     case sc_sdist:
00993       print_sdist(stat, fd);
00994       break;
00995     case sc_formula:
00996       {
00997         /* instantiate a new evaluator to avoid recursion problems */
00998         struct eval_state_t *es = eval_new(stat_eval_ident, sdb);
00999         char *endp;
01000 
01001         fprintf(fd, "%-22s ", stat->name);
01002         val = eval_expr(es, stat->variant.for_formula.formula, &endp);
01003         if (eval_error != ERR_NOERR || *endp != '\0')
01004           fprintf(fd, "<error: %s>", eval_err_str[eval_error]);
01005         else
01006           myfprintf(fd, stat->format, eval_as_double(val));
01007         fprintf(fd, " # %s", stat->desc);
01008 
01009         /* done with the evaluator */
01010         eval_delete(es);
01011       }
01012       break;
01013     default:
01014       panic("bogus stat class");
01015     }
01016   fprintf(fd, "\n");
01017 }
01018 
01019 /* print the value of all stat variables in stat database SDB */
01020 void
01021 stat_print_stats(struct stat_sdb_t *sdb,/* stat database */
01022                  FILE *fd)              /* output stream */
01023 {
01024   struct stat_stat_t *stat;
01025 
01026   if (!sdb)
01027     {
01028       /* no stats */
01029       return;
01030     }
01031 
01032   for (stat=sdb->stats; stat != NULL; stat=stat->next)
01033     stat_print_stat(sdb, stat, fd);
01034 }
01035 
01036 /* find a stat variable, returns NULL if it is not found */
01037 struct stat_stat_t *
01038 stat_find_stat(struct stat_sdb_t *sdb,  /* stat database */
01039                char *stat_name)         /* stat name */
01040 {
01041   struct stat_stat_t *stat;
01042 
01043   for (stat = sdb->stats; stat != NULL; stat = stat->next)
01044     {
01045       if (!strcmp(stat->name, stat_name))
01046         break;
01047     }
01048   return stat;
01049 }
01050 
01051 #ifdef TESTIT
01052 
01053 void
01054 main(void)
01055 {
01056   struct stat_sdb_t *sdb;
01057   struct stat_stat_t *stat, *stat1, *stat2, *stat3, *stat4, *stat5;
01058   int an_int;
01059   unsigned int a_uint;
01060   float a_float;
01061   double a_double;
01062   static char *my_imap[8] = {
01063     "foo", "bar", "uxxe", "blah", "gaga", "dada", "mama", "googoo"
01064   };
01065 
01066   /* make stats database */
01067   sdb = stat_new();
01068 
01069   /* register stat variables */
01070   stat_reg_int(sdb, "stat.an_int", "An integer stat variable.",
01071                &an_int, 1, NULL);
01072   stat_reg_uint(sdb, "stat.a_uint", "An unsigned integer stat variable.",
01073                 &a_uint, 2, "%u (unsigned)");
01074   stat_reg_float(sdb, "stat.a_float", "A float stat variable.",
01075                  &a_float, 3, NULL);
01076   stat_reg_double(sdb, "stat.a_double", "A double stat variable.",
01077                   &a_double, 4, NULL);
01078   stat_reg_formula(sdb, "stat.a_formula", "A double stat formula.",
01079                    "stat.a_float / stat.a_uint", NULL);
01080   stat_reg_formula(sdb, "stat.a_formula1", "A double stat formula #1.",
01081                    "2 * (stat.a_formula / (1.5 * stat.an_int))", NULL);
01082   stat_reg_formula(sdb, "stat.a_bad_formula", "A double stat formula w/error.",
01083                    "stat.a_float / (stat.a_uint - 2)", NULL);
01084   stat = stat_reg_dist(sdb, "stat.a_dist", "An array distribution.",
01085                        0, 8, 1, PF_ALL, NULL, NULL, NULL);
01086   stat1 = stat_reg_dist(sdb, "stat.a_dist1", "An array distribution #1.",
01087                         0, 8, 4, PF_ALL, NULL, NULL, NULL);
01088   stat2 = stat_reg_dist(sdb, "stat.a_dist2", "An array distribution #2.",
01089                         0, 8, 1, (PF_PDF|PF_CDF), NULL, NULL, NULL);
01090   stat3 = stat_reg_dist(sdb, "stat.a_dist3", "An array distribution #3.",
01091                         0, 8, 1, PF_ALL, NULL, my_imap, NULL);
01092   stat4 = stat_reg_sdist(sdb, "stat.a_sdist", "A sparse array distribution.",
01093                          0, PF_ALL, NULL, NULL);
01094   stat5 = stat_reg_sdist(sdb, "stat.a_sdist1",
01095                          "A sparse array distribution #1.",
01096                          0, PF_ALL, "0x%08lx        %10lu %6.2f %6.2f",
01097                          NULL);
01098 
01099   /* print initial stats */
01100   fprintf(stdout, "** Initial stats...\n");
01101   stat_print_stats(sdb, stdout);
01102 
01103   /* adjust stats */
01104   an_int++;
01105   a_uint++;
01106   a_float *= 2;
01107   a_double *= 4;
01108 
01109   stat_add_sample(stat, 8);
01110   stat_add_sample(stat, 8);
01111   stat_add_sample(stat, 1);
01112   stat_add_sample(stat, 3);
01113   stat_add_sample(stat, 4);
01114   stat_add_sample(stat, 4);
01115   stat_add_sample(stat, 7);
01116 
01117   stat_add_sample(stat1, 32);
01118   stat_add_sample(stat1, 32);
01119   stat_add_sample(stat1, 1);
01120   stat_add_sample(stat1, 12);
01121   stat_add_sample(stat1, 17);
01122   stat_add_sample(stat1, 18);
01123   stat_add_sample(stat1, 30);
01124 
01125   stat_add_sample(stat2, 8);
01126   stat_add_sample(stat2, 8);
01127   stat_add_sample(stat2, 1);
01128   stat_add_sample(stat2, 3);
01129   stat_add_sample(stat2, 4);
01130   stat_add_sample(stat2, 4);
01131   stat_add_sample(stat2, 7);
01132 
01133   stat_add_sample(stat3, 8);
01134   stat_add_sample(stat3, 8);
01135   stat_add_sample(stat3, 1);
01136   stat_add_sample(stat3, 3);
01137   stat_add_sample(stat3, 4);
01138   stat_add_sample(stat3, 4);
01139   stat_add_sample(stat3, 7);
01140 
01141   stat_add_sample(stat4, 800);
01142   stat_add_sample(stat4, 800);
01143   stat_add_sample(stat4, 1123);
01144   stat_add_sample(stat4, 3332);
01145   stat_add_sample(stat4, 4000);
01146   stat_add_samples(stat4, 4001, 18);
01147   stat_add_sample(stat4, 7);
01148 
01149   stat_add_sample(stat5, 800);
01150   stat_add_sample(stat5, 800);
01151   stat_add_sample(stat5, 1123);
01152   stat_add_sample(stat5, 3332);
01153   stat_add_sample(stat5, 4000);
01154   stat_add_samples(stat5, 4001, 18);
01155   stat_add_sample(stat5, 7);
01156 
01157   /* print final stats */
01158   fprintf(stdout, "** Final stats...\n");
01159   stat_print_stats(sdb, stdout);
01160 
01161   /* all done */
01162   stat_delete(sdb);
01163   exit(0);
01164 }
01165 
01166 #endif /* TEST */


UVa CS Department of Computer Science
School of Engineering, University of Virginia
151 Engineer's Way, P.O. Box 400740
Charlottesville, Virginia 22904-4740

(434) 982-2200  Fax: (434) 982-2214