/* Web Polygraph http://www.web-polygraph.org/
* (C) 2003-2006 The Measurement Factory
* Licensed under the Apache License, Version 2.0 */
#include "base/polygraph.h"
#include <limits.h>
#include "xstd/h/iostream.h"
#include "xstd/h/iomanip.h"
#include "base/ILog.h"
#include "base/OLog.h"
#include "base/histograms.h"
/* Log2Hist */
/*
* pow2 min : max /precision =#entries (accum size)
* 8 0 : 511 / 1 = 512 ( 512 or 2K)
* 9 512 : 1023 / 2 = 256 ( 768 or 3K)
* 10 1024 : 2047 / 4 = 256 ( 1024 or 4K)
* 11 2048 : 4095 / 8 = 256 ( 1280 or 5K)
* 12 4096 : 8191 / 16 = 256 ( 1536 or 6K)
* 13 8192 : 16383 / 32 = 256 ( 1792 or 7K)
* 14 16384 : 32767 / 64 = 256 ( 2048 or 8K)
* 15 32768 : 65535 / 128 = 256 ( 2304 or 9K)
* 16 65536 : 131071 / 256 = 256 ( 2560 or 10K)
* 17 131072 : 262143 / 512 = 256 ( 2816 or 11K)
* 18 262144 : 524287 / 1024 = 256 ( 3072 or 12K)
* 19 524288 : 1048575 / 2048 = 256 ( 3328 or 13K)
* 20 1048576 : 2097151 / 4096 = 256 ( 3584 or 14K)
* 21 2097152 : 4194303 / 8192 = 256 ( 3840 or 15K)
* 22 4194304 : 8388607 / 16384 = 256 ( 4096 or 16K)
* 23 8388608 : 16777215 / 32768 = 256 ( 4352 or 17K)
* 24 16777216 : 33554431 / 65536 = 256 ( 4608 or 18K)
* 25 33554432 : 67108863 / 131072 = 256 ( 4864 or 19K)
* 26 67108864 : 134217727 / 262144 = 256 ( 5120 or 20K)
* 27 134217728 : 268435455 / 524288 = 256 ( 5376 or 21K)
* 28 268435456 : 536870911 / 1048576 = 256 ( 5632 or 22K)
* 29 536870912 : 1073741823 / 2097152 = 256 ( 5888 or 23K)
* 30 1073741824 : 2147483647 / 4194304 = 256 ( 6144 or 24K)
*/
// note: val2Bin has static binding here
Log2Hist::Log2Hist(): Histogram(0, INT_MAX, val2Bin(INT_MAX)) {
}
// note: val2Bin has static binding here
Log2Hist::Log2Hist(Val aMin, Val aMax):
Histogram(aMin, aMax, Log2Hist::val2Bin(aMax-aMin)) {
}
int Log2Hist::val2Bin(Val v) const {
Assert(v >= 0);
const int vo = v;
if (v >>= 9) {
int p = 1;
while (v >>= 1) p++; // count powers of 2; (super-bin id)
const int min_val = 1 << (8+p);
const int sbin_offset = (vo - min_val) >> p;
const int sbin = (p+1) << 8;
return sbin + sbin_offset;
} else
return vo;
}
Log2Hist::Val Log2Hist::bin2Val(int bin) const {
const int bino = bin;
if (bin >= 512) {
const int bin_offset = bin % 256;
const int sbin = bin - bin_offset;
const int p = sbin/256 - 1;
const int val_offset = bin_offset << p;
const int min_val = 1 << (8+p);
return min_val + val_offset;
} else
return bino;
}
/* TimeHist */
TimeHist::TimeHist(): theTmMax(Time::Msec(theValMax)) {
Assert(theTmMax > 0);
}
/* TimeVsSmthHist */
static inline
OLog &operator <<(OLog &log, const TimeHist *h) {
Assert(h);
return log << *h;
}
static inline
ILog &operator >>(ILog &log, TimeHist *h) {
Assert(h);
return log >> *h;
}
TimeVsSmthHist::TimeVsSmthHist(int aMaxSmth): theMaxSmth(aMaxSmth) {
}
TimeVsSmthHist::~TimeVsSmthHist() {
while (theHists.count()) delete theHists.pop();
}
void TimeVsSmthHist::resize(int maxGrp) {
Assert(!theHists.count());
Assert(maxGrp >= 0);
const int count = 1 + maxGrp;
theHists.stretch(count);
for (int i = 0; i < count; ++i)
theHists.append(new TimeHist);
}
OLog &TimeVsSmthHist::store(OLog &log) const {
return log << theMaxSmth << theHists;
}
ILog &TimeVsSmthHist::load(ILog &log) {
const int ms = log.geti();
Must(ms <= theMaxSmth);
theMaxSmth = ms;
return log >> theHists;
}
// log2 step except a special case of 100 bytes
// range must be checked in the caller
int TimeVsSmthHist::logSmth(int smth_off) const {
Assert(smth_off > 0);
int n = 0;
while (smth_off >>= 1) n++; // log2
return n;
}
int TimeVsSmthHist::expSmth(int grp_off) const {
Assert(grp_off >= 0);
int smth_off = 1;
while (grp_off--) smth_off <<= 1; // exp2
return smth_off;
}
void TimeVsSmthHist::add(const TimeVsSmthHist &h) {
// histograms must match
Assert(theMaxSmth == h.theMaxSmth);
Assert(theHists.count() == h.theHists.count());
for (int i = 0; i < theHists.count(); ++i)
theHists[i]->add(*h.theHists[i]);
}
void TimeVsSmthHist::reset() {
for (int i = 0; i < theHists.count(); ++i)
theHists[i]->reset();
}
void TimeVsSmthHist::printVsLine(const Histogram &h, int pStep, ostream &os) const {
// print count and mean
os << ' ' << setw(7) << h.stats().count()
<< ' ' << setw(9) << h.stats().mean();
// get and print percentiles
Array<HistogramBin> percs;
Percentiles(h, percs);
for (int i = pStep; i <= 100; i += pStep) {
if (i <= percs.count()) // do we ever have less?
os << ' ' << setw(3) << percs[i-1].sup-1;
else
os << ' ' << setw(3) << '?';
}
}
ostream &TimeVsSmthHist::print(ostream &os, const String &type, int min, const String &pfx) const {
const int pStep = 5; // 5%;
// header
os << pfx << "hist:" << endl
<< "# " << setw(4) << type << " response_time" << endl
<< "# min max count mean";
for (int i = pStep; i <= 100; i += pStep)
os << ' ' << setw(2) << i << '%';
os << endl;
// for each size group, print mean and percentiles
const int lastGrp = lastGrpId();
for (int g = 0; g <= lastGrp; ++g) {
const Histogram &h = groupHist(g);
if (!h.stats().count())
continue;
int max = groupMax(g);
os << setw(5) << min << ' ' << setw(6) << max;
printVsLine(h, pStep, os);
os << endl;
min = max + 1;
}
os << endl;
return os;
}
/* TimeVsSizeHist */
TimeVsSizeHist::TimeVsSizeHist(): TimeVsSmthHist(Size::KB(128)-Size(1)) {
resize(TimeVsSizeHist::groupId(theMaxSmth));
}
// special case of 0-100 and 101-1023 ranges
// range must be checked in the caller
int TimeVsSizeHist::groupId(int sz) const {
if (sz < 100)
return 0;
if (sz < 1024)
return 1;
return 2 + logSmth(sz/1024);
}
int TimeVsSizeHist::groupMax(int grp) const {
Assert(grp >= 0);
if (grp == 0)
return 100 - 1;
if (grp == 1)
return 1024 - 1;
return 1024*expSmth(grp-2 + 1) - 1;
}
ostream &TimeVsSizeHist::print(ostream &os, const String &pfx) const {
return TimeVsSmthHist::print(os, "size", 0, pfx);
}
/* TimeVsUseHist */
TimeVsUseHist::TimeVsUseHist(): TimeVsSmthHist(128-1) {
resize(TimeVsUseHist::groupId(theMaxSmth));
}
// special cases for 1,2,3,4 uses
// range must be checked in the caller
int TimeVsUseHist::groupId(int useCnt) const {
if (useCnt <= 4)
return useCnt-1;
return 4 + logSmth(useCnt - 4);
}
int TimeVsUseHist::groupMax(int grp) const {
Assert(grp >= 0);
if (grp < 4)
return grp+1;
return 4+expSmth(grp-4 + 1) - 1;
}
ostream &TimeVsUseHist::print(ostream &os, const String &pfx) const {
return TimeVsSmthHist::print(os, "use", 1, pfx);
}
syntax highlighted by Code2HTML, v. 0.9.1