Added StatHist unit tests, and moved algorithm consistency checks there.
Expanded storage for histograms to 64bit unsigned.
Inlined StatHist constructor, destructor and assignment operator.
Implemented stubs for StatHist.cc and mem.cc
tests/testString \
tests/testURL \
tests/testConfigParser \
+ tests/testStatHist \
$(STORE_TESTS)
## NP: required to run the above list. check_PROGRAMS only builds the binaries...
$(XTRA_LIBS)
tests_testHttpReply_DEPENDENCIES= $(SQUID_CPPUNIT_LA)
-## Tests for the ACLMaxUserIP class
-## acl needs wordlist. wordlist needs MemBug
-## MemBuf needs mem, MemBuf needs event,
-## event needs cbdata.
-## ACLMaxUserUP needs $(AUTH_LIBS)
-## ACLMaxUserIP needs ACLChecklist
-## AuthUser request needs HttpHeader, which brings in
-## ETag.cc \
-## HttpHeader.cc \
-## HttpHeaderTools.cc \
-## HttpHdrContRange.cc \
-## HttpHdrCc.cc \
-## HttpHdrRange.cc \
-## HttpHdrSc.cc \
-## HttpHdrScTarget.cc \
-## Packer.cc \
-## StatHist.cc \
-## String.cc \
-##
-## disk.cc \
-## fs/libfs.la \
+
tests_testACLMaxUserIP_SOURCES= \
cbdata.cc \
ClientInfo.h \
SquidMath.cc \
StatCounters.h \
StatHist.h \
- StatHist.cc \
+ tests/stub_StatHist.cc \
stmem.cc \
String.cc \
store_dir.cc \
StatCounters.h \
StatCounters.cc \
StatHist.h \
- StatHist.cc \
+ tests/stub_StatHist.cc \
stmem.cc \
store.cc \
store_client.cc \
StatCounters.h \
StatCounters.cc \
StatHist.h \
- StatHist.cc \
+ tests/stub_StatHist.cc \
stmem.cc \
StoreFileSystem.cc \
StoreIOState.cc \
StatCounters.h \
StatCounters.cc \
StatHist.h \
- StatHist.cc \
+ tests/stub_StatHist.cc \
stmem.cc \
store.cc \
StoreFileSystem.cc \
StatCounters.h \
StatCounters.cc \
StatHist.h \
- StatHist.cc \
- HttpHdrRange.cc \
- ETag.cc \
+ tests/stub_StatHist.cc \
tests/stub_errorpage.cc \
tests/stub_HttpRequest.cc \
tests/stub_access_log.cc \
StatCounters.h \
StatCounters.cc \
StatHist.h \
- StatHist.cc \
- HttpHdrRange.cc \
- ETag.cc \
+ tests/stub_StatHist.cc \
tests/stub_errorpage.cc \
tests/stub_HttpRequest.cc \
tests/stub_access_log.cc \
StatCounters.h \
StatCounters.cc \
StatHist.h \
- StatHist.cc \
+ tests/stub_StatHist.cc \
stmem.cc \
store.cc \
store_client.cc \
tests_testConfigParser_LDFLAGS = $(LIBADD_DL)
tests_testConfigParser_DEPENDENCIES = \
$(SQUID_CPPUNIT_LA)
+
+tests_testStatHist_SOURCES = \
+ cbdata.cc \
+ MemBuf.cc \
+ StatHist.cc \
+ StatHist.h \
+ String.cc \
+ tests/stub_cache_manager.cc \
+ tests/stub_comm.cc \
+ tests/stub_debug.cc \
+ tests/stub_DelayId.cc \
+ tests/stub_HelperChildConfig.cc \
+ tests/stub_mem.cc \
+ tests/stub_MemObject.cc \
+ tests/stub_mime.cc \
+ tests/stub_pconn.cc \
+ tests/stub_stmem.cc \
+ tests/stub_store.cc \
+ tests/stub_store_stats.cc \
+ tests/stub_tools.cc \
+ tests/testMain.cc \
+ tests/testStatHist.cc \
+ tests/testStatHist.h \
+ time.cc
+nodist_tests_testStatHist_SOURCES = \
+ $(TESTSOURCES)
+tests_testStatHist_LDFLAGS = $(LIBADD_DL)
+tests_testStatHist_LDADD = \
+ base/libbase.la \
+ $(top_builddir)/lib/libmiscutil.la \
+ $(SQUID_CPPUNIT_LIBS) \
+ $(SQUID_CPPUNIT_LA) \
+ $(COMPAT_LIB)
+tests_testStatHist_DEPENDENCIES = $(SQUID_CPPUNIT_LA)
+
TESTS += testHeaders
/* low level init, higher level functions has less params */
void
-StatHist::init(int newCapacity, hbase_f * val_in_, hbase_f * val_out_, double newMin, double newMax)
+StatHist::init(unsigned int newCapacity, hbase_f * val_in_, hbase_f * val_out_, double newMin, double newMax)
{
- assert(newCapacity > 0);
- assert(val_in_ && val_out_);
/* check before we divide to get scale_ */
assert(val_in_(newMax - newMin) > 0);
min_ = newMin;
capacity_ = newCapacity;
val_in = val_in_;
val_out = val_out_;
- bins = static_cast<int *>(xcalloc(capacity_, sizeof(int)));
+ bins = static_cast<bins_type *>(xcalloc(capacity_, sizeof(bins_type)));
scale_ = capacity_ / val_in(max_ - min_);
-
- /* check that functions are valid */
- /* a min value should go into bin[0] */
- assert(findBin(min_) == 0);
- /* a max value should go into the last bin */
- assert(findBin(max_) == capacity_ - 1);
- /* it is hard to test val_out, here is a crude test */
- assert(((int) floor(0.99 + val(0) - min_)) == 0);
}
void
StatHist::clear()
{
- for (int i=0; i<capacity_; ++i)
+ for (unsigned int i=0; i<capacity_; ++i)
bins[i]=0;
}
-StatHist::~StatHist()
-{
- if (bins != NULL) {
- xfree(bins);
- bins = NULL;
- }
-}
-
-StatHist&
-StatHist::operator =(const StatHist & src)
-{
- if (this==&src) //handle self-assignment
- return *this;
- assert(src.bins != NULL); // TODO: remove after initializing bins at construction time
- if (capacity_ != src.capacity_) {
- // need to resize.
- xfree(bins);
- bins = static_cast<int *>(xcalloc(src.capacity_, sizeof(int)));
- capacity_=src.capacity_;
-
- }
- min_=src.min_;
- max_=src.max_;
- scale_=src.scale_;
- val_in=src.val_in;
- val_out=src.val_out;
- memcpy(bins,src.bins,capacity_*sizeof(*bins));
- return *this;
-}
-
StatHist::StatHist(const StatHist &src) :
capacity_(src.capacity_), min_(src.min_), max_(src.max_),
scale_(src.scale_), val_in(src.val_in), val_out(src.val_out)
{
if (src.bins!=NULL) {
- bins = static_cast<int *>(xcalloc(src.capacity_, sizeof(int)));
+ bins = static_cast<bins_type *>(xcalloc(src.capacity_, sizeof(int)));
memcpy(bins,src.bins,capacity_*sizeof(*bins));
}
}
void
StatHist::count(double val)
{
- const int bin = findBin(val);
- assert(bins); /* make sure it got initialized */
- assert(0 <= bin && bin < capacity_);
+ if (bins==NULL) //do not count before initialization or after destruction
+ return;
+ const unsigned int bin = findBin(val);
++bins[bin];
}
-int
+unsigned int
StatHist::findBin(double v)
{
- int bin;
v -= min_; /* offset */
if (v <= 0.0) /* too small */
return 0;
- bin = (int) floor(scale_ * val_in(v) + 0.5);
+ unsigned int bin;
+ double tmp_bin=floor(scale_ * val_in(v) + 0.5);
- if (bin < 0) /* should not happen */
+ if (tmp_bin < 0.0) // should not happen
return 0;
+ bin = static_cast <unsigned int>(tmp_bin);
if (bin >= capacity_) /* too big */
bin = capacity_ - 1;
}
double
-StatHist::val(int bin) const
+StatHist::val(unsigned int bin) const
{
return val_out((double) bin / scale_) + min_;
}
double
StatHist::deltaPctile(const StatHist & B, double pctile) const
{
- int i;
- int s1 = 0;
- int h = 0;
- int a = 0;
- int b = 0;
- int I = 0;
- int J = capacity_;
- int K;
+ unsigned int i;
+ bins_type s1 = 0;
+ bins_type h = 0;
+ bins_type a = 0;
+ bins_type b = 0;
+ unsigned int I = 0;
+ unsigned int J = capacity_;
+ unsigned int K;
double f;
assert(capacity_ == B.capacity_);
f = (h - a) / (b - a);
- K = (int) floor(f * (double) (J - I) + I);
+ K = (unsigned int) floor(f * (double) (J - I) + I);
return val(K);
}
void
StatHist::dump(StoreEntry * sentry, StatHistBinDumper * bd) const
{
- int i;
double left_border = min_;
if (!bd)
bd = statHistBinDumper;
- for (i = 0; i < capacity_; ++i) {
+ for (unsigned int i = 0; i < capacity_; ++i) {
const double right_border = val(i + 1);
assert(right_border - left_border > 0.0);
bd(sentry, i, left_border, right_border - left_border, bins[i]);
}
void
-StatHist::logInit(int capacity, double min, double max)
+StatHist::logInit(unsigned int capacity, double min, double max)
{
init(capacity, Math::Log, Math::Exp, min, max);
}
}
void
-StatHist::enumInit(int last_enum)
+StatHist::enumInit(unsigned int last_enum)
{
init(last_enum + 3, Math::Null, Math::Null, -1.0, (2.0 + last_enum));
}
* \todo specialize the class in a small hierarchy so that all
* relevant initializations are done at build-time
*/
- StatHist() : scale_(1.0) {}
+ StatHist();
StatHist(const StatHist&); //not needed
~StatHist();
+ typedef uint64_t bins_type;
+
StatHist &operator=(const StatHist &);
+
/** clear the contents of the histograms
*
* \todo remove: this function has been replaced in its purpose
/** obtain the output-transformed value from the specified bin
*
*/
- double val(int bin) const;
+ double val(unsigned int bin) const;
/** increment the counter for the histogram entry
* associated to the supplied value
*/
void dump(StoreEntry *sentry, StatHistBinDumper * bd) const;
/** Initialize the Histogram using a logarithmic values distribution
*/
- void logInit(int capacity, double min, double max);
+ void logInit(unsigned int capacity, double min, double max);
/** initialize the histogram to count occurrences in an enum-represented set
*/
- void enumInit(int last_enum);
+ void enumInit(unsigned int last_enum);
protected:
/** low-level initialize function. called by *Init high-level functions
* \note Important restrictions on val_in and val_out functions:
* val_in is applied after offseting the value but before scaling
* See log and linear based histograms for examples
*/
- void init(int capacity, hbase_f * val_in, hbase_f * val_out, double min, double max);
+ void init(unsigned int capacity, hbase_f * val_in, hbase_f * val_out, double min, double max);
/// find what entry in the histogram corresponds to v, by applying
/// the preset input transformation function
- int findBin(double v);
+ unsigned int findBin(double v);
/// the histogram counters
- int *bins;
- int capacity_;
+ bins_type *bins;
+ unsigned int capacity_;
/// minimum value to be stored, corresponding to the first bin
double min_;
/// value of the maximum counter in the histogram
StatHistBinDumper statHistEnumDumper;
StatHistBinDumper statHistIntDumper;
+inline StatHist&
+StatHist::operator =(const StatHist & src)
+{
+ if (this==&src) //handle self-assignment
+ return *this;
+ xfree(bins); // xfree can handle NULL pointers, no need to check
+ capacity_=src.capacity_;
+ bins = static_cast<bins_type *>(xcalloc(src.capacity_, sizeof(bins_type)));
+ min_=src.min_;
+ max_=src.max_;
+ scale_=src.scale_;
+ val_in=src.val_in;
+ val_out=src.val_out;
+ memcpy(bins,src.bins,capacity_*sizeof(*bins));
+ return *this;
+}
+
+inline
+StatHist::StatHist() :
+ bins(NULL), capacity_(0), min_(0), max_(0),
+ scale_(1.0), val_in(NULL), val_out(NULL)
+{}
+
+inline
+StatHist::~StatHist()
+{
+ xfree(bins); //can handle case of bins being NULL
+ bins=NULL;
+ capacity_=0; //mark as destructed, may be needed for troubleshooting
+}
+
#endif /* STATHIST_H_ */
#include "config.h"
+#define STUB_API "StatHist.cc"
#include "STUB.h"
#include "StatHist.h"
-#define STUB_API "StatHist.cc"
void
-StatHist::init(int capacity_, hbase_f * val_in_, hbase_f * val_out_, double min_, double max_)
+StatHist::dump(StoreEntry * sentry, StatHistBinDumper * bd) const
{}
-StatHist::~StatHist()
+void
+StatHist::enumInit(unsigned int i)
{}
void
-StatHist::enumInit(int last_enum)
+StatHist::count(double d)
{}
+double
+statHistDeltaMedian(const StatHist & A, const StatHist & B)
+STUB_RETVAL(0.0)
+
+double
+statHistDeltaPctile(const StatHist & A, const StatHist & B, double pctile)
+STUB_RETVAL(0.0)
+
void
-StatHist::count(double val)
-{}
+StatHist::clear()
+STUB
void
-StatHist::dump(StoreEntry * sentry, StatHistBinDumper * bd) const
-{}
+StatHist::logInit(unsigned int i, double d1, double d2)
+STUB
+
+class StoreEntry;
+void
+statHistIntDumper(StoreEntry * sentry, int idx, double val, double size, int count)
+STUB
+
--- /dev/null
+/*
+ * stub file for mem.cc
+ */
+
+#include "config.h"
+
+#define STUB_API "stub_mem.cc"
+#include "STUB.h"
+/* mem* definitions are still in protos.h */
+#include "protos.h"
+
+extern "C" void
+memFreeString(size_t size, void *buf)
+{
+ xfree(buf);
+}
+
+extern "C" void *
+memAllocString(size_t net_size, size_t * gross_size)
+{
+ *gross_size=net_size;
+ return xmalloc(net_size);
+}
+
+extern "C" void
+memFreeBuf(size_t size, void *buf)
+{
+ xfree(buf);
+}
+
+extern "C" void *
+memAllocBuf(size_t net_size, size_t * gross_size)
+{
+ *gross_size=net_size;
+ return xcalloc(1, net_size);
+}
+
+/* net_size is the new size, *gross size is the old gross size, to be changed to
+ * the new gross size as a side-effect.
+ */
+extern "C" void *
+memReallocBuf(void *oldbuf, size_t net_size, size_t * gross_size)
+{
+ void *rv=xrealloc(oldbuf,net_size);
+// if (net_size > *gross_size)
+// memset(rv+net_size,0,net_size-*gross_size);
+ *gross_size=net_size;
+ return rv;
+}
+
+static void
+cxx_xfree(void * ptr)
+{
+ xfree(ptr);
+}
+
+FREE *
+memFreeBufFunc(size_t size)
+{
+ return cxx_xfree;
+}
+
+void *
+memAllocate(mem_type type)
+STUB_RETVAL(NULL)
+
+void
+memFree(void *p, int type)
+STUB
mem_hdr::mem_hdr() STUB
mem_hdr::~mem_hdr() STUB
size_t mem_hdr::size() const STUB_RETVAL(0)
+int64_t mem_hdr::endOffset () const STUB_RETVAL(0)
+bool mem_hdr::write (StoreIOBuffer const &writeBuffer) STUB_RETVAL(false)
+
--- /dev/null
+#define SQUID_UNIT_TEST 1
+#include "config.h"
+#include "testStatHist.h"
+#include "StatHist.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(testStatHist);
+
+typedef enum {
+ ZERO, ONE, TWO, THREE, FOUR, FIVE
+} number ;
+
+class InspectingStatHist : public StatHist
+{
+public:
+ bool operator==(const InspectingStatHist &);
+ bins_type counter(double val) {
+ return bins[findBin(val)];
+ }
+};
+
+bool
+InspectingStatHist::operator ==(const InspectingStatHist & src)
+{
+ assert(bins != NULL && src.bins != NULL); // TODO: remove after initializing bins at construction time
+ if (capacity_ != src.capacity_ ||
+ min_!=src.min_ ||
+ max_!=src.max_ ||
+ scale_!=src.scale_ ||
+ val_in!=src.val_in ||
+ val_out!=src.val_out)
+ return false;
+ return (memcmp(bins,src.bins,capacity_*sizeof(*bins))==0);
+}
+
+
+
+void
+testStatHist::testStatHistBaseEquality()
+{
+ InspectingStatHist raw, test;
+ raw.enumInit(FIVE);
+ test.enumInit(FIVE);
+ CPPUNIT_ASSERT(raw==test);
+ test.count(ZERO);
+ CPPUNIT_ASSERT_ASSERTION_FAIL(CPPUNIT_ASSERT(raw==test));
+}
+
+void
+testStatHist::testStatHistBaseAssignment()
+{
+ InspectingStatHist raw, test;
+ raw.enumInit(FIVE);
+ test.enumInit(FIVE);
+ test.count(ZERO);
+ CPPUNIT_ASSERT_ASSERTION_FAIL(CPPUNIT_ASSERT(raw==test));
+ test=raw;
+ CPPUNIT_ASSERT(raw==test);
+}
+
+
+void
+testStatHist::testStatHistLog()
+{
+ const double min=0.0, max=10000.0;
+ const int capacity=10;
+ InspectingStatHist raw, test;
+ raw.logInit(capacity,min,max);
+ test=raw;
+ CPPUNIT_ASSERT(test.counter(min)==0);
+ test.count(min);
+ CPPUNIT_ASSERT(test.counter(min)==1);
+ CPPUNIT_ASSERT(test.counter(max)==0);
+ test.count(max);
+ CPPUNIT_ASSERT(test.counter(max)==1);
+ test=raw;
+ test.count(max);
+ //CPPUNIT_ASSERT(test.val(capacity-1)==1); //FIXME: val() returns a density
+}
--- /dev/null
+/*
+ * StatHist unit test
+ */
+
+#ifndef TESTSTATHIST_H_
+#define TESTSTATHIST_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+
+class testStatHist : public CPPUNIT_NS::TestFixture
+{
+ CPPUNIT_TEST_SUITE( testStatHist );
+ CPPUNIT_TEST( testStatHistBaseEquality );
+ CPPUNIT_TEST( testStatHistBaseAssignment );
+ CPPUNIT_TEST( testStatHistLog );
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+
+ protected:
+ void testStatHistBaseEquality();
+ void testStatHistBaseAssignment();
+ void testStatHistLog();
+};
+
+#endif /* TESTSTATHIST_H_ */