=== modified file 'src/Makefile.am'
--- src/Makefile.am	2013-11-22 09:31:30 +0000
+++ src/Makefile.am	2013-11-22 22:02:11 +0000
@@ -486,6 +486,8 @@
 	send-announce.h \
 	send-announce.cc \
 	$(SBUF_SOURCE) \
+	SBufDetailedStats.h \
+	SBufDetailedStats.cc \
 	SBufStatsAction.h \
 	SBufStatsAction.cc \
 	$(SNMP_SOURCE) \
@@ -1514,6 +1516,8 @@
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SBUF_SOURCE) \
+	SBufDetailedStats.h \
+	tests/stub_SBufDetailedStats.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
@@ -1928,6 +1932,8 @@
 	StrList.h \
 	StrList.cc \
 	$(SBUF_SOURCE) \
+	SBufDetailedStats.h \
+	tests/stub_SBufDetailedStats.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.cc \
 	SquidMath.h \
@@ -2170,6 +2176,8 @@
 	refresh.cc \
 	Server.cc \
 	$(SBUF_SOURCE) \
+	SBufDetailedStats.h \
+	tests/stub_SBufDetailedStats.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
@@ -2409,6 +2417,8 @@
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SBUF_SOURCE) \
+	SBufDetailedStats.h \
+	tests/stub_SBufDetailedStats.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
@@ -2694,6 +2704,8 @@
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SBUF_SOURCE) \
+	SBufDetailedStats.h \
+	tests/stub_SBufDetailedStats.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
@@ -3487,6 +3499,8 @@
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SBUF_SOURCE) \
+	SBufDetailedStats.h \
+	tests/stub_SBufDetailedStats.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
@@ -3602,6 +3616,8 @@
 	tests/SBufFindTest.h \
 	tests/SBufFindTest.cc \
 	$(SBUF_SOURCE) \
+	SBufDetailedStats.h \
+	tests/stub_SBufDetailedStats.cc \
 	SBufStream.h \
 	tests/stub_time.cc \
 	mem.cc \

=== modified file 'src/MemBlob.cc'
--- src/MemBlob.cc	2013-10-04 15:33:54 +0000
+++ src/MemBlob.cc	2013-11-22 21:51:09 +0000
@@ -31,6 +31,7 @@
 #include "Debug.h"
 #include "Mem.h"
 #include "MemBlob.h"
+#include "SBufDetailedStats.h"
 
 #if HAVE_IOSTREAM
 #include <iostream>
@@ -96,6 +97,7 @@
         memFreeString(capacity,mem);
     Stats.liveBytes -= capacity;
     --Stats.live;
+    recordMemBlobSizeAtDestruct(size);
 
     debugs(MEMBLOB_DEBUGSECTION,9, HERE << "destructed, this="
            << static_cast<void*>(this) << " id=" << id

=== modified file 'src/SBuf.cc'
--- src/SBuf.cc	2013-10-07 11:23:58 +0000
+++ src/SBuf.cc	2013-11-22 21:50:30 +0000
@@ -31,6 +31,7 @@
 #include "Debug.h"
 #include "OutOfBoundsException.h"
 #include "SBuf.h"
+#include "SBufDetailedStats.h"
 #include "SBufExceptions.h"
 #include "util.h"
 
@@ -148,6 +149,7 @@
 {
     debugs(24, 8, id << " destructed");
     --stats.live;
+    recordSBufSizeAtDestruct(len_);
 }
 
 MemBlob::Pointer

=== added file 'src/SBufDetailedStats.cc'
--- src/SBufDetailedStats.cc	1970-01-01 00:00:00 +0000
+++ src/SBufDetailedStats.cc	2013-11-23 16:53:40 +0000
@@ -0,0 +1,47 @@
+#include "squid.h"
+#include "SBufDetailedStats.h"
+#include "StatHist.h"
+
+/*
+ * Implementation note: the purpose of this construct is to avoid adding
+ * external dependencies to the SBuf code
+ */
+
+static StatHist sbufDestructTimeStats;
+static StatHist memblobDestructTimeStats;
+
+namespace {
+    // run the post-instantiation initialization methods for StatHist objects
+    struct Initializer
+    {
+        Initializer() {
+            sbufDestructTimeStats.logInit(300,30.0,128000.0);
+            memblobDestructTimeStats.logInit(300,30.0,128000.0);
+        }
+    };
+    Initializer initializer;
+}
+
+void
+recordSBufSizeAtDestruct(SBuf::size_type sz)
+{
+    sbufDestructTimeStats.count(static_cast<double>(sz));
+}
+
+const StatHist *
+collectSBufDestructTimeStats()
+{
+    return &sbufDestructTimeStats;
+}
+
+void
+recordMemBlobSizeAtDestruct(SBuf::size_type sz)
+{
+    memblobDestructTimeStats.count(static_cast<double>(sz));
+}
+
+const StatHist *
+collectMemBlobDestructTimeStats()
+{
+    return &memblobDestructTimeStats;
+}

=== added file 'src/SBufDetailedStats.h'
--- src/SBufDetailedStats.h	1970-01-01 00:00:00 +0000
+++ src/SBufDetailedStats.h	2013-11-23 16:33:58 +0000
@@ -0,0 +1,18 @@
+#include "SBuf.h"
+
+class StatHist;
+/// Record the size a SBuf had when it was destructed
+void recordSBufSizeAtDestruct(SBuf::size_type sz);
+/** Collect the SBuf size-at-destruct-time histogram
+ *
+ * \note the returned StatHist object must not be freed
+ */
+const StatHist * collectSBufDestructTimeStats();
+
+/// Record the size a MemBlob had when it was destructed
+void recordMemBlobSizeAtDestruct(MemBlob::size_type sz);
+/** Collect the MemBlob size-at-destruct-time histogram
+ *
+ * \note the returned StatHist object must not be freed
+ */
+const StatHist * collectMemBlobDestructTimeStats();

=== modified file 'src/SBufStatsAction.cc'
--- src/SBufStatsAction.cc	2013-10-10 08:44:03 +0000
+++ src/SBufStatsAction.cc	2013-11-23 12:02:59 +0000
@@ -30,6 +30,7 @@
 #include "ipc/Messages.h"
 #include "ipc/TypedMsgHdr.h"
 #include "mgr/Registration.h"
+#include "SBufDetailedStats.h"
 #include "SBufStatsAction.h"
 #include "StoreEntryStream.h"
 
@@ -48,6 +49,8 @@
 {
     sbdata += dynamic_cast<const SBufStatsAction&>(action).sbdata;
     mbdata += dynamic_cast<const SBufStatsAction&>(action).mbdata;
+    sbsizesatdestruct += dynamic_cast<const SBufStatsAction&>(action).sbsizesatdestruct;
+    mbsizesatdestruct += dynamic_cast<const SBufStatsAction&>(action).mbsizesatdestruct;
 }
 
 void
@@ -55,6 +58,8 @@
 {
     sbdata = SBuf::GetStats();
     mbdata = MemBlob::GetStats();
+    sbsizesatdestruct = *collectSBufDestructTimeStats();
+    mbsizesatdestruct = *collectMemBlobDestructTimeStats();
 }
 
 void
@@ -63,9 +68,14 @@
     StoreEntryStream ses(entry);
     sbdata.dump(ses);
     mbdata.dump(ses);
+    ses << "\n";
+    ses << "SBuf size distribution at destruct time:\n";
+    sbsizesatdestruct.dump(entry,NULL);
+    ses << "MemBlob size distribution at destruct time:\n";
+    mbsizesatdestruct.dump(entry,NULL);
     ses << "\n\n\nThese statistics are experimental; their format and contents "
     "should not be relied upon, they are bound to change as "
-    "the SBuf feature is evolved";
+    "the SBuf feature is evolved\n";
 }
 
 void

=== modified file 'src/SBufStatsAction.h'
--- src/SBufStatsAction.h	2013-10-10 08:44:03 +0000
+++ src/SBufStatsAction.h	2013-11-23 12:02:23 +0000
@@ -31,6 +31,7 @@
 
 #include "mgr/Action.h"
 #include "SBuf.h"
+#include "StatHist.h"
 
 class StoreEntry;
 
@@ -55,6 +56,8 @@
 
     SBufStats sbdata;
     MemBlobStats mbdata;
+    StatHist sbsizesatdestruct;
+    StatHist mbsizesatdestruct;
 };
 
 #endif /* SQUID_SBUFSTATSACTION_H */

=== modified file 'src/StatHist.cc'
--- src/StatHist.cc	2013-01-21 07:15:09 +0000
+++ src/StatHist.cc	2013-11-23 11:23:44 +0000
@@ -205,6 +205,26 @@
     }
 }
 
+StatHist &
+StatHist::operator += (const StatHist &B)
+{
+    Must(capacity_ == B.capacity_);
+    Must(min_ == B.min_);
+    Must(max_ == B.max_);
+
+    if (B.bins == NULL) { // B was not yet initializted
+        return *this;
+    }
+    if (bins == NULL) { // this histogram was not yet initialized
+        *this = B;
+        return *this;
+    }
+    for (unsigned int i = 0; i < capacity_; ++i) {
+        bins[i] += B.bins[i];
+    }
+    return *this;
+}
+
 /* log based histogram */
 double
 Math::Log(double x)

=== modified file 'src/StatHist.h'
--- src/StatHist.h	2012-08-28 13:00:30 +0000
+++ src/StatHist.h	2013-11-23 11:04:03 +0000
@@ -90,6 +90,12 @@
     /** initialize the histogram to count occurrences in an enum-represented set
      */
     void enumInit(unsigned int last_enum);
+    /** Import values from another histogram
+     *
+     * \note: the two histograms MUST have the same capicity, min and max or
+     *      an exception will be raised
+     */
+    StatHist &operator += (const StatHist &B);
 protected:
     /** low-level initialize function. called by *Init high-level functions
      * \note Important restrictions on val_in and val_out functions:

=== added file 'src/tests/stub_SBufDetailedStats.cc'
--- src/tests/stub_SBufDetailedStats.cc	1970-01-01 00:00:00 +0000
+++ src/tests/stub_SBufDetailedStats.cc	2013-11-22 22:04:23 +0000
@@ -0,0 +1,12 @@
+#include "squid.h"
+#include "SBuf.h"
+
+#define STUB_API "SBufDetailedStats.cc"
+#include "tests/STUB.h"
+
+class StatHist;
+
+void recordSBufSizeAtDestruct(SBuf::size_type) STUB_NOP
+const StatHist * collectSBufDestructTimeStats() STUB_RETVAL(NULL)
+void recordMemBlobSizeAtDestruct(SBuf::size_type) STUB_NOP
+const StatHist * collectMemBlobDestructTimeStats() STUB_RETVAL(NULL)

=== modified file 'src/tests/testStatHist.cc'
--- src/tests/testStatHist.cc	2013-10-25 00:13:46 +0000
+++ src/tests/testStatHist.cc	2013-11-23 11:44:28 +0000
@@ -73,3 +73,25 @@
     test.count(max);
     //CPPUNIT_ASSERT(test.val(capacity-1)==1); //FIXME: val() returns a density
 }
+
+void
+testStatHist::testStatHistSum()
+{
+    InspectingStatHist s1, s2;
+    s1.logInit(30,1.0,100.0);
+    s2.logInit(30,1.0,100.0);
+    s1.count(3);
+    s2.count(30);
+    InspectingStatHist ts1, ts2;
+    ts1=s1;
+    ts1+=s2;
+    ts2=s2;
+    ts2+=s1;
+    CPPUNIT_ASSERT(ts1 == ts2);
+    InspectingStatHist ts3;
+    ts3.logInit(30,1.0,100.0);
+    ts3.count(3);
+    ts3.count(30);
+    CPPUNIT_ASSERT(ts3 == ts1);
+
+}

=== modified file 'src/tests/testStatHist.h'
--- src/tests/testStatHist.h	2012-08-28 13:00:30 +0000
+++ src/tests/testStatHist.h	2013-11-23 11:20:47 +0000
@@ -13,6 +13,7 @@
     CPPUNIT_TEST( testStatHistBaseEquality );
     CPPUNIT_TEST( testStatHistBaseAssignment );
     CPPUNIT_TEST( testStatHistLog );
+    CPPUNIT_TEST( testStatHistSum );
     CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -21,6 +22,7 @@
     void testStatHistBaseEquality();
     void testStatHistBaseAssignment();
     void testStatHistLog();
+    void testStatHistSum();
 };
 
 #endif /* TESTSTATHIST_H_ */

