]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/stat.cc
Merge form trunk
[thirdparty/squid.git] / src / stat.cc
index 1d9bc563c09340a7a20f64014c41e72522ffa70c..428c579a3c0c5be580a42aa9fd5e927e68473b40 100644 (file)
@@ -36,7 +36,6 @@
 #include "event.h"
 #include "StoreClient.h"
 #include "auth/UserRequest.h"
-#include "CacheManager.h"
 #include "comm/Connection.h"
 #include "Store.h"
 #include "HttpRequest.h"
 #include "MemBuf.h"
 #include "SquidMath.h"
 #include "SquidTime.h"
+#include "mgr/CountersAction.h"
+#include "mgr/FunAction.h"
+#include "mgr/InfoAction.h"
+#include "mgr/IntervalAction.h"
+#include "mgr/IoAction.h"
+#include "mgr/Registration.h"
+#include "mgr/ServiceTimesAction.h"
 
 /* these are included because they expose stats calls */
 /* TODO: provide a self registration mechanism for those classes
@@ -91,22 +97,29 @@ static void statCountersCopy(StatCounters * dest, const StatCounters * orig);
 static double statPctileSvc(double, int, int);
 static void statStoreEntry(MemBuf * mb, StoreEntry * e);
 static double statCPUUsage(int minutes);
-static OBJH stat_io_get;
 static OBJH stat_objects_get;
 static OBJH stat_vmobjects_get;
 #if DEBUG_OPENFD
 static OBJH statOpenfdObj;
 #endif
 static EVH statObjects;
-static OBJH info_get;
 static OBJH statCountersDump;
 static OBJH statPeerSelect;
 static OBJH statDigestBlob;
-static OBJH statAvg5min;
-static OBJH statAvg60min;
 static OBJH statUtilization;
 static OBJH statCountersHistograms;
 static OBJH statClientRequests;
+void GetAvgStat(Mgr::IntervalActionData& stats, int minutes, int hours);
+void DumpAvgStat(Mgr::IntervalActionData& stats, StoreEntry* sentry);
+void GetInfo(Mgr::InfoActionData& stats);
+void DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry);
+void DumpMallocStatistics(StoreEntry* sentry);
+void GetCountersStats(Mgr::CountersActionData& stats);
+void DumpCountersStats(Mgr::CountersActionData& stats, StoreEntry* sentry);
+void GetServiceTimesStats(Mgr::ServiceTimesActionData& stats);
+void DumpServiceTimesStats(Mgr::ServiceTimesActionData& stats, StoreEntry* sentry);
+void GetIoStats(Mgr::IoActionData& stats);
+void DumpIoStats(Mgr::IoActionData& stats, StoreEntry* sentry);
 
 #if XMALLOC_STATISTICS
 static void info_get_mallstat(int, int, int, void *);
@@ -187,47 +200,71 @@ statUtilization(StoreEntry * e)
     statCountersDump(e);
 }
 
-static void
-stat_io_get(StoreEntry * sentry)
+void
+GetIoStats(Mgr::IoActionData& stats)
+{
+    int i;
+
+    stats.http_reads = IOStats.Http.reads;
+
+    for (i = 0; i < _iostats::histSize; i++) {
+        stats.http_read_hist[i] = IOStats.Http.read_hist[i];
+    }
+
+    stats.ftp_reads = IOStats.Ftp.reads;
+
+    for (i = 0; i < _iostats::histSize; i++) {
+        stats.ftp_read_hist[i] = IOStats.Ftp.read_hist[i];
+    }
+
+    stats.gopher_reads = IOStats.Gopher.reads;
+
+    for (i = 0; i < _iostats::histSize; i++) {
+        stats.gopher_read_hist[i] = IOStats.Gopher.read_hist[i];
+    }
+}
+
+void
+DumpIoStats(Mgr::IoActionData& stats, StoreEntry* sentry)
 {
     int i;
 
     storeAppendPrintf(sentry, "HTTP I/O\n");
-    storeAppendPrintf(sentry, "number of reads: %d\n", IOStats.Http.reads);
+    storeAppendPrintf(sentry, "number of reads: %.0f\n", stats.http_reads);
     storeAppendPrintf(sentry, "Read Histogram:\n");
 
-    for (i = 0; i < 16; i++) {
-        storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%\n",
+    for (i = 0; i < _iostats::histSize; i++) {
+        storeAppendPrintf(sentry, "%5d-%5d: %9.0f %2.0f%%\n",
                           i ? (1 << (i - 1)) + 1 : 1,
                           1 << i,
-                          IOStats.Http.read_hist[i],
-                          Math::intPercent(IOStats.Http.read_hist[i], IOStats.Http.reads));
+                          stats.http_read_hist[i],
+                          Math::doublePercent(stats.http_read_hist[i], stats.http_reads));
     }
 
     storeAppendPrintf(sentry, "\n");
     storeAppendPrintf(sentry, "FTP I/O\n");
-    storeAppendPrintf(sentry, "number of reads: %d\n", IOStats.Ftp.reads);
+    storeAppendPrintf(sentry, "number of reads: %.0f\n", stats.ftp_reads);
     storeAppendPrintf(sentry, "Read Histogram:\n");
 
-    for (i = 0; i < 16; i++) {
-        storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%\n",
+    for (i = 0; i < _iostats::histSize; i++) {
+        storeAppendPrintf(sentry, "%5d-%5d: %9.0f %2.0f%%\n",
                           i ? (1 << (i - 1)) + 1 : 1,
                           1 << i,
-                          IOStats.Ftp.read_hist[i],
-                          Math::intPercent(IOStats.Ftp.read_hist[i], IOStats.Ftp.reads));
+                          stats.ftp_read_hist[i],
+                          Math::doublePercent(stats.ftp_read_hist[i], stats.ftp_reads));
     }
 
     storeAppendPrintf(sentry, "\n");
     storeAppendPrintf(sentry, "Gopher I/O\n");
-    storeAppendPrintf(sentry, "number of reads: %d\n", IOStats.Gopher.reads);
+    storeAppendPrintf(sentry, "number of reads: %.0f\n", stats.gopher_reads);
     storeAppendPrintf(sentry, "Read Histogram:\n");
 
-    for (i = 0; i < 16; i++) {
-        storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%\n",
+    for (i = 0; i < _iostats::histSize; i++) {
+        storeAppendPrintf(sentry, "%5d-%5d: %9.0f %2.0f%%\n",
                           i ? (1 << (i - 1)) + 1 : 1,
                           1 << i,
-                          IOStats.Gopher.read_hist[i],
-                          Math::intPercent(IOStats.Gopher.read_hist[i], IOStats.Gopher.reads));
+                          stats.gopher_read_hist[i],
+                          Math::doublePercent(stats.gopher_read_hist[i], stats.gopher_reads));
     }
 
     storeAppendPrintf(sentry, "\n");
@@ -339,6 +376,8 @@ statObjects(void *data)
     StoreEntry *e;
 
     if (state->theSearch->isDone()) {
+        if (UsingSmp())
+            storeAppendPrintf(state->sentry, "} by kid%d\n\n", KidIdentifier);
         state->sentry->complete();
         state->sentry->unlock();
         cbdataFree(state);
@@ -439,8 +478,8 @@ info_get_mallstat(int size, int number, int oldnum, void *data)
 
 #endif
 
-static void
-info_get(StoreEntry * sentry)
+void
+GetInfo(Mgr::InfoActionData& stats)
 {
 
     struct rusage rusage;
@@ -452,7 +491,6 @@ info_get(StoreEntry * sentry)
 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
 
     struct mallinfo mp;
-    long t;
 #endif
 
     runtime = tvSubDsec(squid_start, current_time);
@@ -460,6 +498,175 @@ info_get(StoreEntry * sentry)
     if (runtime == 0.0)
         runtime = 1.0;
 
+    stats.squid_start = squid_start;
+
+    stats.current_time = current_time;
+
+    stats.client_http_clients = statCounter.client_http.clients;
+
+    stats.client_http_requests = statCounter.client_http.requests;
+
+    stats.icp_pkts_recv = statCounter.icp.pkts_recv;
+
+    stats.icp_pkts_sent = statCounter.icp.pkts_sent;
+
+    stats.icp_replies_queued = statCounter.icp.replies_queued;
+
+#if USE_HTCP
+
+    stats.htcp_pkts_recv = statCounter.htcp.pkts_recv;
+
+    stats.htcp_pkts_sent = statCounter.htcp.pkts_sent;
+
+#endif
+
+    stats.request_failure_ratio = request_failure_ratio;
+
+    stats.avg_client_http_requests = statCounter.client_http.requests / (runtime / 60.0);
+
+    stats.avg_icp_messages = (statCounter.icp.pkts_sent + statCounter.icp.pkts_recv) / (runtime / 60.0);
+
+    stats.select_loops = statCounter.select_loops;
+    stats.avg_loop_time = 1000.0 * runtime / statCounter.select_loops;
+
+    stats.request_hit_ratio5 = statRequestHitRatio(5);
+    stats.request_hit_ratio60 = statRequestHitRatio(60);
+
+    stats.byte_hit_ratio5 = statByteHitRatio(5);
+    stats.byte_hit_ratio60 = statByteHitRatio(60);
+
+    stats.request_hit_mem_ratio5 = statRequestHitMemoryRatio(5);
+    stats.request_hit_mem_ratio60 = statRequestHitMemoryRatio(60);
+
+    stats.request_hit_disk_ratio5 = statRequestHitDiskRatio(5);
+    stats.request_hit_disk_ratio60 = statRequestHitDiskRatio(60);
+
+    stats.store_swap_size = store_swap_size;
+    stats.store_swap_max_size = Store::Root().maxSize();
+
+    stats.store_mem_size = mem_node::StoreMemSize();
+    stats.store_pages_max = store_pages_max;
+    stats.store_mem_used = mem_node::InUseCount();
+
+    stats.objects_size = n_disk_objects ? (double) store_swap_size / n_disk_objects : 0.0;
+
+    stats.unlink_requests = statCounter.unlink.requests;
+
+    stats.http_requests5 = statPctileSvc(0.5, 5, PCTILE_HTTP);
+    stats.http_requests60 = statPctileSvc(0.5, 60, PCTILE_HTTP);
+
+    stats.cache_misses5 = statPctileSvc(0.5, 5, PCTILE_MISS);
+    stats.cache_misses60 = statPctileSvc(0.5, 60, PCTILE_MISS);
+
+    stats.cache_hits5 = statPctileSvc(0.5, 5, PCTILE_HIT);
+    stats.cache_hits60 = statPctileSvc(0.5, 60, PCTILE_HIT);
+
+    stats.near_hits5 = statPctileSvc(0.5, 5, PCTILE_NH);
+    stats.near_hits60 = statPctileSvc(0.5, 60, PCTILE_NH);
+
+    stats.not_modified_replies5 = statPctileSvc(0.5, 5, PCTILE_NM);
+    stats.not_modified_replies60 = statPctileSvc(0.5, 60, PCTILE_NM);
+
+    stats.dns_lookups5 = statPctileSvc(0.5, 5, PCTILE_DNS);
+    stats.dns_lookups60 = statPctileSvc(0.5, 60, PCTILE_DNS);
+
+    stats.icp_queries5 = statPctileSvc(0.5, 5, PCTILE_ICP_QUERY);
+    stats.icp_queries60 = statPctileSvc(0.5, 60, PCTILE_ICP_QUERY);
+
+    squid_getrusage(&rusage);
+    cputime = rusage_cputime(&rusage);
+
+    stats.up_time = runtime;
+    stats.cpu_time = cputime;
+    stats.cpu_usage = Math::doublePercent(cputime, runtime);
+    stats.cpu_usage5 = statCPUUsage(5);
+    stats.cpu_usage60 = statCPUUsage(60);
+
+#if HAVE_SBRK
+
+    stats.proc_data_seg = ((char *) sbrk(0) - (char *) sbrk_start);
+
+#endif
+
+    stats.maxrss = rusage_maxrss(&rusage);
+
+    stats.page_faults = rusage_pagefaults(&rusage);
+
+#if HAVE_MSTATS && HAVE_GNUMALLOC_H
+
+    ms = mstats();
+
+    stats.ms_bytes_total = ms.bytes_total;
+
+    stats.ms_bytes_free = ms.bytes_free;
+
+#elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
+
+    mp = mallinfo();
+
+    stats.mp_arena = mp.arena;
+
+    stats.mp_uordblks = mp.uordblks;
+    stats.mp_ordblks = mp.ordblks;
+
+    stats.mp_usmblks = mp.usmblks;
+    stats.mp_smblks = mp.smblks;
+
+    stats.mp_hblkhd = mp.hblkhd;
+    stats.mp_hblks = mp.hblks;
+
+    stats.mp_fsmblks = mp.fsmblks;
+
+    stats.mp_fordblks = mp.fordblks;
+
+#if HAVE_STRUCT_MALLINFO_MXFAST
+
+    stats.mp_mxfast = mp.mxfast;
+
+    stats.mp_nlblks = mp.nlblks;
+
+    stats.mp_grain = mp.grain;
+
+    stats.mp_uordbytes = mp.uordbytes;
+
+    stats.mp_allocated = mp.allocated;
+
+    stats.mp_treeoverhead = mp.treeoverhead;
+
+#endif /* HAVE_STRUCT_MALLINFO_MXFAST */
+#endif /* HAVE_MALLINFO */
+
+    stats.total_accounted = statMemoryAccounted();
+
+    {
+        MemPoolGlobalStats mp_stats;
+        memPoolGetGlobalStats(&mp_stats);
+#if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
+
+        stats.mem_pool_allocated = mp_stats.TheMeter->alloc.level;
+#endif
+
+        stats.gb_freed_count = mp_stats.TheMeter->gb_saved.count;
+        stats.gb_freed_count = mp_stats.TheMeter->gb_freed.count;
+    }
+
+    stats.max_fd = Squid_MaxFD;
+    stats.biggest_fd = Biggest_FD;
+    stats.number_fd = Number_FD;
+    stats.opening_fd = Opening_FD;
+    stats.num_fd_free = fdNFree();
+    stats.reserved_fd = RESERVED_FD;
+    stats.store_open_disk_fd = store_open_disk_fd;
+
+    stats.store_entries = StoreEntry::inUseCount();
+    stats.store_mem_entries = MemObject::inUseCount();
+    stats.hot_obj_count = hot_obj_count;
+    stats.n_disk_objects = n_disk_objects;
+}
+
+void
+DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry)
+{
     storeAppendPrintf(sentry, "Squid Object Cache: Version %s\n",
                       version_string);
 
@@ -475,219 +682,215 @@ info_get(StoreEntry * sentry)
 #endif
 
     storeAppendPrintf(sentry, "Start Time:\t%s\n",
-                      mkrfc1123(squid_start.tv_sec));
+                      mkrfc1123(stats.squid_start.tv_sec));
 
     storeAppendPrintf(sentry, "Current Time:\t%s\n",
-                      mkrfc1123(current_time.tv_sec));
+                      mkrfc1123(stats.current_time.tv_sec));
 
     storeAppendPrintf(sentry, "Connection information for %s:\n",APP_SHORTNAME);
 
-    storeAppendPrintf(sentry, "\tNumber of clients accessing cache:\t%u\n",
-                      statCounter.client_http.clients);
+    storeAppendPrintf(sentry, "\tNumber of clients accessing cache:\t%.0f\n",
+                      stats.client_http_clients);
 
-    storeAppendPrintf(sentry, "\tNumber of HTTP requests received:\t%u\n",
-                      statCounter.client_http.requests);
+    storeAppendPrintf(sentry, "\tNumber of HTTP requests received:\t%.0f\n",
+                      stats.client_http_requests);
 
-    storeAppendPrintf(sentry, "\tNumber of ICP messages received:\t%u\n",
-                      statCounter.icp.pkts_recv);
+    storeAppendPrintf(sentry, "\tNumber of ICP messages received:\t%.0f\n",
+                      stats.icp_pkts_recv);
 
-    storeAppendPrintf(sentry, "\tNumber of ICP messages sent:\t%u\n",
-                      statCounter.icp.pkts_sent);
+    storeAppendPrintf(sentry, "\tNumber of ICP messages sent:\t%.0f\n",
+                      stats.icp_pkts_sent);
 
-    storeAppendPrintf(sentry, "\tNumber of queued ICP replies:\t%u\n",
-                      statCounter.icp.replies_queued);
+    storeAppendPrintf(sentry, "\tNumber of queued ICP replies:\t%.0f\n",
+                      stats.icp_replies_queued);
 
 #if USE_HTCP
 
-    storeAppendPrintf(sentry, "\tNumber of HTCP messages received:\t%u\n",
-                      statCounter.htcp.pkts_recv);
+    storeAppendPrintf(sentry, "\tNumber of HTCP messages received:\t%.0f\n",
+                      stats.htcp_pkts_recv);
 
-    storeAppendPrintf(sentry, "\tNumber of HTCP messages sent:\t%u\n",
-                      statCounter.htcp.pkts_sent);
+    storeAppendPrintf(sentry, "\tNumber of HTCP messages sent:\t%.0f\n",
+                      stats.htcp_pkts_sent);
 
 #endif
 
+    double fct = stats.count > 1 ? stats.count : 1.0;
     storeAppendPrintf(sentry, "\tRequest failure ratio:\t%5.2f\n",
-                      request_failure_ratio);
+                      stats.request_failure_ratio / fct);
 
     storeAppendPrintf(sentry, "\tAverage HTTP requests per minute since start:\t%.1f\n",
-                      statCounter.client_http.requests / (runtime / 60.0));
+                      stats.avg_client_http_requests / fct);
 
     storeAppendPrintf(sentry, "\tAverage ICP messages per minute since start:\t%.1f\n",
-                      (statCounter.icp.pkts_sent + statCounter.icp.pkts_recv) / (runtime / 60.0));
+                      stats.avg_icp_messages / fct);
 
-    storeAppendPrintf(sentry, "\tSelect loop called: %ld times, %0.3f ms avg\n",
-                      statCounter.select_loops, 1000.0 * runtime / statCounter.select_loops);
+    storeAppendPrintf(sentry, "\tSelect loop called: %.0f times, %0.3f ms avg\n",
+                      stats.select_loops, stats.avg_loop_time / fct);
 
     storeAppendPrintf(sentry, "Cache information for %s:\n",APP_SHORTNAME);
 
     storeAppendPrintf(sentry, "\tHits as %% of all requests:\t5min: %3.1f%%, 60min: %3.1f%%\n",
-                      statRequestHitRatio(5),
-                      statRequestHitRatio(60));
+                      stats.request_hit_ratio5 / fct,
+                      stats.request_hit_ratio60 / fct);
 
     storeAppendPrintf(sentry, "\tHits as %% of bytes sent:\t5min: %3.1f%%, 60min: %3.1f%%\n",
-                      statByteHitRatio(5),
-                      statByteHitRatio(60));
+                      stats.byte_hit_ratio5 / fct,
+                      stats.byte_hit_ratio60 / fct);
 
     storeAppendPrintf(sentry, "\tMemory hits as %% of hit requests:\t5min: %3.1f%%, 60min: %3.1f%%\n",
-                      statRequestHitMemoryRatio(5),
-                      statRequestHitMemoryRatio(60));
+                      stats.request_hit_mem_ratio5 / fct,
+                      stats.request_hit_mem_ratio60 / fct);
 
     storeAppendPrintf(sentry, "\tDisk hits as %% of hit requests:\t5min: %3.1f%%, 60min: %3.1f%%\n",
-                      statRequestHitDiskRatio(5),
-                      statRequestHitDiskRatio(60));
+                      stats.request_hit_disk_ratio5 / fct,
+                      stats.request_hit_disk_ratio60 / fct);
 
-    storeAppendPrintf(sentry, "\tStorage Swap size:\t%lu KB\n",
-                      store_swap_size);
+    storeAppendPrintf(sentry, "\tStorage Swap size:\t%.0f KB\n",
+                      stats.store_swap_size / 1024);
 
     storeAppendPrintf(sentry, "\tStorage Swap capacity:\t%4.1f%% used, %4.1f%% free\n",
-                      Math::doublePercent(store_swap_size, Store::Root().maxSize()),
-                      Math::doublePercent((Store::Root().maxSize() - store_swap_size), Store::Root().maxSize()));
-
+                      Math::doublePercent(stats.store_swap_size, stats.store_swap_max_size),
+                      Math::doublePercent(stats.store_swap_max_size - stats.store_swap_size, stats.store_swap_max_size));
 
-    storeAppendPrintf(sentry, "\tStorage Mem size:\t%lu KB\n",
-                      (unsigned long)(mem_node::StoreMemSize() >> 10));
+    storeAppendPrintf(sentry, "\tStorage Mem size:\t%.0f KB\n",
+                      stats.store_mem_size / 1024);
 
+    const double mFree = max(0.0, stats.store_pages_max-stats.store_mem_used);
     storeAppendPrintf(sentry, "\tStorage Mem capacity:\t%4.1f%% used, %4.1f%% free\n",
-                      Math::doublePercent(mem_node::InUseCount(), store_pages_max),
-                      Math::doublePercent((store_pages_max - mem_node::InUseCount()), store_pages_max));
+                      Math::doublePercent(stats.store_mem_used, stats.store_pages_max),
+                      Math::doublePercent(mFree, stats.store_pages_max));
 
     storeAppendPrintf(sentry, "\tMean Object Size:\t%0.2f KB\n",
-                      n_disk_objects ? (double) store_swap_size / n_disk_objects : 0.0);
+                      stats.objects_size / fct);
 
-    storeAppendPrintf(sentry, "\tRequests given to unlinkd:\t%ld\n",
-                      (long)statCounter.unlink.requests);
+    storeAppendPrintf(sentry, "\tRequests given to unlinkd:\t%.0f\n",
+                      stats.unlink_requests);
 
     storeAppendPrintf(sentry, "Median Service Times (seconds)  5 min    60 min:\n");
 
+    fct = stats.count > 1 ? stats.count * 1000.0 : 1000.0;
     storeAppendPrintf(sentry, "\tHTTP Requests (All):  %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_HTTP) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_HTTP) / 1000.0);
+                      stats.http_requests5 / fct,
+                      stats.http_requests60 / fct);
 
     storeAppendPrintf(sentry, "\tCache Misses:         %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_MISS) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_MISS) / 1000.0);
+                      stats.cache_misses5 / fct,
+                      stats.cache_misses60 / fct);
 
     storeAppendPrintf(sentry, "\tCache Hits:           %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_HIT) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_HIT) / 1000.0);
+                      stats.cache_hits5 / fct,
+                      stats.cache_hits60 / fct);
 
     storeAppendPrintf(sentry, "\tNear Hits:            %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_NH) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_NH) / 1000.0);
+                      stats.near_hits5 / fct,
+                      stats.near_hits60 / fct);
 
     storeAppendPrintf(sentry, "\tNot-Modified Replies: %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_NM) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_NM) / 1000.0);
+                      stats.not_modified_replies5 / fct,
+                      stats.not_modified_replies60 / fct);
 
     storeAppendPrintf(sentry, "\tDNS Lookups:          %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_DNS) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_DNS) / 1000.0);
+                      stats.dns_lookups5 / fct,
+                      stats.dns_lookups60 / fct);
 
+    fct = stats.count > 1 ? stats.count * 1000000.0 : 1000000.0;
     storeAppendPrintf(sentry, "\tICP Queries:          %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_ICP_QUERY) / 1000000.0,
-                      statPctileSvc(0.5, 60, PCTILE_ICP_QUERY) / 1000000.0);
-
-    squid_getrusage(&rusage);
-
-    cputime = rusage_cputime(&rusage);
+                      stats.icp_queries5 / fct,
+                      stats.icp_queries60 / fct);
 
     storeAppendPrintf(sentry, "Resource usage for %s:\n", APP_SHORTNAME);
 
-    storeAppendPrintf(sentry, "\tUP Time:\t%.3f seconds\n", runtime);
+    storeAppendPrintf(sentry, "\tUP Time:\t%.3f seconds\n", stats.up_time);
 
-    storeAppendPrintf(sentry, "\tCPU Time:\t%.3f seconds\n", cputime);
+    storeAppendPrintf(sentry, "\tCPU Time:\t%.3f seconds\n", stats.cpu_time);
 
     storeAppendPrintf(sentry, "\tCPU Usage:\t%.2f%%\n",
-                      Math::doublePercent(cputime, runtime));
+                      stats.cpu_usage);
 
     storeAppendPrintf(sentry, "\tCPU Usage, 5 minute avg:\t%.2f%%\n",
-                      statCPUUsage(5));
+                      stats.cpu_usage5);
 
     storeAppendPrintf(sentry, "\tCPU Usage, 60 minute avg:\t%.2f%%\n",
-                      statCPUUsage(60));
+                      stats.cpu_usage60);
 
 #if HAVE_SBRK
 
-    storeAppendPrintf(sentry, "\tProcess Data Segment Size via sbrk(): %lu KB\n",
-                      (unsigned long) (((char *) sbrk(0) - (char *) sbrk_start) >> 10));
+    storeAppendPrintf(sentry, "\tProcess Data Segment Size via sbrk(): %.0f KB\n",
+                      stats.proc_data_seg / 1024);
 
 #endif
 
-    storeAppendPrintf(sentry, "\tMaximum Resident Size: %ld KB\n",
-                      (long)rusage_maxrss(&rusage));
+    storeAppendPrintf(sentry, "\tMaximum Resident Size: %.0f KB\n",
+                      stats.maxrss);
 
-    storeAppendPrintf(sentry, "\tPage faults with physical i/o: %ld\n",
-                      (long)rusage_pagefaults(&rusage));
+    storeAppendPrintf(sentry, "\tPage faults with physical i/o: %.0f\n",
+                      stats.page_faults);
 
 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
 
-    ms = mstats();
-
     storeAppendPrintf(sentry, "Memory usage for %s via mstats():\n",APP_SHORTNAME);
 
-    storeAppendPrintf(sentry, "\tTotal space in arena:  %6ld KB\n",
-                      (long)(ms.bytes_total >> 10));
+    storeAppendPrintf(sentry, "\tTotal space in arena:  %6.0f KB\n",
+                      stats.ms_bytes_total / 1024);
 
-    storeAppendPrintf(sentry, "\tTotal free:            %6ld KB %d%%\n",
-                      (long)(ms.bytes_free >> 10), Math::intPercent(ms.bytes_free, ms.bytes_total));
+    storeAppendPrintf(sentry, "\tTotal free:            %6.0f KB %.0f%%\n",
+                      stats.ms_bytes_free / 1024,
+                      Math::doublePercent(stats.ms_bytes_free, stats.ms_bytes_total));
 
 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
 
-    mp = mallinfo();
-
     storeAppendPrintf(sentry, "Memory usage for %s via mallinfo():\n",APP_SHORTNAME);
 
-    storeAppendPrintf(sentry, "\tTotal space in arena:  %6ld KB\n",
-                      (long)(mp.arena >> 10));
+    storeAppendPrintf(sentry, "\tTotal space in arena:  %6.0f KB\n",
+                      stats.mp_arena / 1024);
 
-    storeAppendPrintf(sentry, "\tOrdinary blocks:       %6ld KB %6ld blks\n",
-                      (long)(mp.uordblks >> 10), (long)mp.ordblks);
+    storeAppendPrintf(sentry, "\tOrdinary blocks:       %6.0f KB %6.0f blks\n",
+                      stats.mp_uordblks / 1024, stats.mp_ordblks);
 
-    storeAppendPrintf(sentry, "\tSmall blocks:          %6ld KB %6ld blks\n",
-                      (long)(mp.usmblks >> 10), (long)mp.smblks);
+    storeAppendPrintf(sentry, "\tSmall blocks:          %6.0f KB %6.0f blks\n",
+                      stats.mp_usmblks / 1024, stats.mp_smblks);
 
-    storeAppendPrintf(sentry, "\tHolding blocks:        %6ld KB %6ld blks\n",
-                      (long)(mp.hblkhd >> 10), (long)mp.hblks);
+    storeAppendPrintf(sentry, "\tHolding blocks:        %6.0f KB %6.0f blks\n",
+                      stats.mp_hblkhd / 1024, stats.mp_hblks);
 
-    storeAppendPrintf(sentry, "\tFree Small blocks:     %6ld KB\n",
-                      (long)(mp.fsmblks >> 10));
+    storeAppendPrintf(sentry, "\tFree Small blocks:     %6.0f KB\n",
+                      stats.mp_fsmblks / 1024);
 
-    storeAppendPrintf(sentry, "\tFree Ordinary blocks:  %6ld KB\n",
-                      (long)(mp.fordblks >> 10));
+    storeAppendPrintf(sentry, "\tFree Ordinary blocks:  %6.0f KB\n",
+                      stats.mp_fordblks / 1024);
 
-    t = mp.uordblks + mp.usmblks + mp.hblkhd;
+    double t = stats.mp_fsmblks + stats.mp_fordblks;
 
-    storeAppendPrintf(sentry, "\tTotal in use:          %6ld KB %d%%\n",
-                      (long)(t >> 10), Math::intPercent(t, mp.arena + mp.hblkhd));
+    storeAppendPrintf(sentry, "\tTotal in use:          %6.0f KB %.0f%%\n",
+                      t / 1024, Math::doublePercent(t, stats.mp_arena + stats.mp_hblkhd));
 
-    t = mp.fsmblks + mp.fordblks;
+    t = stats.mp_fsmblks + stats.mp_fordblks;
 
-    storeAppendPrintf(sentry, "\tTotal free:            %6ld KB %d%%\n",
-                      (long)(t >> 10), Math::intPercent(t, mp.arena + mp.hblkhd));
+    storeAppendPrintf(sentry, "\tTotal free:            %6.0f KB %.0f%%\n",
+                      t / 1024, Math::doublePercent(t, stats.mp_arena + stats.mp_hblkhd));
 
-    t = mp.arena + mp.hblkhd;
+    t = stats.mp_arena + stats.mp_hblkhd;
 
-    storeAppendPrintf(sentry, "\tTotal size:            %6ld KB\n",
-                      (long)(t >> 10));
+    storeAppendPrintf(sentry, "\tTotal size:            %6.0f KB\n",
+                      t / 1024);
 
 #if HAVE_STRUCT_MALLINFO_MXFAST
 
-    storeAppendPrintf(sentry, "\tmax size of small blocks:\t%d\n", mp.mxfast);
+    storeAppendPrintf(sentry, "\tmax size of small blocks:\t%.0f\n", stats.mp_mxfast);
 
-    storeAppendPrintf(sentry, "\tnumber of small blocks in a holding block:\t%ld\n",
-                      (long)mp.nlblks);
+    storeAppendPrintf(sentry, "\tnumber of small blocks in a holding block:\t%.0f\n",
+                      stats.mp_nlblks);
 
-    storeAppendPrintf(sentry, "\tsmall block rounding factor:\t%ld\n", (long)mp.grain);
+    storeAppendPrintf(sentry, "\tsmall block rounding factor:\t%.0f\n", stats.mp_grain);
 
-    storeAppendPrintf(sentry, "\tspace (including overhead) allocated in ord. blks:\t%ld\n",
-                      (long)mp.uordbytes);
+    storeAppendPrintf(sentry, "\tspace (including overhead) allocated in ord. blks:\t%.0f\n"
+                      ,stats.mp_uordbytes);
 
-    storeAppendPrintf(sentry, "\tnumber of ordinary blocks allocated:\t%ld\n",
-                      (long)mp.allocated);
+    storeAppendPrintf(sentry, "\tnumber of ordinary blocks allocated:\t%.0f\n",
+                      stats.mp_allocated);
 
-    storeAppendPrintf(sentry, "\tbytes used in maintaining the free tree:\t%ld\n",
-                      (long)mp.treeoverhead);
+    storeAppendPrintf(sentry, "\tbytes used in maintaining the free tree:\t%.0f\n",
+                      stats.mp_treeoverhead);
 
 #endif /* HAVE_STRUCT_MALLINFO_MXFAST */
 #endif /* HAVE_MALLINFO */
@@ -696,13 +899,13 @@ info_get(StoreEntry * sentry)
 
 #if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
 
-    storeAppendPrintf(sentry, "\tTotal accounted:       %6ld KB %3d%%\n",
-                      (long)(statMemoryAccounted() >> 10), Math::intPercent(statMemoryAccounted(), t));
+    storeAppendPrintf(sentry, "\tTotal accounted:       %6.0f KB %3.0f%%\n",
+                      stats.total_accounted / 1024, Math::doublePercent(stats.total_accounted, t));
 
 #else
 
-    storeAppendPrintf(sentry, "\tTotal accounted:       %6ld KB\n",
-                      (long)(statMemoryAccounted() >> 10));
+    storeAppendPrintf(sentry, "\tTotal accounted:       %6.0f KB\n",
+                      stats.total_accounted / 1024);
 
 #endif
     {
@@ -710,46 +913,52 @@ info_get(StoreEntry * sentry)
         memPoolGetGlobalStats(&mp_stats);
 #if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
 
-        storeAppendPrintf(sentry, "\tmemPool accounted:     %6ld KB %3d%%\n",
-                          (long)(mp_stats.TheMeter->alloc.level >> 10),
-                          Math::intPercent(mp_stats.TheMeter->alloc.level, t));
-        storeAppendPrintf(sentry, "\tmemPool unaccounted:   %6ld KB %3d%%\n",
-                          (long)((t - mp_stats.TheMeter->alloc.level) >> 10),
-                          Math::intPercent((t - mp_stats.TheMeter->alloc.level), t));
+        storeAppendPrintf(sentry, "\tmemPool accounted:     %6.0f KB %3.0f%%\n",
+                          stats.mem_pool_allocated / 1024,
+                          Math::doublePercent(stats.mem_pool_allocated, t));
+
+        const double iFree = max(0.0, t - stats.mem_pool_allocated);
+        storeAppendPrintf(sentry, "\tmemPool unaccounted:   %6.0f KB %3.0f%%\n",
+                          (t - stats.mem_pool_allocated) / 1024,
+                          Math::doublePercent(iFree, t));
 #endif
 
         storeAppendPrintf(sentry, "\tmemPoolAlloc calls: %9.0f\n",
-                          mp_stats.TheMeter->gb_saved.count);
+                          stats.gb_saved_count);
         storeAppendPrintf(sentry, "\tmemPoolFree calls:  %9.0f\n",
-                          mp_stats.TheMeter->gb_freed.count);
+                          stats.gb_freed_count);
     }
 
     storeAppendPrintf(sentry, "File descriptor usage for %s:\n", APP_SHORTNAME);
-    storeAppendPrintf(sentry, "\tMaximum number of file descriptors:   %4d\n",
-                      Squid_MaxFD);
-    storeAppendPrintf(sentry, "\tLargest file desc currently in use:   %4d\n",
-                      Biggest_FD);
-    storeAppendPrintf(sentry, "\tNumber of file desc currently in use: %4d\n",
-                      Number_FD);
-    storeAppendPrintf(sentry, "\tFiles queued for open:                %4d\n",
-                      Opening_FD);
-    storeAppendPrintf(sentry, "\tAvailable number of file descriptors: %4d\n",
-                      fdNFree());
-    storeAppendPrintf(sentry, "\tReserved number of file descriptors:  %4d\n",
-                      RESERVED_FD);
-    storeAppendPrintf(sentry, "\tStore Disk files open:                %4d\n",
-                      store_open_disk_fd);
+    storeAppendPrintf(sentry, "\tMaximum number of file descriptors:   %4.0f\n",
+                      stats.max_fd);
+    storeAppendPrintf(sentry, "\tLargest file desc currently in use:   %4.0f\n",
+                      stats.biggest_fd);
+    storeAppendPrintf(sentry, "\tNumber of file desc currently in use: %4.0f\n",
+                      stats.number_fd);
+    storeAppendPrintf(sentry, "\tFiles queued for open:                %4.0f\n",
+                      stats.opening_fd);
+    storeAppendPrintf(sentry, "\tAvailable number of file descriptors: %4.0f\n",
+                      stats.num_fd_free);
+    storeAppendPrintf(sentry, "\tReserved number of file descriptors:  %4.0f\n",
+                      stats.reserved_fd);
+    storeAppendPrintf(sentry, "\tStore Disk files open:                %4.0f\n",
+                      stats.store_open_disk_fd);
 
     storeAppendPrintf(sentry, "Internal Data Structures:\n");
-    storeAppendPrintf(sentry, "\t%6lu StoreEntries\n",
-                      (unsigned long)StoreEntry::inUseCount());
-    storeAppendPrintf(sentry, "\t%6lu StoreEntries with MemObjects\n",
-                      (unsigned long)MemObject::inUseCount());
-    storeAppendPrintf(sentry, "\t%6ld Hot Object Cache Items\n",
-                      (long)hot_obj_count);
-    storeAppendPrintf(sentry, "\t%6ld on-disk objects\n",
-                      (long)n_disk_objects);
+    storeAppendPrintf(sentry, "\t%6.0f StoreEntries\n",
+                      stats.store_entries);
+    storeAppendPrintf(sentry, "\t%6.0f StoreEntries with MemObjects\n",
+                      stats.store_mem_entries);
+    storeAppendPrintf(sentry, "\t%6.0f Hot Object Cache Items\n",
+                      stats.hot_obj_count);
+    storeAppendPrintf(sentry, "\t%6.0f on-disk objects\n",
+                      stats.n_disk_objects);
+}
 
+void
+DumpMallocStatistics(StoreEntry* sentry)
+{
 #if XMALLOC_STATISTICS
 
     xm_deltat = current_dtime - xm_time;
@@ -760,64 +969,100 @@ info_get(StoreEntry * sentry)
 #endif
 }
 
-static void
-service_times(StoreEntry * sentry)
+void
+GetServiceTimesStats(Mgr::ServiceTimesActionData& stats)
+{
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
+        double p = (i + 1) * 5 / 100.0;
+        stats.http_requests5[i] = statPctileSvc(p, 5, PCTILE_HTTP);
+        stats.http_requests60[i] = statPctileSvc(p, 60, PCTILE_HTTP);
+
+        stats.cache_misses5[i] = statPctileSvc(p, 5, PCTILE_MISS);
+        stats.cache_misses60[i] = statPctileSvc(p, 60, PCTILE_MISS);
+
+        stats.cache_hits5[i] = statPctileSvc(p, 5, PCTILE_HIT);
+        stats.cache_hits60[i] = statPctileSvc(p, 60, PCTILE_HIT);
+
+        stats.near_hits5[i] = statPctileSvc(p, 5, PCTILE_NH);
+        stats.near_hits60[i] = statPctileSvc(p, 60, PCTILE_NH);
+
+        stats.not_modified_replies5[i] = statPctileSvc(p, 5, PCTILE_NM);
+        stats.not_modified_replies60[i] = statPctileSvc(p, 60, PCTILE_NM);
+
+        stats.dns_lookups5[i] = statPctileSvc(p, 5, PCTILE_DNS);
+        stats.dns_lookups60[i] = statPctileSvc(p, 60, PCTILE_DNS);
+
+        stats.icp_queries5[i] = statPctileSvc(p, 5, PCTILE_ICP_QUERY);
+        stats.icp_queries60[i] = statPctileSvc(p, 60, PCTILE_ICP_QUERY);
+    }
+}
+
+void
+DumpServiceTimesStats(Mgr::ServiceTimesActionData& stats, StoreEntry* sentry)
 {
-    int p;
     storeAppendPrintf(sentry, "Service Time Percentiles            5 min    60 min:\n");
-    for (p = 5; p < 100; p += 5) {
+    double fct = stats.count > 1 ? stats.count * 1000.0 : 1000.0;
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tHTTP Requests (All):  %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_HTTP) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_HTTP) / 1000.0);
+                          (i + 1) * 5,
+                          stats.http_requests5[i] / fct,
+                          stats.http_requests60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tCache Misses:         %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_MISS) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_MISS) / 1000.0);
+                          (i + 1) * 5,
+                          stats.cache_misses5[i] / fct,
+                          stats.cache_misses60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tCache Hits:           %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_HIT) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_HIT) / 1000.0);
+                          (i + 1) * 5,
+                          stats.cache_hits5[i] / fct,
+                          stats.cache_hits60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tNear Hits:            %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_NH) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_NH) / 1000.0);
+                          (i + 1) * 5,
+                          stats.near_hits5[i] / fct,
+                          stats.near_hits60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tNot-Modified Replies: %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_NM) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_NM) / 1000.0);
+                          (i + 1) * 5,
+                          stats.not_modified_replies5[i] / fct,
+                          stats.not_modified_replies60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tDNS Lookups:          %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_DNS) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_DNS) / 1000.0);
+                          (i + 1) * 5,
+                          stats.dns_lookups5[i] / fct,
+                          stats.dns_lookups60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    fct = stats.count > 1 ? stats.count * 1000000.0 : 1000000.0;
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tICP Queries:          %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_ICP_QUERY) / 1000000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_ICP_QUERY) / 1000000.0);
+                          (i + 1) * 5,
+                          stats.icp_queries5[i] / fct,
+                          stats.icp_queries60[i] / fct);
     }
 }
 
-#define XAVG(X) (dt ? (double) (f->X - l->X) / dt : 0.0)
 static void
 statAvgDump(StoreEntry * sentry, int minutes, int hours)
+{
+    Mgr::IntervalActionData stats;
+    GetAvgStat(stats, minutes, hours);
+    DumpAvgStat(stats, sentry);
+}
+
+#define XAVG(X) (dt ? (double) (f->X - l->X) / dt : 0.0)
+void
+GetAvgStat(Mgr::IntervalActionData& stats, int minutes, int hours)
 {
     StatCounters *f;
     StatCounters *l;
     double dt;
     double ct;
-    double x;
     assert(N_COUNT_HIST > 1);
     assert(minutes > 0 || hours > 0);
     f = &CountHist[0];
@@ -845,212 +1090,296 @@ statAvgDump(StoreEntry * sentry, int minutes, int hours)
     dt = tvSubDsec(l->timestamp, f->timestamp);
     ct = f->cputime - l->cputime;
 
+    stats.sample_start_time = l->timestamp;
+    stats.sample_end_time = f->timestamp;
+
+    stats.client_http_requests = XAVG(client_http.requests);
+    stats.client_http_hits = XAVG(client_http.hits);
+    stats.client_http_errors = XAVG(client_http.errors);
+    stats.client_http_kbytes_in = XAVG(client_http.kbytes_in.kb);
+    stats.client_http_kbytes_out = XAVG(client_http.kbytes_out.kb);
+
+    stats.client_http_all_median_svc_time = statHistDeltaMedian(&l->client_http.all_svc_time,
+                                            &f->client_http.all_svc_time) / 1000.0;
+    stats.client_http_miss_median_svc_time = statHistDeltaMedian(&l->client_http.miss_svc_time,
+            &f->client_http.miss_svc_time) / 1000.0;
+    stats.client_http_nm_median_svc_time = statHistDeltaMedian(&l->client_http.nm_svc_time,
+                                           &f->client_http.nm_svc_time) / 1000.0;
+    stats.client_http_nh_median_svc_time = statHistDeltaMedian(&l->client_http.nh_svc_time,
+                                           &f->client_http.nh_svc_time) / 1000.0;
+    stats.client_http_hit_median_svc_time = statHistDeltaMedian(&l->client_http.hit_svc_time,
+                                            &f->client_http.hit_svc_time) / 1000.0;
+
+    stats.server_all_requests = XAVG(server.all.requests);
+    stats.server_all_errors = XAVG(server.all.errors);
+    stats.server_all_kbytes_in = XAVG(server.all.kbytes_in.kb);
+    stats.server_all_kbytes_out = XAVG(server.all.kbytes_out.kb);
+
+    stats.server_http_requests = XAVG(server.http.requests);
+    stats.server_http_errors = XAVG(server.http.errors);
+    stats.server_http_kbytes_in = XAVG(server.http.kbytes_in.kb);
+    stats.server_http_kbytes_out = XAVG(server.http.kbytes_out.kb);
+
+    stats.server_ftp_requests = XAVG(server.ftp.requests);
+    stats.server_ftp_errors = XAVG(server.ftp.errors);
+    stats.server_ftp_kbytes_in = XAVG(server.ftp.kbytes_in.kb);
+    stats.server_ftp_kbytes_out = XAVG(server.ftp.kbytes_out.kb);
+
+    stats.server_other_requests = XAVG(server.other.requests);
+    stats.server_other_errors = XAVG(server.other.errors);
+    stats.server_other_kbytes_in = XAVG(server.other.kbytes_in.kb);
+    stats.server_other_kbytes_out = XAVG(server.other.kbytes_out.kb);
+
+    stats.icp_pkts_sent = XAVG(icp.pkts_sent);
+    stats.icp_pkts_recv = XAVG(icp.pkts_recv);
+    stats.icp_queries_sent = XAVG(icp.queries_sent);
+    stats.icp_replies_sent = XAVG(icp.replies_sent);
+    stats.icp_queries_recv = XAVG(icp.queries_recv);
+    stats.icp_replies_recv = XAVG(icp.replies_recv);
+    stats.icp_replies_queued = XAVG(icp.replies_queued);
+    stats.icp_query_timeouts = XAVG(icp.query_timeouts);
+    stats.icp_kbytes_sent = XAVG(icp.kbytes_sent.kb);
+    stats.icp_kbytes_recv = XAVG(icp.kbytes_recv.kb);
+    stats.icp_q_kbytes_sent = XAVG(icp.q_kbytes_sent.kb);
+    stats.icp_r_kbytes_sent = XAVG(icp.r_kbytes_sent.kb);
+    stats.icp_q_kbytes_recv = XAVG(icp.q_kbytes_recv.kb);
+    stats.icp_r_kbytes_recv = XAVG(icp.r_kbytes_recv.kb);
+
+    stats.icp_query_median_svc_time = statHistDeltaMedian(&l->icp.query_svc_time,
+                                      &f->icp.query_svc_time) / 1000000.0;
+    stats.icp_reply_median_svc_time = statHistDeltaMedian(&l->icp.reply_svc_time,
+                                      &f->icp.reply_svc_time) / 1000000.0;
+    stats.dns_median_svc_time = statHistDeltaMedian(&l->dns.svc_time,
+                                &f->dns.svc_time) / 1000.0;
+
+    stats.unlink_requests = XAVG(unlink.requests);
+    stats.page_faults = XAVG(page_faults);
+    stats.select_loops = XAVG(select_loops);
+    stats.select_fds = XAVG(select_fds);
+    stats.average_select_fd_period = f->select_fds > l->select_fds ?
+                                     (f->select_time - l->select_time) / (f->select_fds - l->select_fds) : 0.0;
+
+    stats.median_select_fds = statHistDeltaMedian(&l->select_fds_hist, &f->select_fds_hist);
+    stats.swap_outs = XAVG(swap.outs);
+    stats.swap_ins = XAVG(swap.ins);
+    stats.swap_files_cleaned = XAVG(swap.files_cleaned);
+    stats.aborted_requests = XAVG(aborted_requests);
+
+    stats.syscalls_disk_opens = XAVG(syscalls.disk.opens);
+    stats.syscalls_disk_closes = XAVG(syscalls.disk.closes);
+    stats.syscalls_disk_reads = XAVG(syscalls.disk.reads);
+    stats.syscalls_disk_writes = XAVG(syscalls.disk.writes);
+    stats.syscalls_disk_seeks = XAVG(syscalls.disk.seeks);
+    stats.syscalls_disk_unlinks = XAVG(syscalls.disk.unlinks);
+    stats.syscalls_sock_accepts = XAVG(syscalls.sock.accepts);
+    stats.syscalls_sock_sockets = XAVG(syscalls.sock.sockets);
+    stats.syscalls_sock_connects = XAVG(syscalls.sock.connects);
+    stats.syscalls_sock_binds = XAVG(syscalls.sock.binds);
+    stats.syscalls_sock_closes = XAVG(syscalls.sock.closes);
+    stats.syscalls_sock_reads = XAVG(syscalls.sock.reads);
+    stats.syscalls_sock_writes = XAVG(syscalls.sock.writes);
+    stats.syscalls_sock_recvfroms = XAVG(syscalls.sock.recvfroms);
+    stats.syscalls_sock_sendtos = XAVG(syscalls.sock.sendtos);
+    stats.syscalls_selects = XAVG(syscalls.selects);
+
+    stats.cpu_time = ct;
+    stats.wall_time = dt;
+}
+
+void
+DumpAvgStat(Mgr::IntervalActionData& stats, StoreEntry* sentry)
+{
     storeAppendPrintf(sentry, "sample_start_time = %d.%d (%s)\n",
-                      (int) l->timestamp.tv_sec,
-                      (int) l->timestamp.tv_usec,
-                      mkrfc1123(l->timestamp.tv_sec));
+                      (int)stats.sample_start_time.tv_sec,
+                      (int)stats.sample_start_time.tv_usec,
+                      mkrfc1123(stats.sample_start_time.tv_sec));
     storeAppendPrintf(sentry, "sample_end_time = %d.%d (%s)\n",
-                      (int) f->timestamp.tv_sec,
-                      (int) f->timestamp.tv_usec,
-                      mkrfc1123(f->timestamp.tv_sec));
+                      (int)stats.sample_end_time.tv_sec,
+                      (int)stats.sample_end_time.tv_usec,
+                      mkrfc1123(stats.sample_end_time.tv_sec));
 
     storeAppendPrintf(sentry, "client_http.requests = %f/sec\n",
-                      XAVG(client_http.requests));
+                      stats.client_http_requests);
     storeAppendPrintf(sentry, "client_http.hits = %f/sec\n",
-                      XAVG(client_http.hits));
+                      stats.client_http_hits);
     storeAppendPrintf(sentry, "client_http.errors = %f/sec\n",
-                      XAVG(client_http.errors));
+                      stats.client_http_errors);
     storeAppendPrintf(sentry, "client_http.kbytes_in = %f/sec\n",
-                      XAVG(client_http.kbytes_in.kb));
+                      stats.client_http_kbytes_in);
     storeAppendPrintf(sentry, "client_http.kbytes_out = %f/sec\n",
-                      XAVG(client_http.kbytes_out.kb));
+                      stats.client_http_kbytes_out);
 
-    x = statHistDeltaMedian(&l->client_http.all_svc_time,
-                            &f->client_http.all_svc_time);
+    double fct = stats.count > 1 ? stats.count : 1.0;
     storeAppendPrintf(sentry, "client_http.all_median_svc_time = %f seconds\n",
-                      x / 1000.0);
-    x = statHistDeltaMedian(&l->client_http.miss_svc_time,
-                            &f->client_http.miss_svc_time);
+                      stats.client_http_all_median_svc_time / fct);
     storeAppendPrintf(sentry, "client_http.miss_median_svc_time = %f seconds\n",
-                      x / 1000.0);
-    x = statHistDeltaMedian(&l->client_http.nm_svc_time,
-                            &f->client_http.nm_svc_time);
+                      stats.client_http_miss_median_svc_time / fct);
     storeAppendPrintf(sentry, "client_http.nm_median_svc_time = %f seconds\n",
-                      x / 1000.0);
-    x = statHistDeltaMedian(&l->client_http.nh_svc_time,
-                            &f->client_http.nh_svc_time);
+                      stats.client_http_nm_median_svc_time / fct);
     storeAppendPrintf(sentry, "client_http.nh_median_svc_time = %f seconds\n",
-                      x / 1000.0);
-    x = statHistDeltaMedian(&l->client_http.hit_svc_time,
-                            &f->client_http.hit_svc_time);
+                      stats.client_http_nh_median_svc_time / fct);
     storeAppendPrintf(sentry, "client_http.hit_median_svc_time = %f seconds\n",
-                      x / 1000.0);
+                      stats.client_http_hit_median_svc_time / fct);
 
     storeAppendPrintf(sentry, "server.all.requests = %f/sec\n",
-                      XAVG(server.all.requests));
+                      stats.server_all_requests);
     storeAppendPrintf(sentry, "server.all.errors = %f/sec\n",
-                      XAVG(server.all.errors));
+                      stats.server_all_errors);
     storeAppendPrintf(sentry, "server.all.kbytes_in = %f/sec\n",
-                      XAVG(server.all.kbytes_in.kb));
+                      stats.server_all_kbytes_in);
     storeAppendPrintf(sentry, "server.all.kbytes_out = %f/sec\n",
-                      XAVG(server.all.kbytes_out.kb));
+                      stats.server_all_kbytes_out);
 
     storeAppendPrintf(sentry, "server.http.requests = %f/sec\n",
-                      XAVG(server.http.requests));
+                      stats.server_http_requests);
     storeAppendPrintf(sentry, "server.http.errors = %f/sec\n",
-                      XAVG(server.http.errors));
+                      stats.server_http_errors);
     storeAppendPrintf(sentry, "server.http.kbytes_in = %f/sec\n",
-                      XAVG(server.http.kbytes_in.kb));
+                      stats.server_http_kbytes_in);
     storeAppendPrintf(sentry, "server.http.kbytes_out = %f/sec\n",
-                      XAVG(server.http.kbytes_out.kb));
+                      stats.server_http_kbytes_out);
 
     storeAppendPrintf(sentry, "server.ftp.requests = %f/sec\n",
-                      XAVG(server.ftp.requests));
+                      stats.server_ftp_requests);
     storeAppendPrintf(sentry, "server.ftp.errors = %f/sec\n",
-                      XAVG(server.ftp.errors));
+                      stats.server_ftp_errors);
     storeAppendPrintf(sentry, "server.ftp.kbytes_in = %f/sec\n",
-                      XAVG(server.ftp.kbytes_in.kb));
+                      stats.server_ftp_kbytes_in);
     storeAppendPrintf(sentry, "server.ftp.kbytes_out = %f/sec\n",
-                      XAVG(server.ftp.kbytes_out.kb));
+                      stats.server_ftp_kbytes_out);
 
     storeAppendPrintf(sentry, "server.other.requests = %f/sec\n",
-                      XAVG(server.other.requests));
+                      stats.server_other_requests);
     storeAppendPrintf(sentry, "server.other.errors = %f/sec\n",
-                      XAVG(server.other.errors));
+                      stats.server_other_errors);
     storeAppendPrintf(sentry, "server.other.kbytes_in = %f/sec\n",
-                      XAVG(server.other.kbytes_in.kb));
+                      stats.server_other_kbytes_in);
     storeAppendPrintf(sentry, "server.other.kbytes_out = %f/sec\n",
-                      XAVG(server.other.kbytes_out.kb));
+                      stats.server_other_kbytes_out);
 
     storeAppendPrintf(sentry, "icp.pkts_sent = %f/sec\n",
-                      XAVG(icp.pkts_sent));
+                      stats.icp_pkts_sent);
     storeAppendPrintf(sentry, "icp.pkts_recv = %f/sec\n",
-                      XAVG(icp.pkts_recv));
+                      stats.icp_pkts_recv);
     storeAppendPrintf(sentry, "icp.queries_sent = %f/sec\n",
-                      XAVG(icp.queries_sent));
+                      stats.icp_queries_sent);
     storeAppendPrintf(sentry, "icp.replies_sent = %f/sec\n",
-                      XAVG(icp.replies_sent));
+                      stats.icp_replies_sent);
     storeAppendPrintf(sentry, "icp.queries_recv = %f/sec\n",
-                      XAVG(icp.queries_recv));
+                      stats.icp_queries_recv);
     storeAppendPrintf(sentry, "icp.replies_recv = %f/sec\n",
-                      XAVG(icp.replies_recv));
+                      stats.icp_replies_recv);
     storeAppendPrintf(sentry, "icp.replies_queued = %f/sec\n",
-                      XAVG(icp.replies_queued));
+                      stats.icp_replies_queued);
     storeAppendPrintf(sentry, "icp.query_timeouts = %f/sec\n",
-                      XAVG(icp.query_timeouts));
+                      stats.icp_query_timeouts);
     storeAppendPrintf(sentry, "icp.kbytes_sent = %f/sec\n",
-                      XAVG(icp.kbytes_sent.kb));
+                      stats.icp_kbytes_sent);
     storeAppendPrintf(sentry, "icp.kbytes_recv = %f/sec\n",
-                      XAVG(icp.kbytes_recv.kb));
+                      stats.icp_kbytes_recv);
     storeAppendPrintf(sentry, "icp.q_kbytes_sent = %f/sec\n",
-                      XAVG(icp.q_kbytes_sent.kb));
+                      stats.icp_q_kbytes_sent);
     storeAppendPrintf(sentry, "icp.r_kbytes_sent = %f/sec\n",
-                      XAVG(icp.r_kbytes_sent.kb));
+                      stats.icp_r_kbytes_sent);
     storeAppendPrintf(sentry, "icp.q_kbytes_recv = %f/sec\n",
-                      XAVG(icp.q_kbytes_recv.kb));
+                      stats.icp_q_kbytes_recv);
     storeAppendPrintf(sentry, "icp.r_kbytes_recv = %f/sec\n",
-                      XAVG(icp.r_kbytes_recv.kb));
-    x = statHistDeltaMedian(&l->icp.query_svc_time, &f->icp.query_svc_time);
+                      stats.icp_r_kbytes_recv);
     storeAppendPrintf(sentry, "icp.query_median_svc_time = %f seconds\n",
-                      x / 1000000.0);
-    x = statHistDeltaMedian(&l->icp.reply_svc_time, &f->icp.reply_svc_time);
+                      stats.icp_query_median_svc_time / fct);
     storeAppendPrintf(sentry, "icp.reply_median_svc_time = %f seconds\n",
-                      x / 1000000.0);
-    x = statHistDeltaMedian(&l->dns.svc_time, &f->dns.svc_time);
+                      stats.icp_reply_median_svc_time / fct);
     storeAppendPrintf(sentry, "dns.median_svc_time = %f seconds\n",
-                      x / 1000.0);
+                      stats.dns_median_svc_time / fct);
     storeAppendPrintf(sentry, "unlink.requests = %f/sec\n",
-                      XAVG(unlink.requests));
+                      stats.unlink_requests);
     storeAppendPrintf(sentry, "page_faults = %f/sec\n",
-                      XAVG(page_faults));
+                      stats.page_faults);
     storeAppendPrintf(sentry, "select_loops = %f/sec\n",
-                      XAVG(select_loops));
+                      stats.select_loops);
     storeAppendPrintf(sentry, "select_fds = %f/sec\n",
-                      XAVG(select_fds));
+                      stats.select_fds);
     storeAppendPrintf(sentry, "average_select_fd_period = %f/fd\n",
-                      f->select_fds > l->select_fds ?
-                      (f->select_time - l->select_time) / (f->select_fds - l->select_fds)
-                      : 0.0);
-    x = statHistDeltaMedian(&l->select_fds_hist, &f->select_fds_hist);
-    storeAppendPrintf(sentry, "median_select_fds = %f\n", x);
+                      stats.average_select_fd_period / fct);
+    storeAppendPrintf(sentry, "median_select_fds = %f\n",
+                      stats.median_select_fds / fct);
     storeAppendPrintf(sentry, "swap.outs = %f/sec\n",
-                      XAVG(swap.outs));
+                      stats.swap_outs);
     storeAppendPrintf(sentry, "swap.ins = %f/sec\n",
-                      XAVG(swap.ins));
+                      stats.swap_ins);
     storeAppendPrintf(sentry, "swap.files_cleaned = %f/sec\n",
-                      XAVG(swap.files_cleaned));
+                      stats.swap_files_cleaned);
     storeAppendPrintf(sentry, "aborted_requests = %f/sec\n",
-                      XAVG(aborted_requests));
+                      stats.aborted_requests);
 
 #if USE_POLL
-    storeAppendPrintf(sentry, "syscalls.polls = %f/sec\n", XAVG(syscalls.selects));
+    storeAppendPrintf(sentry, "syscalls.polls = %f/sec\n", stats.syscalls_selects);
 #elif defined(USE_SELECT) || defined(USE_SELECT_WIN32)
-    storeAppendPrintf(sentry, "syscalls.selects = %f/sec\n", XAVG(syscalls.selects));
+    storeAppendPrintf(sentry, "syscalls.selects = %f/sec\n", stats.syscalls_selects);
 #endif
 
-    storeAppendPrintf(sentry, "syscalls.disk.opens = %f/sec\n", XAVG(syscalls.disk.opens));
-    storeAppendPrintf(sentry, "syscalls.disk.closes = %f/sec\n", XAVG(syscalls.disk.closes));
-    storeAppendPrintf(sentry, "syscalls.disk.reads = %f/sec\n", XAVG(syscalls.disk.reads));
-    storeAppendPrintf(sentry, "syscalls.disk.writes = %f/sec\n", XAVG(syscalls.disk.writes));
-    storeAppendPrintf(sentry, "syscalls.disk.seeks = %f/sec\n", XAVG(syscalls.disk.seeks));
-    storeAppendPrintf(sentry, "syscalls.disk.unlinks = %f/sec\n", XAVG(syscalls.disk.unlinks));
-    storeAppendPrintf(sentry, "syscalls.sock.accepts = %f/sec\n", XAVG(syscalls.sock.accepts));
-    storeAppendPrintf(sentry, "syscalls.sock.sockets = %f/sec\n", XAVG(syscalls.sock.sockets));
-    storeAppendPrintf(sentry, "syscalls.sock.connects = %f/sec\n", XAVG(syscalls.sock.connects));
-    storeAppendPrintf(sentry, "syscalls.sock.binds = %f/sec\n", XAVG(syscalls.sock.binds));
-    storeAppendPrintf(sentry, "syscalls.sock.closes = %f/sec\n", XAVG(syscalls.sock.closes));
-    storeAppendPrintf(sentry, "syscalls.sock.reads = %f/sec\n", XAVG(syscalls.sock.reads));
-    storeAppendPrintf(sentry, "syscalls.sock.writes = %f/sec\n", XAVG(syscalls.sock.writes));
-    storeAppendPrintf(sentry, "syscalls.sock.recvfroms = %f/sec\n", XAVG(syscalls.sock.recvfroms));
-    storeAppendPrintf(sentry, "syscalls.sock.sendtos = %f/sec\n", XAVG(syscalls.sock.sendtos));
-
-    storeAppendPrintf(sentry, "cpu_time = %f seconds\n", ct);
-    storeAppendPrintf(sentry, "wall_time = %f seconds\n", dt);
-    storeAppendPrintf(sentry, "cpu_usage = %f%%\n", Math::doublePercent(ct, dt));
+    storeAppendPrintf(sentry, "syscalls.disk.opens = %f/sec\n", stats.syscalls_disk_opens);
+    storeAppendPrintf(sentry, "syscalls.disk.closes = %f/sec\n", stats.syscalls_disk_closes);
+    storeAppendPrintf(sentry, "syscalls.disk.reads = %f/sec\n", stats.syscalls_disk_reads);
+    storeAppendPrintf(sentry, "syscalls.disk.writes = %f/sec\n", stats.syscalls_disk_writes);
+    storeAppendPrintf(sentry, "syscalls.disk.seeks = %f/sec\n", stats.syscalls_disk_seeks);
+    storeAppendPrintf(sentry, "syscalls.disk.unlinks = %f/sec\n", stats.syscalls_disk_unlinks);
+    storeAppendPrintf(sentry, "syscalls.sock.accepts = %f/sec\n", stats.syscalls_sock_accepts);
+    storeAppendPrintf(sentry, "syscalls.sock.sockets = %f/sec\n", stats.syscalls_sock_sockets);
+    storeAppendPrintf(sentry, "syscalls.sock.connects = %f/sec\n", stats.syscalls_sock_connects);
+    storeAppendPrintf(sentry, "syscalls.sock.binds = %f/sec\n", stats.syscalls_sock_binds);
+    storeAppendPrintf(sentry, "syscalls.sock.closes = %f/sec\n", stats.syscalls_sock_closes);
+    storeAppendPrintf(sentry, "syscalls.sock.reads = %f/sec\n", stats.syscalls_sock_reads);
+    storeAppendPrintf(sentry, "syscalls.sock.writes = %f/sec\n", stats.syscalls_sock_writes);
+    storeAppendPrintf(sentry, "syscalls.sock.recvfroms = %f/sec\n", stats.syscalls_sock_recvfroms);
+    storeAppendPrintf(sentry, "syscalls.sock.sendtos = %f/sec\n", stats.syscalls_sock_sendtos);
+
+    storeAppendPrintf(sentry, "cpu_time = %f seconds\n", stats.cpu_time);
+    storeAppendPrintf(sentry, "wall_time = %f seconds\n", stats.wall_time);
+    storeAppendPrintf(sentry, "cpu_usage = %f%%\n", Math::doublePercent(stats.cpu_time, stats.wall_time));
 }
 
 static void
 statRegisterWithCacheManager(void)
 {
-    CacheManager *manager = CacheManager::GetInstance();
-    manager->registerAction("info", "General Runtime Information",
-                            info_get, 0, 1);
-    manager->registerAction("service_times", "Service Times (Percentiles)",
-                            service_times, 0, 1);
-    manager->registerAction("filedescriptors", "Process Filedescriptor Allocation",
-                            fde::DumpStats, 0, 1);
-    manager->registerAction("objects", "All Cache Objects", stat_objects_get, 0, 0);
-    manager->registerAction("vm_objects", "In-Memory and In-Transit Objects",
-                            stat_vmobjects_get, 0, 0);
-    manager->registerAction("io", "Server-side network read() size histograms",
-                            stat_io_get, 0, 1);
-    manager->registerAction("counters", "Traffic and Resource Counters",
-                            statCountersDump, 0, 1);
-    manager->registerAction("peer_select", "Peer Selection Algorithms",
-                            statPeerSelect, 0, 1);
-    manager->registerAction("digest_stats", "Cache Digest and ICP blob",
-                            statDigestBlob, 0, 1);
-    manager->registerAction("5min", "5 Minute Average of Counters",
-                            statAvg5min, 0, 1);
-    manager->registerAction("60min", "60 Minute Average of Counters",
-                            statAvg60min, 0, 1);
-    manager->registerAction("utilization", "Cache Utilization",
-                            statUtilization, 0, 1);
-    manager->registerAction("histograms", "Full Histogram Counts",
-                            statCountersHistograms, 0, 1);
-    manager->registerAction("active_requests",
-                            "Client-side Active Requests",
-                            statClientRequests, 0, 1);
-    manager->registerAction("username_cache",
-                            "Active Cached Usernames",
-                            AuthUser::UsernameCacheStats, 0, 1);
+    Mgr::RegisterAction("info", "General Runtime Information",
+                        &Mgr::InfoAction::Create, 0, 1);
+    Mgr::RegisterAction("service_times", "Service Times (Percentiles)",
+                        &Mgr::ServiceTimesAction::Create, 0, 1);
+    Mgr::RegisterAction("filedescriptors", "Process Filedescriptor Allocation",
+                        fde::DumpStats, 0, 1);
+    Mgr::RegisterAction("objects", "All Cache Objects", stat_objects_get, 0, 0);
+    Mgr::RegisterAction("vm_objects", "In-Memory and In-Transit Objects",
+                        stat_vmobjects_get, 0, 0);
+    Mgr::RegisterAction("io", "Server-side network read() size histograms",
+                        &Mgr::IoAction::Create, 0, 1);
+    Mgr::RegisterAction("counters", "Traffic and Resource Counters",
+                        &Mgr::CountersAction::Create, 0, 1);
+    Mgr::RegisterAction("peer_select", "Peer Selection Algorithms",
+                        statPeerSelect, 0, 1);
+    Mgr::RegisterAction("digest_stats", "Cache Digest and ICP blob",
+                        statDigestBlob, 0, 1);
+    Mgr::RegisterAction("5min", "5 Minute Average of Counters",
+                        &Mgr::IntervalAction::Create5min, 0, 1);
+    Mgr::RegisterAction("60min", "60 Minute Average of Counters",
+                        &Mgr::IntervalAction::Create60min, 0, 1);
+    Mgr::RegisterAction("utilization", "Cache Utilization",
+                        statUtilization, 0, 1);
+    Mgr::RegisterAction("histograms", "Full Histogram Counts",
+                        statCountersHistograms, 0, 1);
+    Mgr::RegisterAction("active_requests",
+                        "Client-side Active Requests",
+                        statClientRequests, 0, 1);
+    Mgr::RegisterAction("username_cache",
+                        "Active Cached Usernames",
+                        AuthUser::UsernameCacheStats, 0, 1);
 #if DEBUG_OPENFD
-    manager->registerAction("openfd_objects", "Objects with Swapout files open",
-                            statOpenfdObj, 0, 0);
+    Mgr::RegisterAction("openfd_objects", "Objects with Swapout files open",
+                        statOpenfdObj, 0, 0);
 #endif
 #if STAT_GRAPHS
-    manager->registerAction("graph_variables", "Display cache metrics graphically",
-                            statGraphDump, 0, 1);
+    Mgr::RegisterAction("graph_variables", "Display cache metrics graphically",
+                        statGraphDump, 0, 1);
 #endif
 }
 
@@ -1258,6 +1587,14 @@ statCountersHistograms(StoreEntry * sentry)
 
 static void
 statCountersDump(StoreEntry * sentry)
+{
+    Mgr::CountersActionData stats;
+    GetCountersStats(stats);
+    DumpCountersStats(stats, sentry);
+}
+
+void
+GetCountersStats(Mgr::CountersActionData& stats)
 {
     StatCounters *f = &statCounter;
 
@@ -1266,126 +1603,195 @@ statCountersDump(StoreEntry * sentry)
     f->page_faults = rusage_pagefaults(&rusage);
     f->cputime = rusage_cputime(&rusage);
 
+    stats.sample_time = f->timestamp;
+    stats.client_http_requests = f->client_http.requests;
+    stats.client_http_hits = f->client_http.hits;
+    stats.client_http_errors = f->client_http.errors;
+    stats.client_http_kbytes_in = f->client_http.kbytes_in.kb;
+    stats.client_http_kbytes_out = f->client_http.kbytes_out.kb;
+    stats.client_http_hit_kbytes_out = f->client_http.hit_kbytes_out.kb;
+
+    stats.server_all_requests = f->server.all.requests;
+    stats.server_all_errors = f->server.all.errors;
+    stats.server_all_kbytes_in = f->server.all.kbytes_in.kb;
+    stats.server_all_kbytes_out = f->server.all.kbytes_out.kb;
+
+    stats.server_http_requests = f->server.http.requests;
+    stats.server_http_errors = f->server.http.errors;
+    stats.server_http_kbytes_in = f->server.http.kbytes_in.kb;
+    stats.server_http_kbytes_out = f->server.http.kbytes_out.kb;
+
+    stats.server_ftp_requests = f->server.ftp.requests;
+    stats.server_ftp_errors = f->server.ftp.errors;
+    stats.server_ftp_kbytes_in = f->server.ftp.kbytes_in.kb;
+    stats.server_ftp_kbytes_out = f->server.ftp.kbytes_out.kb;
+
+    stats.server_other_requests = f->server.other.requests;
+    stats.server_other_errors = f->server.other.errors;
+    stats.server_other_kbytes_in = f->server.other.kbytes_in.kb;
+    stats.server_other_kbytes_out = f->server.other.kbytes_out.kb;
+
+    stats.icp_pkts_sent = f->icp.pkts_sent;
+    stats.icp_pkts_recv = f->icp.pkts_recv;
+    stats.icp_queries_sent = f->icp.queries_sent;
+    stats.icp_replies_sent = f->icp.replies_sent;
+    stats.icp_queries_recv = f->icp.queries_recv;
+    stats.icp_replies_recv = f->icp.replies_recv;
+    stats.icp_query_timeouts = f->icp.query_timeouts;
+    stats.icp_replies_queued = f->icp.replies_queued;
+    stats.icp_kbytes_sent = f->icp.kbytes_sent.kb;
+    stats.icp_kbytes_recv = f->icp.kbytes_recv.kb;
+    stats.icp_q_kbytes_sent = f->icp.q_kbytes_sent.kb;
+    stats.icp_r_kbytes_sent = f->icp.r_kbytes_sent.kb;
+    stats.icp_q_kbytes_recv = f->icp.q_kbytes_recv.kb;
+    stats.icp_r_kbytes_recv = f->icp.r_kbytes_recv.kb;
+
+#if USE_CACHE_DIGESTS
+
+    stats.icp_times_used = f->icp.times_used;
+    stats.cd_times_used = f->cd.times_used;
+    stats.cd_msgs_sent = f->cd.msgs_sent;
+    stats.cd_msgs_recv = f->cd.msgs_recv;
+    stats.cd_memory = f->cd.memory.kb;
+    stats.cd_local_memory = store_digest ? store_digest->mask_size / 1024 : 0;
+    stats.cd_kbytes_sent = f->cd.kbytes_sent.kb;
+    stats.cd_kbytes_recv = f->cd.kbytes_recv.kb;
+#endif
+
+    stats.unlink_requests = f->unlink.requests;
+    stats.page_faults = f->page_faults;
+    stats.select_loops = f->select_loops;
+    stats.cpu_time = f->cputime;
+    stats.wall_time = tvSubDsec(f->timestamp, current_time);
+    stats.swap_outs = f->swap.outs;
+    stats.swap_ins = f->swap.ins;
+    stats.swap_files_cleaned = f->swap.files_cleaned;
+    stats.aborted_requests = f->aborted_requests;
+}
+
+void
+DumpCountersStats(Mgr::CountersActionData& stats, StoreEntry* sentry)
+{
     storeAppendPrintf(sentry, "sample_time = %d.%d (%s)\n",
-                      (int) f->timestamp.tv_sec,
-                      (int) f->timestamp.tv_usec,
-                      mkrfc1123(f->timestamp.tv_sec));
-    storeAppendPrintf(sentry, "client_http.requests = %ld\n",
-                      (long)f->client_http.requests);
-    storeAppendPrintf(sentry, "client_http.hits = %ld\n",
-                      (long)f->client_http.hits);
-    storeAppendPrintf(sentry, "client_http.errors = %ld\n",
-                      (long)f->client_http.errors);
-    storeAppendPrintf(sentry, "client_http.kbytes_in = %ld\n",
-                      (long)f->client_http.kbytes_in.kb);
-    storeAppendPrintf(sentry, "client_http.kbytes_out = %ld\n",
-                      (long)f->client_http.kbytes_out.kb);
-    storeAppendPrintf(sentry, "client_http.hit_kbytes_out = %ld\n",
-                      (long)f->client_http.hit_kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "server.all.requests = %ld\n",
-                      (long)f->server.all.requests);
-    storeAppendPrintf(sentry, "server.all.errors = %ld\n",
-                      (long) f->server.all.errors);
-    storeAppendPrintf(sentry, "server.all.kbytes_in = %ld\n",
-                      (long) f->server.all.kbytes_in.kb);
-    storeAppendPrintf(sentry, "server.all.kbytes_out = %ld\n",
-                      (long) f->server.all.kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "server.http.requests = %ld\n",
-                      (long) f->server.http.requests);
-    storeAppendPrintf(sentry, "server.http.errors = %ld\n",
-                      (long) f->server.http.errors);
-    storeAppendPrintf(sentry, "server.http.kbytes_in = %ld\n",
-                      (long) f->server.http.kbytes_in.kb);
-    storeAppendPrintf(sentry, "server.http.kbytes_out = %ld\n",
-                      (long) f->server.http.kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "server.ftp.requests = %ld\n",
-                      (long) f->server.ftp.requests);
-    storeAppendPrintf(sentry, "server.ftp.errors = %ld\n",
-                      (long) f->server.ftp.errors);
-    storeAppendPrintf(sentry, "server.ftp.kbytes_in = %ld\n",
-                      (long) f->server.ftp.kbytes_in.kb);
-    storeAppendPrintf(sentry, "server.ftp.kbytes_out = %ld\n",
-                      (long) f->server.ftp.kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "server.other.requests = %ld\n",
-                      (long) f->server.other.requests);
-    storeAppendPrintf(sentry, "server.other.errors = %ld\n",
-                      (long) f->server.other.errors);
-    storeAppendPrintf(sentry, "server.other.kbytes_in = %ld\n",
-                      (long) f->server.other.kbytes_in.kb);
-    storeAppendPrintf(sentry, "server.other.kbytes_out = %ld\n",
-                      (long) f->server.other.kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "icp.pkts_sent = %ld\n",
-                      (long)f->icp.pkts_sent);
-    storeAppendPrintf(sentry, "icp.pkts_recv = %ld\n",
-                      (long)f->icp.pkts_recv);
-    storeAppendPrintf(sentry, "icp.queries_sent = %ld\n",
-                      (long)f->icp.queries_sent);
-    storeAppendPrintf(sentry, "icp.replies_sent = %ld\n",
-                      (long)f->icp.replies_sent);
-    storeAppendPrintf(sentry, "icp.queries_recv = %ld\n",
-                      (long)f->icp.queries_recv);
-    storeAppendPrintf(sentry, "icp.replies_recv = %ld\n",
-                      (long)f->icp.replies_recv);
-    storeAppendPrintf(sentry, "icp.query_timeouts = %ld\n",
-                      (long)f->icp.query_timeouts);
-    storeAppendPrintf(sentry, "icp.replies_queued = %ld\n",
-                      (long)f->icp.replies_queued);
-    storeAppendPrintf(sentry, "icp.kbytes_sent = %ld\n",
-                      (long) f->icp.kbytes_sent.kb);
-    storeAppendPrintf(sentry, "icp.kbytes_recv = %ld\n",
-                      (long) f->icp.kbytes_recv.kb);
-    storeAppendPrintf(sentry, "icp.q_kbytes_sent = %ld\n",
-                      (long) f->icp.q_kbytes_sent.kb);
-    storeAppendPrintf(sentry, "icp.r_kbytes_sent = %ld\n",
-                      (long) f->icp.r_kbytes_sent.kb);
-    storeAppendPrintf(sentry, "icp.q_kbytes_recv = %ld\n",
-                      (long) f->icp.q_kbytes_recv.kb);
-    storeAppendPrintf(sentry, "icp.r_kbytes_recv = %ld\n",
-                      (long) f->icp.r_kbytes_recv.kb);
+                      (int) stats.sample_time.tv_sec,
+                      (int) stats.sample_time.tv_usec,
+                      mkrfc1123(stats.sample_time.tv_sec));
+    storeAppendPrintf(sentry, "client_http.requests = %.0f\n",
+                      stats.client_http_requests);
+    storeAppendPrintf(sentry, "client_http.hits = %.0f\n",
+                      stats.client_http_hits);
+    storeAppendPrintf(sentry, "client_http.errors = %.0f\n",
+                      stats.client_http_errors);
+    storeAppendPrintf(sentry, "client_http.kbytes_in = %.0f\n",
+                      stats.client_http_kbytes_in);
+    storeAppendPrintf(sentry, "client_http.kbytes_out = %.0f\n",
+                      stats.client_http_kbytes_out);
+    storeAppendPrintf(sentry, "client_http.hit_kbytes_out = %.0f\n",
+                      stats.client_http_hit_kbytes_out);
+
+    storeAppendPrintf(sentry, "server.all.requests = %.0f\n",
+                      stats.server_all_requests);
+    storeAppendPrintf(sentry, "server.all.errors = %.0f\n",
+                      stats.server_all_errors);
+    storeAppendPrintf(sentry, "server.all.kbytes_in = %.0f\n",
+                      stats.server_all_kbytes_in);
+    storeAppendPrintf(sentry, "server.all.kbytes_out = %.0f\n",
+                      stats.server_all_kbytes_out);
+
+    storeAppendPrintf(sentry, "server.http.requests = %.0f\n",
+                      stats.server_http_requests);
+    storeAppendPrintf(sentry, "server.http.errors = %.0f\n",
+                      stats.server_http_errors);
+    storeAppendPrintf(sentry, "server.http.kbytes_in = %.0f\n",
+                      stats.server_http_kbytes_in);
+    storeAppendPrintf(sentry, "server.http.kbytes_out = %.0f\n",
+                      stats.server_http_kbytes_out);
+
+    storeAppendPrintf(sentry, "server.ftp.requests = %.0f\n",
+                      stats.server_ftp_requests);
+    storeAppendPrintf(sentry, "server.ftp.errors = %.0f\n",
+                      stats.server_ftp_errors);
+    storeAppendPrintf(sentry, "server.ftp.kbytes_in = %.0f\n",
+                      stats.server_ftp_kbytes_in);
+    storeAppendPrintf(sentry, "server.ftp.kbytes_out = %.0f\n",
+                      stats.server_ftp_kbytes_out);
+
+    storeAppendPrintf(sentry, "server.other.requests = %.0f\n",
+                      stats.server_other_requests);
+    storeAppendPrintf(sentry, "server.other.errors = %.0f\n",
+                      stats.server_other_errors);
+    storeAppendPrintf(sentry, "server.other.kbytes_in = %.0f\n",
+                      stats.server_other_kbytes_in);
+    storeAppendPrintf(sentry, "server.other.kbytes_out = %.0f\n",
+                      stats.server_other_kbytes_out);
+
+    storeAppendPrintf(sentry, "icp.pkts_sent = %.0f\n",
+                      stats.icp_pkts_sent);
+    storeAppendPrintf(sentry, "icp.pkts_recv = %.0f\n",
+                      stats.icp_pkts_recv);
+    storeAppendPrintf(sentry, "icp.queries_sent = %.0f\n",
+                      stats.icp_queries_sent);
+    storeAppendPrintf(sentry, "icp.replies_sent = %.0f\n",
+                      stats.icp_replies_sent);
+    storeAppendPrintf(sentry, "icp.queries_recv = %.0f\n",
+                      stats.icp_queries_recv);
+    storeAppendPrintf(sentry, "icp.replies_recv = %.0f\n",
+                      stats.icp_replies_recv);
+    storeAppendPrintf(sentry, "icp.query_timeouts = %.0f\n",
+                      stats.icp_query_timeouts);
+    storeAppendPrintf(sentry, "icp.replies_queued = %.0f\n",
+                      stats.icp_replies_queued);
+    storeAppendPrintf(sentry, "icp.kbytes_sent = %.0f\n",
+                      stats.icp_kbytes_sent);
+    storeAppendPrintf(sentry, "icp.kbytes_recv = %.0f\n",
+                      stats.icp_kbytes_recv);
+    storeAppendPrintf(sentry, "icp.q_kbytes_sent = %.0f\n",
+                      stats.icp_q_kbytes_sent);
+    storeAppendPrintf(sentry, "icp.r_kbytes_sent = %.0f\n",
+                      stats.icp_r_kbytes_sent);
+    storeAppendPrintf(sentry, "icp.q_kbytes_recv = %.0f\n",
+                      stats.icp_q_kbytes_recv);
+    storeAppendPrintf(sentry, "icp.r_kbytes_recv = %.0f\n",
+                      stats.icp_r_kbytes_recv);
 
 #if USE_CACHE_DIGESTS
 
-    storeAppendPrintf(sentry, "icp.times_used = %ld\n",
-                      (long)f->icp.times_used);
-    storeAppendPrintf(sentry, "cd.times_used = %ld\n",
-                      (long)f->cd.times_used);
-    storeAppendPrintf(sentry, "cd.msgs_sent = %ld\n",
-                      (long)f->cd.msgs_sent);
-    storeAppendPrintf(sentry, "cd.msgs_recv = %ld\n",
-                      (long)f->cd.msgs_recv);
-    storeAppendPrintf(sentry, "cd.memory = %ld\n",
-                      (long) f->cd.memory.kb);
-    storeAppendPrintf(sentry, "cd.local_memory = %ld\n",
-                      (long) (store_digest ? store_digest->mask_size / 1024 : 0));
-    storeAppendPrintf(sentry, "cd.kbytes_sent = %ld\n",
-                      (long) f->cd.kbytes_sent.kb);
-    storeAppendPrintf(sentry, "cd.kbytes_recv = %ld\n",
-                      (long) f->cd.kbytes_recv.kb);
+    storeAppendPrintf(sentry, "icp.times_used = %.0f\n",
+                      stats.icp_times_used);
+    storeAppendPrintf(sentry, "cd.times_used = %.0f\n",
+                      stats.cd_times_used);
+    storeAppendPrintf(sentry, "cd.msgs_sent = %.0f\n",
+                      stats.cd_msgs_sent);
+    storeAppendPrintf(sentry, "cd.msgs_recv = %.0f\n",
+                      stats.cd_msgs_recv);
+    storeAppendPrintf(sentry, "cd.memory = %.0f\n",
+                      stats.cd_memory);
+    storeAppendPrintf(sentry, "cd.local_memory = %.0f\n",
+                      stats.cd_local_memory);
+    storeAppendPrintf(sentry, "cd.kbytes_sent = %.0f\n",
+                      stats.cd_kbytes_sent);
+    storeAppendPrintf(sentry, "cd.kbytes_recv = %.0f\n",
+                      stats.cd_kbytes_recv);
 #endif
 
-    storeAppendPrintf(sentry, "unlink.requests = %ld\n",
-                      (long)f->unlink.requests);
-    storeAppendPrintf(sentry, "page_faults = %ld\n",
-                      (long)f->page_faults);
-    storeAppendPrintf(sentry, "select_loops = %ld\n",
-                      (long)f->select_loops);
+    storeAppendPrintf(sentry, "unlink.requests = %.0f\n",
+                      stats.unlink_requests);
+    storeAppendPrintf(sentry, "page_faults = %.0f\n",
+                      stats.page_faults);
+    storeAppendPrintf(sentry, "select_loops = %.0f\n",
+                      stats.select_loops);
     storeAppendPrintf(sentry, "cpu_time = %f\n",
-                      f->cputime);
+                      stats.cpu_time);
     storeAppendPrintf(sentry, "wall_time = %f\n",
-                      tvSubDsec(f->timestamp, current_time));
-    storeAppendPrintf(sentry, "swap.outs = %ld\n",
-                      (long)f->swap.outs);
-    storeAppendPrintf(sentry, "swap.ins = %ld\n",
-                      (long)f->swap.ins);
-    storeAppendPrintf(sentry, "swap.files_cleaned = %ld\n",
-                      (long)f->swap.files_cleaned);
-    storeAppendPrintf(sentry, "aborted_requests = %ld\n",
-                      (long)f->aborted_requests);
+                      stats.wall_time);
+    storeAppendPrintf(sentry, "swap.outs = %.0f\n",
+                      stats.swap_outs);
+    storeAppendPrintf(sentry, "swap.ins = %.0f\n",
+                      stats.swap_ins);
+    storeAppendPrintf(sentry, "swap.files_cleaned = %.0f\n",
+                      stats.swap_files_cleaned);
+    storeAppendPrintf(sentry, "aborted_requests = %.0f\n",
+                      stats.aborted_requests);
 }
 
 void
@@ -1450,18 +1856,6 @@ statDigestBlob(StoreEntry * sentry)
     storeDigestReport(sentry);
 }
 
-static void
-statAvg5min(StoreEntry * e)
-{
-    statAvgDump(e, 5, 0);
-}
-
-static void
-statAvg60min(StoreEntry * e)
-{
-    statAvgDump(e, 60, 0);
-}
-
 static double
 statPctileSvc(double pctile, int interval, int which)
 {