StatHist.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:8k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: StatHist.c,v 1.23 1999/01/19 02:24:20 wessels Exp $
  3.  *
  4.  * DEBUG: section 62    Generic Histogram
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. /*
  35.  * Important restrictions on val_in and val_out functions:
  36.  * 
  37.  *   - val_in:  ascending, defined on [0, oo), val_in(0) == 0;
  38.  *   - val_out: x == val_out(val_in(x)) where val_in(x) is defined
  39.  *
  40.  *  In practice, the requirements are less strict, 
  41.  *  but then it gets hard to define them without math notation.
  42.  *  val_in is applied after offseting the value but before scaling
  43.  *  See log and linear based histograms for examples
  44.  */
  45. #include "squid.h"
  46. /* Local functions */
  47. static void statHistInit(StatHist * H, int capacity, hbase_f * val_in, hbase_f * val_out, double min, double max);
  48. static int statHistBin(const StatHist * H, double v);
  49. static double statHistVal(const StatHist * H, int bin);
  50. static StatHistBinDumper statHistBinDumper;
  51. #if !defined(_SQUID_HPUX_) || !defined(__GNUC__)
  52.     /*
  53.      * HP-UX and GCC (2.8?) give strange errors when these simple
  54.      * functions are static.
  55.      */
  56. static hbase_f Log;
  57. static hbase_f Exp;
  58. static hbase_f Null;
  59. #endif
  60. /* low level init, higher level functions has less params */
  61. static void
  62. statHistInit(StatHist * H, int capacity, hbase_f * val_in, hbase_f * val_out, double min, double max)
  63. {
  64.     assert(H);
  65.     assert(capacity > 0);
  66.     assert(val_in && val_out);
  67.     /* check before we divide to get scale */
  68.     assert(val_in(max - min) > 0);
  69.     H->bins = xcalloc(capacity, sizeof(int));
  70.     H->min = min;
  71.     H->max = max;
  72.     H->capacity = capacity;
  73.     H->scale = capacity / val_in(max - min);
  74.     H->val_in = val_in;
  75.     H->val_out = val_out;
  76.     /* HPUX users: If you get one of the assertions below, please send
  77.      * [at least] the values of all variables involved in the assertions
  78.      * when reporting a bug!
  79.      */
  80.     /* check that functions are valid */
  81.     /* a min value should go into bin[0] */
  82.     assert(statHistBin(H, min) == 0);
  83.     /* a max value should go into the last bin */
  84.     assert(statHistBin(H, max) == H->capacity - 1);
  85.     /* it is hard to test val_out, here is a crude test */
  86.     assert(((int) floor(0.99L + statHistVal(H, 0) - min)) == 0);
  87. }
  88. void
  89. statHistClean(StatHist * H)
  90. {
  91.     xfree(H->bins);
  92.     H->bins = NULL;
  93. }
  94. /* assumes that somebody already called init for Dest */
  95. void
  96. statHistCopy(StatHist * Dest, const StatHist * Orig)
  97. {
  98.     assert(Dest);
  99.     assert(Orig);
  100.     debug(62, 3) ("statHistCopy: Dest=%p, Orig=%pn", Dest, Orig);
  101.     assert(Dest->bins);
  102.     /* better be safe than sorry */
  103.     debug(62, 3) ("statHistCopy: capacity %d %dn",
  104. Dest->capacity, Orig->capacity);
  105.     assert(Dest->capacity == Orig->capacity);
  106.     debug(62, 3) ("statHistCopy: min %f %fn", Dest->min, Orig->min);
  107.     assert(Dest->min == Orig->min);
  108.     debug(62, 3) ("statHistCopy: max %f %fn", Dest->max, Orig->max);
  109.     assert(Dest->max == Orig->max);
  110.     debug(62, 3) ("statHistCopy: scale %f %fn", Dest->scale, Orig->scale);
  111.     assert(Dest->scale == Orig->scale);
  112.     assert(Dest->val_in == Orig->val_in);
  113.     assert(Dest->val_out == Orig->val_out);
  114.     /* actual copy */
  115.     debug(62, 3) ("statHistCopy: copying %d bytes to %p from %pn",
  116. Dest->capacity * sizeof(*Dest->bins),
  117. Dest->bins,
  118. Orig->bins);
  119.     xmemcpy(Dest->bins, Orig->bins, Dest->capacity * sizeof(*Dest->bins));
  120. }
  121. /*
  122.  * same as statHistCopy but will do nothing if capacities do not match; the
  123.  * latter happens, for example, when #peers changes during reconfiguration;
  124.  * if it happens too often we should think about more general solution..
  125.  */
  126. void
  127. statHistSafeCopy(StatHist * Dest, const StatHist * Orig)
  128. {
  129.     assert(Dest && Orig);
  130.     assert(Dest->bins);
  131.     if (Dest->capacity == Orig->capacity)
  132. statHistCopy(Dest, Orig);
  133. }
  134. void
  135. statHistCount(StatHist * H, double val)
  136. {
  137.     const int bin = statHistBin(H, val);
  138.     assert(H->bins); /* make sure it got initialized */
  139.     assert(0 <= bin && bin < H->capacity);
  140.     H->bins[bin]++;
  141. }
  142. static int
  143. statHistBin(const StatHist * H, double v)
  144. {
  145.     int bin;
  146. #if BROKEN_STAT_HIST_BIN
  147.     return 0;
  148.     /* NOTREACHED */
  149. #endif
  150.     v -= H->min; /* offset */
  151.     if (v <= 0.0) /* too small */
  152. return 0;
  153.     bin = (int) floor(H->scale * H->val_in(v) + 0.5);
  154.     if (bin < 0) /* should not happen */
  155. bin = 0;
  156.     if (bin >= H->capacity) /* too big */
  157. bin = H->capacity - 1;
  158.     return bin;
  159. }
  160. static double
  161. statHistVal(const StatHist * H, int bin)
  162. {
  163.     return H->val_out((double) bin / H->scale) + H->min;
  164. }
  165. double
  166. statHistDeltaMedian(const StatHist * A, const StatHist * B)
  167. {
  168.     int i;
  169.     int s1 = 0;
  170.     int h = 0;
  171.     int a = 0;
  172.     int b = 0;
  173.     int I = 0;
  174.     int J = A->capacity;
  175.     int K;
  176.     double f;
  177.     int *D = xcalloc(A->capacity, sizeof(int));
  178.     assert(A->capacity == B->capacity);
  179.     for (i = 0; i < A->capacity; i++) {
  180. D[i] = B->bins[i] - A->bins[i];
  181. assert(D[i] >= 0);
  182.     }
  183.     for (i = 0; i < A->capacity; i++)
  184. s1 += D[i];
  185.     h = s1 >> 1;
  186.     for (i = 0; i < A->capacity; i++) {
  187. J = i;
  188. b += D[J];
  189. if (a <= h && h <= b)
  190.     break;
  191. I = i;
  192. a += D[I];
  193.     }
  194.     xfree(D);
  195.     if (s1 == 0)
  196. return 0.0;
  197.     if (a > h)
  198. return 0.0;
  199.     if (a >= b)
  200. return 0.0;
  201.     if (I >= J)
  202. return 0.0;
  203.     f = (h - a) / (b - a);
  204.     K = (int) floor(f * (double) (J - I) + I);
  205.     return statHistVal(A, K);
  206. }
  207. static void
  208. statHistBinDumper(StoreEntry * sentry, int idx, double val, double size, int count)
  209. {
  210.     if (count)
  211. storeAppendPrintf(sentry, "t%3d/%ft%dt%fn",
  212.     idx, val, count, count / size);
  213. }
  214. void
  215. statHistDump(const StatHist * H, StoreEntry * sentry, StatHistBinDumper * bd)
  216. {
  217.     int i;
  218.     double left_border = H->min;
  219.     if (!bd)
  220. bd = statHistBinDumper;
  221.     for (i = 0; i < H->capacity; i++) {
  222. const double right_border = statHistVal(H, i + 1);
  223. assert(right_border - left_border > 0.0);
  224. bd(sentry, i, left_border, right_border - left_border, H->bins[i]);
  225. left_border = right_border;
  226.     }
  227. }
  228. /* log based histogram */
  229. #if !defined(_SQUID_HPUX_) || !defined(__GNUC__)
  230. static
  231. #endif
  232. double
  233. Log(double x)
  234. {
  235.     assert((x + 1.0) >= 0.0);
  236.     return log(x + 1.0);
  237. }
  238. #if !defined(_SQUID_HPUX_) || !defined(__GNUC__)
  239. static
  240. #endif
  241. double
  242. Exp(double x)
  243. {
  244.     return exp(x) - 1.0;
  245. }
  246. void
  247. statHistLogInit(StatHist * H, int capacity, double min, double max)
  248. {
  249.     statHistInit(H, capacity, Log, Exp, min, max);
  250. }
  251. /* linear histogram for enums */
  252. /* we want to be have [-1,last_enum+1] range to track out of range enums */
  253. #if !defined(_SQUID_HPUX_) || !defined(__GNUC__)
  254. static
  255. #endif
  256. double
  257. Null(double x)
  258. {
  259.     return x;
  260. }
  261. void
  262. statHistEnumInit(StatHist * H, int last_enum)
  263. {
  264.     statHistInit(H, last_enum + 3, Null, Null, (double) -1, (double) (last_enum + 1 + 1));
  265. }
  266. void
  267. statHistEnumDumper(StoreEntry * sentry, int idx, double val, double size, int count)
  268. {
  269.     if (count)
  270. storeAppendPrintf(sentry, "%2dt %5dt %5dn",
  271.     idx, (int) val, count);
  272. }
  273. void
  274. statHistIntInit(StatHist * H, int n)
  275. {
  276.     statHistInit(H, n, Null, Null, (double) 0, (double) n - 1);
  277. }
  278. void
  279. statHistIntDumper(StoreEntry * sentry, int idx, double val, double size, int count)
  280. {
  281.     if (count)
  282. storeAppendPrintf(sentry, "%9dt%9dn", (int) val, count);
  283. }