3 * $Id: StatHist.cc,v 1.34 2007/04/28 22:26:37 hno Exp $
5 * DEBUG: section 62 Generic Histogram
6 * AUTHOR: Duane Wessels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37 * Important restrictions on val_in and val_out functions:
39 * - val_in: ascending, defined on [0, oo), val_in(0) == 0;
40 * - val_out: x == val_out(val_in(x)) where val_in(x) is defined
42 * In practice, the requirements are less strict,
43 * but then it gets hard to define them without math notation.
44 * val_in is applied after offseting the value but before scaling
45 * See log and linear based histograms for examples
52 static void statHistInit(StatHist
* H
, int capacity
, hbase_f
* val_in
, hbase_f
* val_out
, double min
, double max
);
53 static int statHistBin(const StatHist
* H
, double v
);
54 static double statHistVal(const StatHist
* H
, int bin
);
55 static StatHistBinDumper statHistBinDumper
;
56 #if !defined(_SQUID_HPUX_) || !defined(__GNUC__)
58 * HP-UX and GCC (2.8?) give strange errors when these simple
59 * functions are static.
66 /* low level init, higher level functions has less params */
68 statHistInit(StatHist
* H
, int capacity
, hbase_f
* val_in
, hbase_f
* val_out
, double min
, double max
)
72 assert(val_in
&& val_out
);
73 /* check before we divide to get scale */
74 assert(val_in(max
- min
) > 0);
75 H
->bins
= (int *)xcalloc(capacity
, sizeof(int));
78 H
->capacity
= capacity
;
79 H
->scale
= capacity
/ val_in(max
- min
);
83 /* HPUX users: If you get one of the assertions below, please send
84 * [at least] the values of all variables involved in the assertions
85 * when reporting a bug!
88 /* check that functions are valid */
89 /* a min value should go into bin[0] */
90 assert(statHistBin(H
, min
) == 0);
91 /* a max value should go into the last bin */
92 assert(statHistBin(H
, max
) == H
->capacity
- 1);
93 /* it is hard to test val_out, here is a crude test */
94 assert(((int) floor(0.99 + statHistVal(H
, 0) - min
)) == 0);
98 statHistClean(StatHist
* H
)
104 /* assumes that somebody already called init for Dest */
106 statHistCopy(StatHist
* Dest
, const StatHist
* Orig
)
110 debugs(62, 3, "statHistCopy: Dest=" << Dest
<< ", Orig=" << Orig
);
112 /* better be safe than sorry */
113 debugs(62, 3, "statHistCopy: capacity " << Dest
->capacity
<< " " << Orig
->capacity
);
114 assert(Dest
->capacity
== Orig
->capacity
);
115 debugs(62, 3, "statHistCopy: min " << Dest
->min
<< " " << Orig
->min
);
116 assert(Dest
->min
== Orig
->min
);
117 debugs(62, 3, "statHistCopy: max " << Dest
->max
<< " " << Orig
->max
);
118 assert(Dest
->max
== Orig
->max
);
119 debugs(62, 3, "statHistCopy: scale " << Dest
->scale
<< " " << Orig
->scale
);
120 assert(fabs(Dest
->scale
- Orig
->scale
) < 0.0000001);
121 assert(Dest
->val_in
== Orig
->val_in
);
122 assert(Dest
->val_out
== Orig
->val_out
);
124 debugs(62, 3, "statHistCopy: copying " <<
125 (long int) (Dest
->capacity
* sizeof(*Dest
->bins
)) << " bytes to " <<
126 Dest
->bins
<< " from " << Orig
->bins
);
128 xmemcpy(Dest
->bins
, Orig
->bins
, Dest
->capacity
* sizeof(*Dest
->bins
));
132 * same as statHistCopy but will do nothing if capacities do not match; the
133 * latter happens, for example, when #peers changes during reconfiguration;
134 * if it happens too often we should think about more general solution..
137 statHistSafeCopy(StatHist
* Dest
, const StatHist
* Orig
)
139 assert(Dest
&& Orig
);
142 if (Dest
->capacity
== Orig
->capacity
)
143 statHistCopy(Dest
, Orig
);
147 statHistCount(StatHist
* H
, double val
)
149 const int bin
= statHistBin(H
, val
);
150 assert(H
->bins
); /* make sure it got initialized */
151 assert(0 <= bin
&& bin
< H
->capacity
);
156 statHistBin(const StatHist
* H
, double v
)
159 #if BROKEN_STAT_HIST_BIN
165 v
-= H
->min
; /* offset */
167 if (v
<= 0.0) /* too small */
170 bin
= (int) floor(H
->scale
* H
->val_in(v
) + 0.5);
172 if (bin
< 0) /* should not happen */
175 if (bin
>= H
->capacity
) /* too big */
176 bin
= H
->capacity
- 1;
182 statHistVal(const StatHist
* H
, int bin
)
184 return H
->val_out((double) bin
/ H
->scale
) + H
->min
;
188 statHistDeltaMedian(const StatHist
* A
, const StatHist
* B
)
190 return statHistDeltaPctile(A
, B
, 0.5);
194 statHistDeltaPctile(const StatHist
* A
, const StatHist
* B
, double pctile
)
205 int *D
= (int *)xcalloc(A
->capacity
, sizeof(int));
206 assert(A
->capacity
== B
->capacity
);
208 for (i
= 0; i
< A
->capacity
; i
++) {
209 D
[i
] = B
->bins
[i
] - A
->bins
[i
];
213 for (i
= 0; i
< A
->capacity
; i
++)
216 h
= int(s1
* pctile
);
218 for (i
= 0; i
< A
->capacity
; i
++) {
222 if (a
<= h
&& h
<= b
)
244 f
= (h
- a
) / (b
- a
);
246 K
= (int) floor(f
* (double) (J
- I
) + I
);
248 return statHistVal(A
, K
);
252 statHistBinDumper(StoreEntry
* sentry
, int idx
, double val
, double size
, int count
)
255 storeAppendPrintf(sentry
, "\t%3d/%f\t%d\t%f\n",
256 idx
, val
, count
, count
/ size
);
260 statHistDump(const StatHist
* H
, StoreEntry
* sentry
, StatHistBinDumper
* bd
)
263 double left_border
= H
->min
;
266 bd
= statHistBinDumper
;
268 for (i
= 0; i
< H
->capacity
; i
++) {
269 const double right_border
= statHistVal(H
, i
+ 1);
270 assert(right_border
- left_border
> 0.0);
271 bd(sentry
, i
, left_border
, right_border
- left_border
, H
->bins
[i
]);
272 left_border
= right_border
;
276 /* log based histogram */
277 #if !defined(_SQUID_HPUX_) || !defined(__GNUC__)
283 assert((x
+ 1.0) >= 0.0);
287 #if !defined(_SQUID_HPUX_) || !defined(__GNUC__)
297 statHistLogInit(StatHist
* H
, int capacity
, double min
, double max
)
299 statHistInit(H
, capacity
, Log
, Exp
, min
, max
);
302 /* linear histogram for enums */
303 /* we want to be have [-1,last_enum+1] range to track out of range enums */
304 #if !defined(_SQUID_HPUX_) || !defined(__GNUC__)
314 statHistEnumInit(StatHist
* H
, int last_enum
)
316 statHistInit(H
, last_enum
+ 3, Null
, Null
, (double) -1, (double) (last_enum
+ 1 + 1));
320 statHistEnumDumper(StoreEntry
* sentry
, int idx
, double val
, double size
, int count
)
323 storeAppendPrintf(sentry
, "%2d\t %5d\t %5d\n",
324 idx
, (int) val
, count
);
328 statHistIntInit(StatHist
* H
, int n
)
330 statHistInit(H
, n
, Null
, Null
, (double) 0, (double) n
- 1);
334 statHistIntDumper(StoreEntry
* sentry
, int idx
, double val
, double size
, int count
)
337 storeAppendPrintf(sentry
, "%9d\t%9d\n", (int) val
, count
);