]> git.ipfire.org Git - thirdparty/squid.git/blob - src/stat.cc
Merged from trunk
[thirdparty/squid.git] / src / stat.cc
1 /*
2 * DEBUG: section 18 Cache Manager Statistics
3 * AUTHOR: Harvest Derived
4 *
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
7 *
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 */
32
33 #include "squid.h"
34 #include "CacheDigest.h"
35 #include "CachePeer.h"
36 #include "client_side_request.h"
37 #include "client_side.h"
38 #include "comm/Connection.h"
39 #include "comm/Loops.h"
40 #include "event.h"
41 #include "fde.h"
42 #include "format/Token.h"
43 #include "globals.h"
44 #include "HttpRequest.h"
45 #include "MemObject.h"
46 #include "mem_node.h"
47 #include "MemBuf.h"
48 #include "mgr/CountersAction.h"
49 #include "mgr/FunAction.h"
50 #include "mgr/InfoAction.h"
51 #include "mgr/IntervalAction.h"
52 #include "mgr/IoAction.h"
53 #include "mgr/Registration.h"
54 #include "mgr/ServiceTimesAction.h"
55 #include "neighbors.h"
56 #include "PeerDigest.h"
57 #include "SquidConfig.h"
58 #include "SquidMath.h"
59 #include "SquidTime.h"
60 #include "StatCounters.h"
61 #include "stat.h"
62 #include "StoreClient.h"
63 #include "Store.h"
64 #include "store_digest.h"
65 #include "tools.h"
66 #if USE_AUTH
67 #include "auth/UserRequest.h"
68 #endif
69 #if USE_DELAY_POOLS
70 #include "DelayId.h"
71 #endif
72 #if USE_SSL
73 #include "ssl/support.h"
74 #endif
75
76 /* these are included because they expose stats calls */
77 /* TODO: provide a self registration mechanism for those classes
78 * to use during static construction
79 */
80 #include "comm.h"
81 #include "StoreSearch.h"
82
83 #define DEBUG_OPENFD 1
84
85 typedef int STOBJFLT(const StoreEntry *);
86
87 class StatObjectsState
88 {
89
90 public:
91 StoreEntry *sentry;
92 STOBJFLT *filter;
93 StoreSearchPointer theSearch;
94
95 private:
96 CBDATA_CLASS2(StatObjectsState);
97 };
98
99 /* LOCALS */
100 static const char *describeStatuses(const StoreEntry *);
101 static const char *describeTimestamps(const StoreEntry *);
102 static void statAvgTick(void *notused);
103 static void statAvgDump(StoreEntry *, int minutes, int hours);
104 #if STAT_GRAPHS
105 static void statGraphDump(StoreEntry *);
106 #endif
107 static void statCountersInit(StatCounters *);
108 static void statCountersInitSpecial(StatCounters *);
109 static void statCountersClean(StatCounters *);
110 static void statCountersCopy(StatCounters * dest, const StatCounters * orig);
111 static double statPctileSvc(double, int, int);
112 static void statStoreEntry(MemBuf * mb, StoreEntry * e);
113 static double statCPUUsage(int minutes);
114 static OBJH stat_objects_get;
115 static OBJH stat_vmobjects_get;
116 #if DEBUG_OPENFD
117 static OBJH statOpenfdObj;
118 #endif
119 static EVH statObjects;
120 static OBJH statCountersDump;
121 static OBJH statPeerSelect;
122 static OBJH statDigestBlob;
123 static OBJH statUtilization;
124 static OBJH statCountersHistograms;
125 static OBJH statClientRequests;
126 void GetAvgStat(Mgr::IntervalActionData& stats, int minutes, int hours);
127 void DumpAvgStat(Mgr::IntervalActionData& stats, StoreEntry* sentry);
128 void GetInfo(Mgr::InfoActionData& stats);
129 void DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry);
130 void DumpMallocStatistics(StoreEntry* sentry);
131 void GetCountersStats(Mgr::CountersActionData& stats);
132 void DumpCountersStats(Mgr::CountersActionData& stats, StoreEntry* sentry);
133 void GetServiceTimesStats(Mgr::ServiceTimesActionData& stats);
134 void DumpServiceTimesStats(Mgr::ServiceTimesActionData& stats, StoreEntry* sentry);
135 void GetIoStats(Mgr::IoActionData& stats);
136 void DumpIoStats(Mgr::IoActionData& stats, StoreEntry* sentry);
137
138 #if XMALLOC_STATISTICS
139 static void info_get_mallstat(int, int, int, void *);
140 static double xm_time;
141 static double xm_deltat;
142 #endif
143
144 StatCounters CountHist[N_COUNT_HIST];
145 static int NCountHist = 0;
146 static StatCounters CountHourHist[N_COUNT_HOUR_HIST];
147 static int NCountHourHist = 0;
148 CBDATA_CLASS_INIT(StatObjectsState);
149
150 extern unsigned int mem_pool_alloc_calls;
151 extern unsigned int mem_pool_free_calls;
152
153 static void
154 statUtilization(StoreEntry * e)
155 {
156 storeAppendPrintf(e, "Cache Utilisation:\n");
157 storeAppendPrintf(e, "\n");
158 storeAppendPrintf(e, "Last 5 minutes:\n");
159
160 if (NCountHist >= 5)
161 statAvgDump(e, 5, 0);
162 else
163 storeAppendPrintf(e, "(no values recorded yet)\n");
164
165 storeAppendPrintf(e, "\n");
166
167 storeAppendPrintf(e, "Last 15 minutes:\n");
168
169 if (NCountHist >= 15)
170 statAvgDump(e, 15, 0);
171 else
172 storeAppendPrintf(e, "(no values recorded yet)\n");
173
174 storeAppendPrintf(e, "\n");
175
176 storeAppendPrintf(e, "Last hour:\n");
177
178 if (NCountHist >= 60)
179 statAvgDump(e, 60, 0);
180 else
181 storeAppendPrintf(e, "(no values recorded yet)\n");
182
183 storeAppendPrintf(e, "\n");
184
185 storeAppendPrintf(e, "Last 8 hours:\n");
186
187 if (NCountHourHist >= 8)
188 statAvgDump(e, 0, 8);
189 else
190 storeAppendPrintf(e, "(no values recorded yet)\n");
191
192 storeAppendPrintf(e, "\n");
193
194 storeAppendPrintf(e, "Last day:\n");
195
196 if (NCountHourHist >= 24)
197 statAvgDump(e, 0, 24);
198 else
199 storeAppendPrintf(e, "(no values recorded yet)\n");
200
201 storeAppendPrintf(e, "\n");
202
203 storeAppendPrintf(e, "Last 3 days:\n");
204
205 if (NCountHourHist >= 72)
206 statAvgDump(e, 0, 72);
207 else
208 storeAppendPrintf(e, "(no values recorded yet)\n");
209
210 storeAppendPrintf(e, "\n");
211
212 storeAppendPrintf(e, "Totals since cache startup:\n");
213
214 statCountersDump(e);
215 }
216
217 void
218 GetIoStats(Mgr::IoActionData& stats)
219 {
220 int i;
221
222 stats.http_reads = IOStats.Http.reads;
223
224 for (i = 0; i < iostats::histSize; ++i) {
225 stats.http_read_hist[i] = IOStats.Http.read_hist[i];
226 }
227
228 stats.ftp_reads = IOStats.Ftp.reads;
229
230 for (i = 0; i < iostats::histSize; ++i) {
231 stats.ftp_read_hist[i] = IOStats.Ftp.read_hist[i];
232 }
233
234 stats.gopher_reads = IOStats.Gopher.reads;
235
236 for (i = 0; i < iostats::histSize; ++i) {
237 stats.gopher_read_hist[i] = IOStats.Gopher.read_hist[i];
238 }
239 }
240
241 void
242 DumpIoStats(Mgr::IoActionData& stats, StoreEntry* sentry)
243 {
244 int i;
245
246 storeAppendPrintf(sentry, "HTTP I/O\n");
247 storeAppendPrintf(sentry, "number of reads: %.0f\n", stats.http_reads);
248 storeAppendPrintf(sentry, "Read Histogram:\n");
249
250 for (i = 0; i < iostats::histSize; ++i) {
251 storeAppendPrintf(sentry, "%5d-%5d: %9.0f %2.0f%%\n",
252 i ? (1 << (i - 1)) + 1 : 1,
253 1 << i,
254 stats.http_read_hist[i],
255 Math::doublePercent(stats.http_read_hist[i], stats.http_reads));
256 }
257
258 storeAppendPrintf(sentry, "\n");
259 storeAppendPrintf(sentry, "FTP I/O\n");
260 storeAppendPrintf(sentry, "number of reads: %.0f\n", stats.ftp_reads);
261 storeAppendPrintf(sentry, "Read Histogram:\n");
262
263 for (i = 0; i < iostats::histSize; ++i) {
264 storeAppendPrintf(sentry, "%5d-%5d: %9.0f %2.0f%%\n",
265 i ? (1 << (i - 1)) + 1 : 1,
266 1 << i,
267 stats.ftp_read_hist[i],
268 Math::doublePercent(stats.ftp_read_hist[i], stats.ftp_reads));
269 }
270
271 storeAppendPrintf(sentry, "\n");
272 storeAppendPrintf(sentry, "Gopher I/O\n");
273 storeAppendPrintf(sentry, "number of reads: %.0f\n", stats.gopher_reads);
274 storeAppendPrintf(sentry, "Read Histogram:\n");
275
276 for (i = 0; i < iostats::histSize; ++i) {
277 storeAppendPrintf(sentry, "%5d-%5d: %9.0f %2.0f%%\n",
278 i ? (1 << (i - 1)) + 1 : 1,
279 1 << i,
280 stats.gopher_read_hist[i],
281 Math::doublePercent(stats.gopher_read_hist[i], stats.gopher_reads));
282 }
283
284 storeAppendPrintf(sentry, "\n");
285 }
286
287 static const char *
288 describeStatuses(const StoreEntry * entry)
289 {
290 LOCAL_ARRAY(char, buf, 256);
291 snprintf(buf, 256, "%-13s %-13s %-12s %-12s",
292 storeStatusStr[entry->store_status],
293 memStatusStr[entry->mem_status],
294 swapStatusStr[entry->swap_status],
295 pingStatusStr[entry->ping_status]);
296 return buf;
297 }
298
299 const char *
300 storeEntryFlags(const StoreEntry * entry)
301 {
302 LOCAL_ARRAY(char, buf, 256);
303 int flags = (int) entry->flags;
304 char *t;
305 buf[0] = '\0';
306
307 if (EBIT_TEST(flags, ENTRY_SPECIAL))
308 strcat(buf, "SPECIAL,");
309
310 if (EBIT_TEST(flags, ENTRY_REVALIDATE))
311 strcat(buf, "REVALIDATE,");
312
313 if (EBIT_TEST(flags, DELAY_SENDING))
314 strcat(buf, "DELAY_SENDING,");
315
316 if (EBIT_TEST(flags, RELEASE_REQUEST))
317 strcat(buf, "RELEASE_REQUEST,");
318
319 if (EBIT_TEST(flags, REFRESH_REQUEST))
320 strcat(buf, "REFRESH_REQUEST,");
321
322 if (EBIT_TEST(flags, ENTRY_CACHABLE))
323 strcat(buf, "CACHABLE,");
324
325 if (EBIT_TEST(flags, ENTRY_DISPATCHED))
326 strcat(buf, "DISPATCHED,");
327
328 if (EBIT_TEST(flags, KEY_PRIVATE))
329 strcat(buf, "PRIVATE,");
330
331 if (EBIT_TEST(flags, ENTRY_FWD_HDR_WAIT))
332 strcat(buf, "FWD_HDR_WAIT,");
333
334 if (EBIT_TEST(flags, ENTRY_NEGCACHED))
335 strcat(buf, "NEGCACHED,");
336
337 if (EBIT_TEST(flags, ENTRY_VALIDATED))
338 strcat(buf, "VALIDATED,");
339
340 if (EBIT_TEST(flags, ENTRY_BAD_LENGTH))
341 strcat(buf, "BAD_LENGTH,");
342
343 if (EBIT_TEST(flags, ENTRY_ABORTED))
344 strcat(buf, "ABORTED,");
345
346 if ((t = strrchr(buf, ',')))
347 *t = '\0';
348
349 return buf;
350 }
351
352 static const char *
353 describeTimestamps(const StoreEntry * entry)
354 {
355 LOCAL_ARRAY(char, buf, 256);
356 snprintf(buf, 256, "LV:%-9d LU:%-9d LM:%-9d EX:%-9d",
357 (int) entry->timestamp,
358 (int) entry->lastref,
359 (int) entry->lastmod,
360 (int) entry->expires);
361 return buf;
362 }
363
364 static void
365 statStoreEntry(MemBuf * mb, StoreEntry * e)
366 {
367 MemObject *mem = e->mem_obj;
368 mb->Printf("KEY %s\n", e->getMD5Text());
369 mb->Printf("\t%s\n", describeStatuses(e));
370 mb->Printf("\t%s\n", storeEntryFlags(e));
371 mb->Printf("\t%s\n", describeTimestamps(e));
372 mb->Printf("\t%d locks, %d clients, %d refs\n",
373 (int) e->lock_count,
374 storePendingNClients(e),
375 (int) e->refcount);
376 mb->Printf("\tSwap Dir %d, File %#08X\n",
377 e->swap_dirn, e->swap_filen);
378
379 if (mem != NULL)
380 mem->stat (mb);
381
382 mb->Printf("\n");
383 }
384
385 /* process objects list */
386 static void
387 statObjects(void *data)
388 {
389 StatObjectsState *state = static_cast<StatObjectsState *>(data);
390 StoreEntry *e;
391
392 if (state->theSearch->isDone()) {
393 if (UsingSmp())
394 storeAppendPrintf(state->sentry, "} by kid%d\n\n", KidIdentifier);
395 state->sentry->complete();
396 state->sentry->unlock();
397 cbdataFree(state);
398 return;
399 } else if (EBIT_TEST(state->sentry->flags, ENTRY_ABORTED)) {
400 state->sentry->unlock();
401 cbdataFree(state);
402 return;
403 } else if (state->sentry->checkDeferRead(-1)) {
404 state->sentry->flush();
405 eventAdd("statObjects", statObjects, state, 0.1, 1);
406 return;
407 }
408
409 state->sentry->buffer();
410 size_t statCount = 0;
411 MemBuf mb;
412 mb.init();
413
414 while (statCount++ < static_cast<size_t>(Config.Store.objectsPerBucket) && state->
415 theSearch->next()) {
416 e = state->theSearch->currentItem();
417
418 if (state->filter && 0 == state->filter(e))
419 continue;
420
421 statStoreEntry(&mb, e);
422 }
423
424 if (mb.size)
425 state->sentry->append(mb.buf, mb.size);
426 mb.clean();
427
428 eventAdd("statObjects", statObjects, state, 0.0, 1);
429 }
430
431 static void
432 statObjectsStart(StoreEntry * sentry, STOBJFLT * filter)
433 {
434 StatObjectsState *state = new StatObjectsState;
435 state->sentry = sentry;
436 state->filter = filter;
437
438 sentry->lock();
439 state->theSearch = Store::Root().search(NULL, NULL);
440
441 eventAdd("statObjects", statObjects, state, 0.0, 1);
442 }
443
444 static void
445 stat_objects_get(StoreEntry * sentry)
446 {
447 statObjectsStart(sentry, NULL);
448 }
449
450 static int
451 statObjectsVmFilter(const StoreEntry * e)
452 {
453 return e->mem_obj ? 1 : 0;
454 }
455
456 static void
457 stat_vmobjects_get(StoreEntry * sentry)
458 {
459 statObjectsStart(sentry, statObjectsVmFilter);
460 }
461
462 #if DEBUG_OPENFD
463 static int
464 statObjectsOpenfdFilter(const StoreEntry * e)
465 {
466 if (e->mem_obj == NULL)
467 return 0;
468
469 if (e->mem_obj->swapout.sio == NULL)
470 return 0;
471
472 return 1;
473 }
474
475 static void
476 statOpenfdObj(StoreEntry * sentry)
477 {
478 statObjectsStart(sentry, statObjectsOpenfdFilter);
479 }
480
481 #endif
482
483 #if XMALLOC_STATISTICS
484 static void
485 info_get_mallstat(int size, int number, int oldnum, void *data)
486 {
487 StoreEntry *sentry = (StoreEntry *)data;
488
489 // format: "%12s %15s %6s %12s\n","Alloc Size","Count","Delta","Alloc/sec"
490 if (number > 0)
491 storeAppendPrintf(sentry, "%12d %15d %6d %.1f\n", size, number, number - oldnum, xdiv((number - oldnum), xm_deltat));
492 }
493
494 #endif
495
496 void
497 GetInfo(Mgr::InfoActionData& stats)
498 {
499
500 struct rusage rusage;
501 double cputime;
502 double runtime;
503 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
504
505 struct mstats ms;
506 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
507
508 struct mallinfo mp;
509 #endif
510
511 runtime = tvSubDsec(squid_start, current_time);
512
513 if (runtime == 0.0)
514 runtime = 1.0;
515
516 stats.squid_start = squid_start;
517
518 stats.current_time = current_time;
519
520 stats.client_http_clients = statCounter.client_http.clients;
521
522 stats.client_http_requests = statCounter.client_http.requests;
523
524 stats.icp_pkts_recv = statCounter.icp.pkts_recv;
525
526 stats.icp_pkts_sent = statCounter.icp.pkts_sent;
527
528 stats.icp_replies_queued = statCounter.icp.replies_queued;
529
530 #if USE_HTCP
531
532 stats.htcp_pkts_recv = statCounter.htcp.pkts_recv;
533
534 stats.htcp_pkts_sent = statCounter.htcp.pkts_sent;
535
536 #endif
537
538 stats.request_failure_ratio = request_failure_ratio;
539
540 stats.avg_client_http_requests = statCounter.client_http.requests / (runtime / 60.0);
541
542 stats.avg_icp_messages = (statCounter.icp.pkts_sent + statCounter.icp.pkts_recv) / (runtime / 60.0);
543
544 stats.select_loops = statCounter.select_loops;
545 stats.avg_loop_time = 1000.0 * runtime / statCounter.select_loops;
546
547 stats.request_hit_ratio5 = statRequestHitRatio(5);
548 stats.request_hit_ratio60 = statRequestHitRatio(60);
549
550 stats.byte_hit_ratio5 = statByteHitRatio(5);
551 stats.byte_hit_ratio60 = statByteHitRatio(60);
552
553 stats.request_hit_mem_ratio5 = statRequestHitMemoryRatio(5);
554 stats.request_hit_mem_ratio60 = statRequestHitMemoryRatio(60);
555
556 stats.request_hit_disk_ratio5 = statRequestHitDiskRatio(5);
557 stats.request_hit_disk_ratio60 = statRequestHitDiskRatio(60);
558
559 Store::Root().getStats(stats.store);
560
561 stats.unlink_requests = statCounter.unlink.requests;
562
563 stats.http_requests5 = statPctileSvc(0.5, 5, PCTILE_HTTP);
564 stats.http_requests60 = statPctileSvc(0.5, 60, PCTILE_HTTP);
565
566 stats.cache_misses5 = statPctileSvc(0.5, 5, PCTILE_MISS);
567 stats.cache_misses60 = statPctileSvc(0.5, 60, PCTILE_MISS);
568
569 stats.cache_hits5 = statPctileSvc(0.5, 5, PCTILE_HIT);
570 stats.cache_hits60 = statPctileSvc(0.5, 60, PCTILE_HIT);
571
572 stats.near_hits5 = statPctileSvc(0.5, 5, PCTILE_NH);
573 stats.near_hits60 = statPctileSvc(0.5, 60, PCTILE_NH);
574
575 stats.not_modified_replies5 = statPctileSvc(0.5, 5, PCTILE_NM);
576 stats.not_modified_replies60 = statPctileSvc(0.5, 60, PCTILE_NM);
577
578 stats.dns_lookups5 = statPctileSvc(0.5, 5, PCTILE_DNS);
579 stats.dns_lookups60 = statPctileSvc(0.5, 60, PCTILE_DNS);
580
581 stats.icp_queries5 = statPctileSvc(0.5, 5, PCTILE_ICP_QUERY);
582 stats.icp_queries60 = statPctileSvc(0.5, 60, PCTILE_ICP_QUERY);
583
584 squid_getrusage(&rusage);
585 cputime = rusage_cputime(&rusage);
586
587 stats.up_time = runtime;
588 stats.cpu_time = cputime;
589 stats.cpu_usage = Math::doublePercent(cputime, runtime);
590 stats.cpu_usage5 = statCPUUsage(5);
591 stats.cpu_usage60 = statCPUUsage(60);
592
593 #if HAVE_SBRK
594
595 stats.proc_data_seg = ((char *) sbrk(0) - (char *) sbrk_start);
596
597 #endif
598
599 stats.maxrss = rusage_maxrss(&rusage);
600
601 stats.page_faults = rusage_pagefaults(&rusage);
602
603 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
604
605 ms = mstats();
606
607 stats.ms_bytes_total = ms.bytes_total;
608
609 stats.ms_bytes_free = ms.bytes_free;
610
611 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
612
613 mp = mallinfo();
614
615 stats.mp_arena = mp.arena;
616
617 stats.mp_uordblks = mp.uordblks;
618 stats.mp_ordblks = mp.ordblks;
619
620 stats.mp_usmblks = mp.usmblks;
621 stats.mp_smblks = mp.smblks;
622
623 stats.mp_hblkhd = mp.hblkhd;
624 stats.mp_hblks = mp.hblks;
625
626 stats.mp_fsmblks = mp.fsmblks;
627
628 stats.mp_fordblks = mp.fordblks;
629
630 #if HAVE_STRUCT_MALLINFO_MXFAST
631
632 stats.mp_mxfast = mp.mxfast;
633
634 stats.mp_nlblks = mp.nlblks;
635
636 stats.mp_grain = mp.grain;
637
638 stats.mp_uordbytes = mp.uordbytes;
639
640 stats.mp_allocated = mp.allocated;
641
642 stats.mp_treeoverhead = mp.treeoverhead;
643
644 #endif /* HAVE_STRUCT_MALLINFO_MXFAST */
645 #endif /* HAVE_MALLINFO */
646
647 stats.total_accounted = statMemoryAccounted();
648
649 {
650 MemPoolGlobalStats mp_stats;
651 memPoolGetGlobalStats(&mp_stats);
652 #if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
653
654 stats.mem_pool_allocated = mp_stats.TheMeter->alloc.level;
655 #endif
656
657 stats.gb_saved_count = mp_stats.TheMeter->gb_saved.count;
658 stats.gb_freed_count = mp_stats.TheMeter->gb_freed.count;
659 }
660
661 stats.max_fd = Squid_MaxFD;
662 stats.biggest_fd = Biggest_FD;
663 stats.number_fd = Number_FD;
664 stats.opening_fd = Opening_FD;
665 stats.num_fd_free = fdNFree();
666 stats.reserved_fd = RESERVED_FD;
667 }
668
669 void
670 DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry)
671 {
672 storeAppendPrintf(sentry, "Squid Object Cache: Version %s\n",
673 version_string);
674
675 #if _SQUID_WINDOWS_
676 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
677 storeAppendPrintf(sentry,"\nRunning as %s Windows System Service on %s\n",
678 WIN32_Service_name, WIN32_OS_string);
679 storeAppendPrintf(sentry,"Service command line is: %s\n", WIN32_Service_Command_Line);
680 } else
681 storeAppendPrintf(sentry,"Running on %s\n",WIN32_OS_string);
682 #endif
683
684 storeAppendPrintf(sentry, "Start Time:\t%s\n",
685 mkrfc1123(stats.squid_start.tv_sec));
686
687 storeAppendPrintf(sentry, "Current Time:\t%s\n",
688 mkrfc1123(stats.current_time.tv_sec));
689
690 storeAppendPrintf(sentry, "Connection information for %s:\n",APP_SHORTNAME);
691
692 storeAppendPrintf(sentry, "\tNumber of clients accessing cache:\t%.0f\n",
693 stats.client_http_clients);
694
695 storeAppendPrintf(sentry, "\tNumber of HTTP requests received:\t%.0f\n",
696 stats.client_http_requests);
697
698 storeAppendPrintf(sentry, "\tNumber of ICP messages received:\t%.0f\n",
699 stats.icp_pkts_recv);
700
701 storeAppendPrintf(sentry, "\tNumber of ICP messages sent:\t%.0f\n",
702 stats.icp_pkts_sent);
703
704 storeAppendPrintf(sentry, "\tNumber of queued ICP replies:\t%.0f\n",
705 stats.icp_replies_queued);
706
707 #if USE_HTCP
708
709 storeAppendPrintf(sentry, "\tNumber of HTCP messages received:\t%.0f\n",
710 stats.htcp_pkts_recv);
711
712 storeAppendPrintf(sentry, "\tNumber of HTCP messages sent:\t%.0f\n",
713 stats.htcp_pkts_sent);
714
715 #endif
716
717 double fct = stats.count > 1 ? stats.count : 1.0;
718 storeAppendPrintf(sentry, "\tRequest failure ratio:\t%5.2f\n",
719 stats.request_failure_ratio / fct);
720
721 storeAppendPrintf(sentry, "\tAverage HTTP requests per minute since start:\t%.1f\n",
722 stats.avg_client_http_requests);
723
724 storeAppendPrintf(sentry, "\tAverage ICP messages per minute since start:\t%.1f\n",
725 stats.avg_icp_messages);
726
727 storeAppendPrintf(sentry, "\tSelect loop called: %.0f times, %0.3f ms avg\n",
728 stats.select_loops, stats.avg_loop_time / fct);
729
730 storeAppendPrintf(sentry, "Cache information for %s:\n",APP_SHORTNAME);
731
732 storeAppendPrintf(sentry, "\tHits as %% of all requests:\t5min: %3.1f%%, 60min: %3.1f%%\n",
733 stats.request_hit_ratio5 / fct,
734 stats.request_hit_ratio60 / fct);
735
736 storeAppendPrintf(sentry, "\tHits as %% of bytes sent:\t5min: %3.1f%%, 60min: %3.1f%%\n",
737 stats.byte_hit_ratio5 / fct,
738 stats.byte_hit_ratio60 / fct);
739
740 storeAppendPrintf(sentry, "\tMemory hits as %% of hit requests:\t5min: %3.1f%%, 60min: %3.1f%%\n",
741 stats.request_hit_mem_ratio5 / fct,
742 stats.request_hit_mem_ratio60 / fct);
743
744 storeAppendPrintf(sentry, "\tDisk hits as %% of hit requests:\t5min: %3.1f%%, 60min: %3.1f%%\n",
745 stats.request_hit_disk_ratio5 / fct,
746 stats.request_hit_disk_ratio60 / fct);
747
748 storeAppendPrintf(sentry, "\tStorage Swap size:\t%.0f KB\n",
749 stats.store.swap.size / 1024);
750
751 storeAppendPrintf(sentry, "\tStorage Swap capacity:\t%4.1f%% used, %4.1f%% free\n",
752 Math::doublePercent(stats.store.swap.size, stats.store.swap.capacity),
753 Math::doublePercent(stats.store.swap.available(), stats.store.swap.capacity));
754
755 storeAppendPrintf(sentry, "\tStorage Mem size:\t%.0f KB\n",
756 stats.store.mem.size / 1024);
757
758 storeAppendPrintf(sentry, "\tStorage Mem capacity:\t%4.1f%% used, %4.1f%% free\n",
759 Math::doublePercent(stats.store.mem.size, stats.store.mem.capacity),
760 Math::doublePercent(stats.store.mem.available(), stats.store.mem.capacity));
761
762 storeAppendPrintf(sentry, "\tMean Object Size:\t%0.2f KB\n",
763 stats.store.swap.meanObjectSize() / 1024);
764
765 storeAppendPrintf(sentry, "\tRequests given to unlinkd:\t%.0f\n",
766 stats.unlink_requests);
767
768 storeAppendPrintf(sentry, "Median Service Times (seconds) 5 min 60 min:\n");
769
770 fct = stats.count > 1 ? stats.count * 1000.0 : 1000.0;
771 storeAppendPrintf(sentry, "\tHTTP Requests (All): %8.5f %8.5f\n",
772 stats.http_requests5 / fct,
773 stats.http_requests60 / fct);
774
775 storeAppendPrintf(sentry, "\tCache Misses: %8.5f %8.5f\n",
776 stats.cache_misses5 / fct,
777 stats.cache_misses60 / fct);
778
779 storeAppendPrintf(sentry, "\tCache Hits: %8.5f %8.5f\n",
780 stats.cache_hits5 / fct,
781 stats.cache_hits60 / fct);
782
783 storeAppendPrintf(sentry, "\tNear Hits: %8.5f %8.5f\n",
784 stats.near_hits5 / fct,
785 stats.near_hits60 / fct);
786
787 storeAppendPrintf(sentry, "\tNot-Modified Replies: %8.5f %8.5f\n",
788 stats.not_modified_replies5 / fct,
789 stats.not_modified_replies60 / fct);
790
791 storeAppendPrintf(sentry, "\tDNS Lookups: %8.5f %8.5f\n",
792 stats.dns_lookups5 / fct,
793 stats.dns_lookups60 / fct);
794
795 fct = stats.count > 1 ? stats.count * 1000000.0 : 1000000.0;
796 storeAppendPrintf(sentry, "\tICP Queries: %8.5f %8.5f\n",
797 stats.icp_queries5 / fct,
798 stats.icp_queries60 / fct);
799
800 storeAppendPrintf(sentry, "Resource usage for %s:\n", APP_SHORTNAME);
801
802 storeAppendPrintf(sentry, "\tUP Time:\t%.3f seconds\n", stats.up_time);
803
804 storeAppendPrintf(sentry, "\tCPU Time:\t%.3f seconds\n", stats.cpu_time);
805
806 storeAppendPrintf(sentry, "\tCPU Usage:\t%.2f%%\n",
807 stats.cpu_usage);
808
809 storeAppendPrintf(sentry, "\tCPU Usage, 5 minute avg:\t%.2f%%\n",
810 stats.cpu_usage5);
811
812 storeAppendPrintf(sentry, "\tCPU Usage, 60 minute avg:\t%.2f%%\n",
813 stats.cpu_usage60);
814
815 #if HAVE_SBRK
816
817 storeAppendPrintf(sentry, "\tProcess Data Segment Size via sbrk(): %.0f KB\n",
818 stats.proc_data_seg / 1024);
819
820 #endif
821
822 storeAppendPrintf(sentry, "\tMaximum Resident Size: %.0f KB\n",
823 stats.maxrss);
824
825 storeAppendPrintf(sentry, "\tPage faults with physical i/o: %.0f\n",
826 stats.page_faults);
827
828 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
829
830 storeAppendPrintf(sentry, "Memory usage for %s via mstats():\n",APP_SHORTNAME);
831
832 storeAppendPrintf(sentry, "\tTotal space in arena: %6.0f KB\n",
833 stats.ms_bytes_total / 1024);
834
835 storeAppendPrintf(sentry, "\tTotal free: %6.0f KB %.0f%%\n",
836 stats.ms_bytes_free / 1024,
837 Math::doublePercent(stats.ms_bytes_free, stats.ms_bytes_total));
838
839 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
840
841 storeAppendPrintf(sentry, "Memory usage for %s via mallinfo():\n",APP_SHORTNAME);
842
843 storeAppendPrintf(sentry, "\tTotal space in arena: %6.0f KB\n",
844 stats.mp_arena / 1024);
845
846 storeAppendPrintf(sentry, "\tOrdinary blocks: %6.0f KB %6.0f blks\n",
847 stats.mp_uordblks / 1024, stats.mp_ordblks);
848
849 storeAppendPrintf(sentry, "\tSmall blocks: %6.0f KB %6.0f blks\n",
850 stats.mp_usmblks / 1024, stats.mp_smblks);
851
852 storeAppendPrintf(sentry, "\tHolding blocks: %6.0f KB %6.0f blks\n",
853 stats.mp_hblkhd / 1024, stats.mp_hblks);
854
855 storeAppendPrintf(sentry, "\tFree Small blocks: %6.0f KB\n",
856 stats.mp_fsmblks / 1024);
857
858 storeAppendPrintf(sentry, "\tFree Ordinary blocks: %6.0f KB\n",
859 stats.mp_fordblks / 1024);
860
861 double t = stats.mp_fsmblks + stats.mp_fordblks;
862
863 storeAppendPrintf(sentry, "\tTotal in use: %6.0f KB %.0f%%\n",
864 t / 1024, Math::doublePercent(t, stats.mp_arena + stats.mp_hblkhd));
865
866 t = stats.mp_fsmblks + stats.mp_fordblks;
867
868 storeAppendPrintf(sentry, "\tTotal free: %6.0f KB %.0f%%\n",
869 t / 1024, Math::doublePercent(t, stats.mp_arena + stats.mp_hblkhd));
870
871 t = stats.mp_arena + stats.mp_hblkhd;
872
873 storeAppendPrintf(sentry, "\tTotal size: %6.0f KB\n",
874 t / 1024);
875
876 #if HAVE_STRUCT_MALLINFO_MXFAST
877
878 storeAppendPrintf(sentry, "\tmax size of small blocks:\t%.0f\n", stats.mp_mxfast);
879
880 storeAppendPrintf(sentry, "\tnumber of small blocks in a holding block:\t%.0f\n",
881 stats.mp_nlblks);
882
883 storeAppendPrintf(sentry, "\tsmall block rounding factor:\t%.0f\n", stats.mp_grain);
884
885 storeAppendPrintf(sentry, "\tspace (including overhead) allocated in ord. blks:\t%.0f\n"
886 ,stats.mp_uordbytes);
887
888 storeAppendPrintf(sentry, "\tnumber of ordinary blocks allocated:\t%.0f\n",
889 stats.mp_allocated);
890
891 storeAppendPrintf(sentry, "\tbytes used in maintaining the free tree:\t%.0f\n",
892 stats.mp_treeoverhead);
893
894 #endif /* HAVE_STRUCT_MALLINFO_MXFAST */
895 #endif /* HAVE_MALLINFO */
896
897 storeAppendPrintf(sentry, "Memory accounted for:\n");
898
899 #if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
900
901 storeAppendPrintf(sentry, "\tTotal accounted: %6.0f KB %3.0f%%\n",
902 stats.total_accounted / 1024, Math::doublePercent(stats.total_accounted, t));
903
904 #else
905
906 storeAppendPrintf(sentry, "\tTotal accounted: %6.0f KB\n",
907 stats.total_accounted / 1024);
908
909 #endif
910 {
911 MemPoolGlobalStats mp_stats;
912 memPoolGetGlobalStats(&mp_stats);
913 #if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
914
915 storeAppendPrintf(sentry, "\tmemPool accounted: %6.0f KB %3.0f%%\n",
916 stats.mem_pool_allocated / 1024,
917 Math::doublePercent(stats.mem_pool_allocated, t));
918
919 const double iFree = max(0.0, t - stats.mem_pool_allocated);
920 storeAppendPrintf(sentry, "\tmemPool unaccounted: %6.0f KB %3.0f%%\n",
921 (t - stats.mem_pool_allocated) / 1024,
922 Math::doublePercent(iFree, t));
923 #endif
924
925 storeAppendPrintf(sentry, "\tmemPoolAlloc calls: %9.0f\n",
926 stats.gb_saved_count);
927 storeAppendPrintf(sentry, "\tmemPoolFree calls: %9.0f\n",
928 stats.gb_freed_count);
929 }
930
931 storeAppendPrintf(sentry, "File descriptor usage for %s:\n", APP_SHORTNAME);
932 storeAppendPrintf(sentry, "\tMaximum number of file descriptors: %4.0f\n",
933 stats.max_fd);
934 storeAppendPrintf(sentry, "\tLargest file desc currently in use: %4.0f\n",
935 stats.biggest_fd);
936 storeAppendPrintf(sentry, "\tNumber of file desc currently in use: %4.0f\n",
937 stats.number_fd);
938 storeAppendPrintf(sentry, "\tFiles queued for open: %4.0f\n",
939 stats.opening_fd);
940 storeAppendPrintf(sentry, "\tAvailable number of file descriptors: %4.0f\n",
941 stats.num_fd_free);
942 storeAppendPrintf(sentry, "\tReserved number of file descriptors: %4.0f\n",
943 stats.reserved_fd);
944 storeAppendPrintf(sentry, "\tStore Disk files open: %4.0f\n",
945 stats.store.swap.open_disk_fd);
946
947 storeAppendPrintf(sentry, "Internal Data Structures:\n");
948 storeAppendPrintf(sentry, "\t%6.0f StoreEntries\n",
949 stats.store.store_entry_count);
950 storeAppendPrintf(sentry, "\t%6.0f StoreEntries with MemObjects\n",
951 stats.store.mem_object_count);
952 storeAppendPrintf(sentry, "\t%6.0f Hot Object Cache Items\n",
953 stats.store.mem.count);
954 storeAppendPrintf(sentry, "\t%6.0f on-disk objects\n",
955 stats.store.swap.count);
956 }
957
958 void
959 DumpMallocStatistics(StoreEntry* sentry)
960 {
961 #if XMALLOC_STATISTICS
962
963 xm_deltat = current_dtime - xm_time;
964 xm_time = current_dtime;
965 storeAppendPrintf(sentry, "\nMemory allocation statistics\n");
966 storeAppendPrintf(sentry, "%12s %15s %6s %12s\n","Alloc Size","Count","Delta","Alloc/sec");
967 malloc_statistics(info_get_mallstat, sentry);
968 #endif
969 }
970
971 void
972 GetServiceTimesStats(Mgr::ServiceTimesActionData& stats)
973 {
974 for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
975 double p = (i + 1) * 5 / 100.0;
976 stats.http_requests5[i] = statPctileSvc(p, 5, PCTILE_HTTP);
977 stats.http_requests60[i] = statPctileSvc(p, 60, PCTILE_HTTP);
978
979 stats.cache_misses5[i] = statPctileSvc(p, 5, PCTILE_MISS);
980 stats.cache_misses60[i] = statPctileSvc(p, 60, PCTILE_MISS);
981
982 stats.cache_hits5[i] = statPctileSvc(p, 5, PCTILE_HIT);
983 stats.cache_hits60[i] = statPctileSvc(p, 60, PCTILE_HIT);
984
985 stats.near_hits5[i] = statPctileSvc(p, 5, PCTILE_NH);
986 stats.near_hits60[i] = statPctileSvc(p, 60, PCTILE_NH);
987
988 stats.not_modified_replies5[i] = statPctileSvc(p, 5, PCTILE_NM);
989 stats.not_modified_replies60[i] = statPctileSvc(p, 60, PCTILE_NM);
990
991 stats.dns_lookups5[i] = statPctileSvc(p, 5, PCTILE_DNS);
992 stats.dns_lookups60[i] = statPctileSvc(p, 60, PCTILE_DNS);
993
994 stats.icp_queries5[i] = statPctileSvc(p, 5, PCTILE_ICP_QUERY);
995 stats.icp_queries60[i] = statPctileSvc(p, 60, PCTILE_ICP_QUERY);
996 }
997 }
998
999 void
1000 DumpServiceTimesStats(Mgr::ServiceTimesActionData& stats, StoreEntry* sentry)
1001 {
1002 storeAppendPrintf(sentry, "Service Time Percentiles 5 min 60 min:\n");
1003 double fct = stats.count > 1 ? stats.count * 1000.0 : 1000.0;
1004 for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
1005 storeAppendPrintf(sentry, "\tHTTP Requests (All): %2d%% %8.5f %8.5f\n",
1006 (i + 1) * 5,
1007 stats.http_requests5[i] / fct,
1008 stats.http_requests60[i] / fct);
1009 }
1010 for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
1011 storeAppendPrintf(sentry, "\tCache Misses: %2d%% %8.5f %8.5f\n",
1012 (i + 1) * 5,
1013 stats.cache_misses5[i] / fct,
1014 stats.cache_misses60[i] / fct);
1015 }
1016 for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
1017 storeAppendPrintf(sentry, "\tCache Hits: %2d%% %8.5f %8.5f\n",
1018 (i + 1) * 5,
1019 stats.cache_hits5[i] / fct,
1020 stats.cache_hits60[i] / fct);
1021 }
1022 for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
1023 storeAppendPrintf(sentry, "\tNear Hits: %2d%% %8.5f %8.5f\n",
1024 (i + 1) * 5,
1025 stats.near_hits5[i] / fct,
1026 stats.near_hits60[i] / fct);
1027 }
1028 for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
1029 storeAppendPrintf(sentry, "\tNot-Modified Replies: %2d%% %8.5f %8.5f\n",
1030 (i + 1) * 5,
1031 stats.not_modified_replies5[i] / fct,
1032 stats.not_modified_replies60[i] / fct);
1033 }
1034 for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
1035 storeAppendPrintf(sentry, "\tDNS Lookups: %2d%% %8.5f %8.5f\n",
1036 (i + 1) * 5,
1037 stats.dns_lookups5[i] / fct,
1038 stats.dns_lookups60[i] / fct);
1039 }
1040 fct = stats.count > 1 ? stats.count * 1000000.0 : 1000000.0;
1041 for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
1042 storeAppendPrintf(sentry, "\tICP Queries: %2d%% %8.5f %8.5f\n",
1043 (i + 1) * 5,
1044 stats.icp_queries5[i] / fct,
1045 stats.icp_queries60[i] / fct);
1046 }
1047 }
1048
1049 static void
1050 statAvgDump(StoreEntry * sentry, int minutes, int hours)
1051 {
1052 Mgr::IntervalActionData stats;
1053 GetAvgStat(stats, minutes, hours);
1054 DumpAvgStat(stats, sentry);
1055 }
1056
1057 #define XAVG(X) (dt ? (double) (f->X - l->X) / dt : 0.0)
1058 void
1059 GetAvgStat(Mgr::IntervalActionData& stats, int minutes, int hours)
1060 {
1061 StatCounters *f;
1062 StatCounters *l;
1063 double dt;
1064 double ct;
1065 assert(N_COUNT_HIST > 1);
1066 assert(minutes > 0 || hours > 0);
1067 f = &CountHist[0];
1068 l = f;
1069
1070 if (minutes > 0 && hours == 0) {
1071 /* checking minute readings ... */
1072
1073 if (minutes > N_COUNT_HIST - 1)
1074 minutes = N_COUNT_HIST - 1;
1075
1076 l = &CountHist[minutes];
1077 } else if (minutes == 0 && hours > 0) {
1078 /* checking hour readings ... */
1079
1080 if (hours > N_COUNT_HOUR_HIST - 1)
1081 hours = N_COUNT_HOUR_HIST - 1;
1082
1083 l = &CountHourHist[hours];
1084 } else {
1085 debugs(18, DBG_IMPORTANT, "statAvgDump: Invalid args, minutes=" << minutes << ", hours=" << hours);
1086 return;
1087 }
1088
1089 dt = tvSubDsec(l->timestamp, f->timestamp);
1090 ct = f->cputime - l->cputime;
1091
1092 stats.sample_start_time = l->timestamp;
1093 stats.sample_end_time = f->timestamp;
1094
1095 stats.client_http_requests = XAVG(client_http.requests);
1096 stats.client_http_hits = XAVG(client_http.hits);
1097 stats.client_http_errors = XAVG(client_http.errors);
1098 stats.client_http_kbytes_in = XAVG(client_http.kbytes_in.kb);
1099 stats.client_http_kbytes_out = XAVG(client_http.kbytes_out.kb);
1100
1101 stats.client_http_all_median_svc_time = statHistDeltaMedian(l->client_http.allSvcTime,
1102 f->client_http.allSvcTime) / 1000.0;
1103 stats.client_http_miss_median_svc_time = statHistDeltaMedian(l->client_http.missSvcTime,
1104 f->client_http.missSvcTime) / 1000.0;
1105 stats.client_http_nm_median_svc_time = statHistDeltaMedian(l->client_http.nearMissSvcTime,
1106 f->client_http.nearMissSvcTime) / 1000.0;
1107 stats.client_http_nh_median_svc_time = statHistDeltaMedian(l->client_http.nearHitSvcTime,
1108 f->client_http.nearHitSvcTime) / 1000.0;
1109 stats.client_http_hit_median_svc_time = statHistDeltaMedian(l->client_http.hitSvcTime,
1110 f->client_http.hitSvcTime) / 1000.0;
1111
1112 stats.server_all_requests = XAVG(server.all.requests);
1113 stats.server_all_errors = XAVG(server.all.errors);
1114 stats.server_all_kbytes_in = XAVG(server.all.kbytes_in.kb);
1115 stats.server_all_kbytes_out = XAVG(server.all.kbytes_out.kb);
1116
1117 stats.server_http_requests = XAVG(server.http.requests);
1118 stats.server_http_errors = XAVG(server.http.errors);
1119 stats.server_http_kbytes_in = XAVG(server.http.kbytes_in.kb);
1120 stats.server_http_kbytes_out = XAVG(server.http.kbytes_out.kb);
1121
1122 stats.server_ftp_requests = XAVG(server.ftp.requests);
1123 stats.server_ftp_errors = XAVG(server.ftp.errors);
1124 stats.server_ftp_kbytes_in = XAVG(server.ftp.kbytes_in.kb);
1125 stats.server_ftp_kbytes_out = XAVG(server.ftp.kbytes_out.kb);
1126
1127 stats.server_other_requests = XAVG(server.other.requests);
1128 stats.server_other_errors = XAVG(server.other.errors);
1129 stats.server_other_kbytes_in = XAVG(server.other.kbytes_in.kb);
1130 stats.server_other_kbytes_out = XAVG(server.other.kbytes_out.kb);
1131
1132 stats.icp_pkts_sent = XAVG(icp.pkts_sent);
1133 stats.icp_pkts_recv = XAVG(icp.pkts_recv);
1134 stats.icp_queries_sent = XAVG(icp.queries_sent);
1135 stats.icp_replies_sent = XAVG(icp.replies_sent);
1136 stats.icp_queries_recv = XAVG(icp.queries_recv);
1137 stats.icp_replies_recv = XAVG(icp.replies_recv);
1138 stats.icp_replies_queued = XAVG(icp.replies_queued);
1139 stats.icp_query_timeouts = XAVG(icp.query_timeouts);
1140 stats.icp_kbytes_sent = XAVG(icp.kbytes_sent.kb);
1141 stats.icp_kbytes_recv = XAVG(icp.kbytes_recv.kb);
1142 stats.icp_q_kbytes_sent = XAVG(icp.q_kbytes_sent.kb);
1143 stats.icp_r_kbytes_sent = XAVG(icp.r_kbytes_sent.kb);
1144 stats.icp_q_kbytes_recv = XAVG(icp.q_kbytes_recv.kb);
1145 stats.icp_r_kbytes_recv = XAVG(icp.r_kbytes_recv.kb);
1146
1147 stats.icp_query_median_svc_time = statHistDeltaMedian(l->icp.querySvcTime,
1148 f->icp.querySvcTime) / 1000000.0;
1149 stats.icp_reply_median_svc_time = statHistDeltaMedian(l->icp.replySvcTime,
1150 f->icp.replySvcTime) / 1000000.0;
1151 stats.dns_median_svc_time = statHistDeltaMedian(l->dns.svcTime,
1152 f->dns.svcTime) / 1000.0;
1153
1154 stats.unlink_requests = XAVG(unlink.requests);
1155 stats.page_faults = XAVG(page_faults);
1156 stats.select_loops = XAVG(select_loops);
1157 stats.select_fds = XAVG(select_fds);
1158 stats.average_select_fd_period = f->select_fds > l->select_fds ?
1159 (f->select_time - l->select_time) / (f->select_fds - l->select_fds) : 0.0;
1160
1161 stats.median_select_fds = statHistDeltaMedian(l->select_fds_hist, f->select_fds_hist);
1162 stats.swap_outs = XAVG(swap.outs);
1163 stats.swap_ins = XAVG(swap.ins);
1164 stats.swap_files_cleaned = XAVG(swap.files_cleaned);
1165 stats.aborted_requests = XAVG(aborted_requests);
1166
1167 stats.syscalls_disk_opens = XAVG(syscalls.disk.opens);
1168 stats.syscalls_disk_closes = XAVG(syscalls.disk.closes);
1169 stats.syscalls_disk_reads = XAVG(syscalls.disk.reads);
1170 stats.syscalls_disk_writes = XAVG(syscalls.disk.writes);
1171 stats.syscalls_disk_seeks = XAVG(syscalls.disk.seeks);
1172 stats.syscalls_disk_unlinks = XAVG(syscalls.disk.unlinks);
1173 stats.syscalls_sock_accepts = XAVG(syscalls.sock.accepts);
1174 stats.syscalls_sock_sockets = XAVG(syscalls.sock.sockets);
1175 stats.syscalls_sock_connects = XAVG(syscalls.sock.connects);
1176 stats.syscalls_sock_binds = XAVG(syscalls.sock.binds);
1177 stats.syscalls_sock_closes = XAVG(syscalls.sock.closes);
1178 stats.syscalls_sock_reads = XAVG(syscalls.sock.reads);
1179 stats.syscalls_sock_writes = XAVG(syscalls.sock.writes);
1180 stats.syscalls_sock_recvfroms = XAVG(syscalls.sock.recvfroms);
1181 stats.syscalls_sock_sendtos = XAVG(syscalls.sock.sendtos);
1182 stats.syscalls_selects = XAVG(syscalls.selects);
1183
1184 stats.cpu_time = ct;
1185 stats.wall_time = dt;
1186 }
1187
1188 void
1189 DumpAvgStat(Mgr::IntervalActionData& stats, StoreEntry* sentry)
1190 {
1191 storeAppendPrintf(sentry, "sample_start_time = %d.%d (%s)\n",
1192 (int)stats.sample_start_time.tv_sec,
1193 (int)stats.sample_start_time.tv_usec,
1194 mkrfc1123(stats.sample_start_time.tv_sec));
1195 storeAppendPrintf(sentry, "sample_end_time = %d.%d (%s)\n",
1196 (int)stats.sample_end_time.tv_sec,
1197 (int)stats.sample_end_time.tv_usec,
1198 mkrfc1123(stats.sample_end_time.tv_sec));
1199
1200 storeAppendPrintf(sentry, "client_http.requests = %f/sec\n",
1201 stats.client_http_requests);
1202 storeAppendPrintf(sentry, "client_http.hits = %f/sec\n",
1203 stats.client_http_hits);
1204 storeAppendPrintf(sentry, "client_http.errors = %f/sec\n",
1205 stats.client_http_errors);
1206 storeAppendPrintf(sentry, "client_http.kbytes_in = %f/sec\n",
1207 stats.client_http_kbytes_in);
1208 storeAppendPrintf(sentry, "client_http.kbytes_out = %f/sec\n",
1209 stats.client_http_kbytes_out);
1210
1211 double fct = stats.count > 1 ? stats.count : 1.0;
1212 storeAppendPrintf(sentry, "client_http.all_median_svc_time = %f seconds\n",
1213 stats.client_http_all_median_svc_time / fct);
1214 storeAppendPrintf(sentry, "client_http.miss_median_svc_time = %f seconds\n",
1215 stats.client_http_miss_median_svc_time / fct);
1216 storeAppendPrintf(sentry, "client_http.nm_median_svc_time = %f seconds\n",
1217 stats.client_http_nm_median_svc_time / fct);
1218 storeAppendPrintf(sentry, "client_http.nh_median_svc_time = %f seconds\n",
1219 stats.client_http_nh_median_svc_time / fct);
1220 storeAppendPrintf(sentry, "client_http.hit_median_svc_time = %f seconds\n",
1221 stats.client_http_hit_median_svc_time / fct);
1222
1223 storeAppendPrintf(sentry, "server.all.requests = %f/sec\n",
1224 stats.server_all_requests);
1225 storeAppendPrintf(sentry, "server.all.errors = %f/sec\n",
1226 stats.server_all_errors);
1227 storeAppendPrintf(sentry, "server.all.kbytes_in = %f/sec\n",
1228 stats.server_all_kbytes_in);
1229 storeAppendPrintf(sentry, "server.all.kbytes_out = %f/sec\n",
1230 stats.server_all_kbytes_out);
1231
1232 storeAppendPrintf(sentry, "server.http.requests = %f/sec\n",
1233 stats.server_http_requests);
1234 storeAppendPrintf(sentry, "server.http.errors = %f/sec\n",
1235 stats.server_http_errors);
1236 storeAppendPrintf(sentry, "server.http.kbytes_in = %f/sec\n",
1237 stats.server_http_kbytes_in);
1238 storeAppendPrintf(sentry, "server.http.kbytes_out = %f/sec\n",
1239 stats.server_http_kbytes_out);
1240
1241 storeAppendPrintf(sentry, "server.ftp.requests = %f/sec\n",
1242 stats.server_ftp_requests);
1243 storeAppendPrintf(sentry, "server.ftp.errors = %f/sec\n",
1244 stats.server_ftp_errors);
1245 storeAppendPrintf(sentry, "server.ftp.kbytes_in = %f/sec\n",
1246 stats.server_ftp_kbytes_in);
1247 storeAppendPrintf(sentry, "server.ftp.kbytes_out = %f/sec\n",
1248 stats.server_ftp_kbytes_out);
1249
1250 storeAppendPrintf(sentry, "server.other.requests = %f/sec\n",
1251 stats.server_other_requests);
1252 storeAppendPrintf(sentry, "server.other.errors = %f/sec\n",
1253 stats.server_other_errors);
1254 storeAppendPrintf(sentry, "server.other.kbytes_in = %f/sec\n",
1255 stats.server_other_kbytes_in);
1256 storeAppendPrintf(sentry, "server.other.kbytes_out = %f/sec\n",
1257 stats.server_other_kbytes_out);
1258
1259 storeAppendPrintf(sentry, "icp.pkts_sent = %f/sec\n",
1260 stats.icp_pkts_sent);
1261 storeAppendPrintf(sentry, "icp.pkts_recv = %f/sec\n",
1262 stats.icp_pkts_recv);
1263 storeAppendPrintf(sentry, "icp.queries_sent = %f/sec\n",
1264 stats.icp_queries_sent);
1265 storeAppendPrintf(sentry, "icp.replies_sent = %f/sec\n",
1266 stats.icp_replies_sent);
1267 storeAppendPrintf(sentry, "icp.queries_recv = %f/sec\n",
1268 stats.icp_queries_recv);
1269 storeAppendPrintf(sentry, "icp.replies_recv = %f/sec\n",
1270 stats.icp_replies_recv);
1271 storeAppendPrintf(sentry, "icp.replies_queued = %f/sec\n",
1272 stats.icp_replies_queued);
1273 storeAppendPrintf(sentry, "icp.query_timeouts = %f/sec\n",
1274 stats.icp_query_timeouts);
1275 storeAppendPrintf(sentry, "icp.kbytes_sent = %f/sec\n",
1276 stats.icp_kbytes_sent);
1277 storeAppendPrintf(sentry, "icp.kbytes_recv = %f/sec\n",
1278 stats.icp_kbytes_recv);
1279 storeAppendPrintf(sentry, "icp.q_kbytes_sent = %f/sec\n",
1280 stats.icp_q_kbytes_sent);
1281 storeAppendPrintf(sentry, "icp.r_kbytes_sent = %f/sec\n",
1282 stats.icp_r_kbytes_sent);
1283 storeAppendPrintf(sentry, "icp.q_kbytes_recv = %f/sec\n",
1284 stats.icp_q_kbytes_recv);
1285 storeAppendPrintf(sentry, "icp.r_kbytes_recv = %f/sec\n",
1286 stats.icp_r_kbytes_recv);
1287 storeAppendPrintf(sentry, "icp.query_median_svc_time = %f seconds\n",
1288 stats.icp_query_median_svc_time / fct);
1289 storeAppendPrintf(sentry, "icp.reply_median_svc_time = %f seconds\n",
1290 stats.icp_reply_median_svc_time / fct);
1291 storeAppendPrintf(sentry, "dns.median_svc_time = %f seconds\n",
1292 stats.dns_median_svc_time / fct);
1293 storeAppendPrintf(sentry, "unlink.requests = %f/sec\n",
1294 stats.unlink_requests);
1295 storeAppendPrintf(sentry, "page_faults = %f/sec\n",
1296 stats.page_faults);
1297 storeAppendPrintf(sentry, "select_loops = %f/sec\n",
1298 stats.select_loops);
1299 storeAppendPrintf(sentry, "select_fds = %f/sec\n",
1300 stats.select_fds);
1301 storeAppendPrintf(sentry, "average_select_fd_period = %f/fd\n",
1302 stats.average_select_fd_period / fct);
1303 storeAppendPrintf(sentry, "median_select_fds = %f\n",
1304 stats.median_select_fds / fct);
1305 storeAppendPrintf(sentry, "swap.outs = %f/sec\n",
1306 stats.swap_outs);
1307 storeAppendPrintf(sentry, "swap.ins = %f/sec\n",
1308 stats.swap_ins);
1309 storeAppendPrintf(sentry, "swap.files_cleaned = %f/sec\n",
1310 stats.swap_files_cleaned);
1311 storeAppendPrintf(sentry, "aborted_requests = %f/sec\n",
1312 stats.aborted_requests);
1313
1314 #if USE_POLL
1315 storeAppendPrintf(sentry, "syscalls.polls = %f/sec\n", stats.syscalls_selects);
1316 #elif defined(USE_SELECT) || defined(USE_SELECT_WIN32)
1317 storeAppendPrintf(sentry, "syscalls.selects = %f/sec\n", stats.syscalls_selects);
1318 #endif
1319
1320 storeAppendPrintf(sentry, "syscalls.disk.opens = %f/sec\n", stats.syscalls_disk_opens);
1321 storeAppendPrintf(sentry, "syscalls.disk.closes = %f/sec\n", stats.syscalls_disk_closes);
1322 storeAppendPrintf(sentry, "syscalls.disk.reads = %f/sec\n", stats.syscalls_disk_reads);
1323 storeAppendPrintf(sentry, "syscalls.disk.writes = %f/sec\n", stats.syscalls_disk_writes);
1324 storeAppendPrintf(sentry, "syscalls.disk.seeks = %f/sec\n", stats.syscalls_disk_seeks);
1325 storeAppendPrintf(sentry, "syscalls.disk.unlinks = %f/sec\n", stats.syscalls_disk_unlinks);
1326 storeAppendPrintf(sentry, "syscalls.sock.accepts = %f/sec\n", stats.syscalls_sock_accepts);
1327 storeAppendPrintf(sentry, "syscalls.sock.sockets = %f/sec\n", stats.syscalls_sock_sockets);
1328 storeAppendPrintf(sentry, "syscalls.sock.connects = %f/sec\n", stats.syscalls_sock_connects);
1329 storeAppendPrintf(sentry, "syscalls.sock.binds = %f/sec\n", stats.syscalls_sock_binds);
1330 storeAppendPrintf(sentry, "syscalls.sock.closes = %f/sec\n", stats.syscalls_sock_closes);
1331 storeAppendPrintf(sentry, "syscalls.sock.reads = %f/sec\n", stats.syscalls_sock_reads);
1332 storeAppendPrintf(sentry, "syscalls.sock.writes = %f/sec\n", stats.syscalls_sock_writes);
1333 storeAppendPrintf(sentry, "syscalls.sock.recvfroms = %f/sec\n", stats.syscalls_sock_recvfroms);
1334 storeAppendPrintf(sentry, "syscalls.sock.sendtos = %f/sec\n", stats.syscalls_sock_sendtos);
1335
1336 storeAppendPrintf(sentry, "cpu_time = %f seconds\n", stats.cpu_time);
1337 storeAppendPrintf(sentry, "wall_time = %f seconds\n", stats.wall_time);
1338 storeAppendPrintf(sentry, "cpu_usage = %f%%\n", Math::doublePercent(stats.cpu_time, stats.wall_time));
1339 }
1340
1341 static void
1342 statRegisterWithCacheManager(void)
1343 {
1344 Mgr::RegisterAction("info", "General Runtime Information",
1345 &Mgr::InfoAction::Create, 0, 1);
1346 Mgr::RegisterAction("service_times", "Service Times (Percentiles)",
1347 &Mgr::ServiceTimesAction::Create, 0, 1);
1348 Mgr::RegisterAction("filedescriptors", "Process Filedescriptor Allocation",
1349 fde::DumpStats, 0, 1);
1350 Mgr::RegisterAction("objects", "All Cache Objects", stat_objects_get, 0, 0);
1351 Mgr::RegisterAction("vm_objects", "In-Memory and In-Transit Objects",
1352 stat_vmobjects_get, 0, 0);
1353 Mgr::RegisterAction("io", "Server-side network read() size histograms",
1354 &Mgr::IoAction::Create, 0, 1);
1355 Mgr::RegisterAction("counters", "Traffic and Resource Counters",
1356 &Mgr::CountersAction::Create, 0, 1);
1357 Mgr::RegisterAction("peer_select", "Peer Selection Algorithms",
1358 statPeerSelect, 0, 1);
1359 Mgr::RegisterAction("digest_stats", "Cache Digest and ICP blob",
1360 statDigestBlob, 0, 1);
1361 Mgr::RegisterAction("5min", "5 Minute Average of Counters",
1362 &Mgr::IntervalAction::Create5min, 0, 1);
1363 Mgr::RegisterAction("60min", "60 Minute Average of Counters",
1364 &Mgr::IntervalAction::Create60min, 0, 1);
1365 Mgr::RegisterAction("utilization", "Cache Utilization",
1366 statUtilization, 0, 1);
1367 Mgr::RegisterAction("histograms", "Full Histogram Counts",
1368 statCountersHistograms, 0, 1);
1369 Mgr::RegisterAction("active_requests",
1370 "Client-side Active Requests",
1371 statClientRequests, 0, 1);
1372 #if USE_AUTH
1373 Mgr::RegisterAction("username_cache",
1374 "Active Cached Usernames",
1375 Auth::User::UsernameCacheStats, 0, 1);
1376 #endif
1377 #if DEBUG_OPENFD
1378 Mgr::RegisterAction("openfd_objects", "Objects with Swapout files open",
1379 statOpenfdObj, 0, 0);
1380 #endif
1381 #if STAT_GRAPHS
1382 Mgr::RegisterAction("graph_variables", "Display cache metrics graphically",
1383 statGraphDump, 0, 1);
1384 #endif
1385 }
1386
1387 void
1388 statInit(void)
1389 {
1390 int i;
1391 debugs(18, 5, "statInit: Initializing...");
1392
1393 for (i = 0; i < N_COUNT_HIST; ++i)
1394 statCountersInit(&CountHist[i]);
1395
1396 for (i = 0; i < N_COUNT_HOUR_HIST; ++i)
1397 statCountersInit(&CountHourHist[i]);
1398
1399 statCountersInit(&statCounter);
1400
1401 eventAdd("statAvgTick", statAvgTick, NULL, (double) COUNT_INTERVAL, 1);
1402
1403 ClientActiveRequests.head = NULL;
1404
1405 ClientActiveRequests.tail = NULL;
1406
1407 statRegisterWithCacheManager();
1408 }
1409
1410 static void
1411 statAvgTick(void *notused)
1412 {
1413 StatCounters *t = &CountHist[0];
1414 StatCounters *p = &CountHist[1];
1415 StatCounters *c = &statCounter;
1416
1417 struct rusage rusage;
1418 eventAdd("statAvgTick", statAvgTick, NULL, (double) COUNT_INTERVAL, 1);
1419 squid_getrusage(&rusage);
1420 c->page_faults = rusage_pagefaults(&rusage);
1421 c->cputime = rusage_cputime(&rusage);
1422 c->timestamp = current_time;
1423 /* even if NCountHist is small, we already Init()ed the tail */
1424 statCountersClean(CountHist + N_COUNT_HIST - 1);
1425 memmove(p, t, (N_COUNT_HIST - 1) * sizeof(StatCounters));
1426 statCountersCopy(t, c);
1427 ++NCountHist;
1428
1429 if ((NCountHist % COUNT_INTERVAL) == 0) {
1430 /* we have an hours worth of readings. store previous hour */
1431 StatCounters *t2 = &CountHourHist[0];
1432 StatCounters *p2 = &CountHourHist[1];
1433 StatCounters *c2 = &CountHist[N_COUNT_HIST - 1];
1434 statCountersClean(CountHourHist + N_COUNT_HOUR_HIST - 1);
1435 memmove(p2, t2, (N_COUNT_HOUR_HIST - 1) * sizeof(StatCounters));
1436 statCountersCopy(t2, c2);
1437 ++NCountHourHist;
1438 }
1439
1440 if (Config.warnings.high_rptm > 0) {
1441 int i = (int) statPctileSvc(0.5, 20, PCTILE_HTTP);
1442
1443 if (Config.warnings.high_rptm < i)
1444 debugs(18, DBG_CRITICAL, "WARNING: Median response time is " << i << " milliseconds");
1445 }
1446
1447 if (Config.warnings.high_pf) {
1448 int i = (CountHist[0].page_faults - CountHist[1].page_faults);
1449 double dt = tvSubDsec(CountHist[0].timestamp, CountHist[1].timestamp);
1450
1451 if (i > 0 && dt > 0.0) {
1452 i /= (int) dt;
1453
1454 if (Config.warnings.high_pf < i)
1455 debugs(18, DBG_CRITICAL, "WARNING: Page faults occuring at " << i << "/sec");
1456 }
1457 }
1458
1459 if (Config.warnings.high_memory) {
1460 size_t i = 0;
1461 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
1462
1463 struct mstats ms = mstats();
1464 i = ms.bytes_total;
1465 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
1466
1467 struct mallinfo mp = mallinfo();
1468 i = mp.arena;
1469 #elif HAVE_SBRK
1470
1471 i = (size_t) ((char *) sbrk(0) - (char *) sbrk_start);
1472 #endif
1473
1474 if (Config.warnings.high_memory < i)
1475 debugs(18, DBG_CRITICAL, "WARNING: Memory usage at " << ((unsigned long int)(i >> 20)) << " MB");
1476 }
1477 }
1478
1479 static void
1480 statCountersInit(StatCounters * C)
1481 {
1482 assert(C);
1483 memset(C, 0, sizeof(*C));
1484 C->timestamp = current_time;
1485 statCountersInitSpecial(C);
1486 }
1487
1488 /* add special cases here as they arrive */
1489 static void
1490 statCountersInitSpecial(StatCounters * C)
1491 {
1492 /*
1493 * HTTP svc_time hist is kept in milli-seconds; max of 3 hours.
1494 */
1495 C->client_http.allSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
1496 C->client_http.missSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
1497 C->client_http.nearMissSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
1498 C->client_http.nearHitSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
1499 C->client_http.hitSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
1500 /*
1501 * ICP svc_time hist is kept in micro-seconds; max of 1 minute.
1502 */
1503 C->icp.querySvcTime.logInit(300, 0.0, 1000000.0 * 60.0);
1504 C->icp.replySvcTime.logInit(300, 0.0, 1000000.0 * 60.0);
1505 /*
1506 * DNS svc_time hist is kept in milli-seconds; max of 10 minutes.
1507 */
1508 C->dns.svcTime.logInit(300, 0.0, 60000.0 * 10.0);
1509 /*
1510 * Cache Digest Stuff
1511 */
1512 C->cd.on_xition_count.enumInit(CacheDigestHashFuncCount);
1513 C->comm_udp_incoming.enumInit(INCOMING_UDP_MAX);
1514 C->comm_dns_incoming.enumInit(INCOMING_DNS_MAX);
1515 C->comm_tcp_incoming.enumInit(INCOMING_TCP_MAX);
1516 C->select_fds_hist.enumInit(256); /* was SQUID_MAXFD, but it is way too much. It is OK to crop this statistics */
1517 }
1518
1519 /* add special cases here as they arrive */
1520 static void
1521 statCountersClean(StatCounters * C)
1522 {
1523 assert(C);
1524 C->client_http.allSvcTime.clear();
1525 C->client_http.missSvcTime.clear();
1526 C->client_http.nearMissSvcTime.clear();
1527 C->client_http.nearHitSvcTime.clear();
1528 C->client_http.hitSvcTime.clear();
1529 C->icp.querySvcTime.clear();
1530 C->icp.replySvcTime.clear();
1531 C->dns.svcTime.clear();
1532 C->cd.on_xition_count.clear();
1533 C->comm_udp_incoming.clear();
1534 C->comm_dns_incoming.clear();
1535 C->comm_tcp_incoming.clear();
1536 C->select_fds_hist.clear();
1537 }
1538
1539 /* add special cases here as they arrive */
1540 static void
1541 statCountersCopy(StatCounters * dest, const StatCounters * orig)
1542 {
1543 assert(dest && orig);
1544 /* this should take care of all the fields, but "special" ones */
1545 memcpy(dest, orig, sizeof(*dest));
1546 /* prepare space where to copy special entries */
1547 statCountersInitSpecial(dest);
1548 /* now handle special cases */
1549 /* note: we assert that histogram capacities do not change */
1550 dest->client_http.allSvcTime=orig->client_http.allSvcTime;
1551 dest->client_http.missSvcTime=orig->client_http.missSvcTime;
1552 dest->client_http.nearMissSvcTime=orig->client_http.nearMissSvcTime;
1553 dest->client_http.nearHitSvcTime=orig->client_http.nearHitSvcTime;
1554
1555 dest->client_http.hitSvcTime=orig->client_http.hitSvcTime;
1556 dest->icp.querySvcTime=orig->icp.querySvcTime;
1557 dest->icp.replySvcTime=orig->icp.replySvcTime;
1558 dest->dns.svcTime=orig->dns.svcTime;
1559 dest->cd.on_xition_count=orig->cd.on_xition_count;
1560 dest->comm_udp_incoming=orig->comm_udp_incoming;
1561 dest->comm_dns_incoming=orig->comm_dns_incoming;
1562 dest->comm_tcp_incoming=orig->comm_tcp_incoming;
1563 dest->select_fds_hist=orig->select_fds_hist;
1564 }
1565
1566 static void
1567 statCountersHistograms(StoreEntry * sentry)
1568 {
1569 storeAppendPrintf(sentry, "client_http.allSvcTime histogram:\n");
1570 statCounter.client_http.allSvcTime.dump(sentry, NULL);
1571 storeAppendPrintf(sentry, "client_http.missSvcTime histogram:\n");
1572 statCounter.client_http.missSvcTime.dump(sentry, NULL);
1573 storeAppendPrintf(sentry, "client_http.nearMissSvcTime histogram:\n");
1574 statCounter.client_http.nearMissSvcTime.dump(sentry, NULL);
1575 storeAppendPrintf(sentry, "client_http.nearHitSvcTime histogram:\n");
1576 statCounter.client_http.nearHitSvcTime.dump(sentry, NULL);
1577 storeAppendPrintf(sentry, "client_http.hitSvcTime histogram:\n");
1578 statCounter.client_http.hitSvcTime.dump(sentry, NULL);
1579 storeAppendPrintf(sentry, "icp.querySvcTime histogram:\n");
1580 statCounter.icp.querySvcTime.dump(sentry, NULL);
1581 storeAppendPrintf(sentry, "icp.replySvcTime histogram:\n");
1582 statCounter.icp.replySvcTime.dump(sentry, NULL);
1583 storeAppendPrintf(sentry, "dns.svc_time histogram:\n");
1584 statCounter.dns.svcTime.dump(sentry, NULL);
1585 storeAppendPrintf(sentry, "select_fds_hist histogram:\n");
1586 statCounter.select_fds_hist.dump(sentry, NULL);
1587 }
1588
1589 static void
1590 statCountersDump(StoreEntry * sentry)
1591 {
1592 Mgr::CountersActionData stats;
1593 GetCountersStats(stats);
1594 DumpCountersStats(stats, sentry);
1595 }
1596
1597 void
1598 GetCountersStats(Mgr::CountersActionData& stats)
1599 {
1600 StatCounters *f = &statCounter;
1601
1602 struct rusage rusage;
1603 squid_getrusage(&rusage);
1604 f->page_faults = rusage_pagefaults(&rusage);
1605 f->cputime = rusage_cputime(&rusage);
1606
1607 stats.sample_time = f->timestamp;
1608 stats.client_http_requests = f->client_http.requests;
1609 stats.client_http_hits = f->client_http.hits;
1610 stats.client_http_errors = f->client_http.errors;
1611 stats.client_http_kbytes_in = f->client_http.kbytes_in.kb;
1612 stats.client_http_kbytes_out = f->client_http.kbytes_out.kb;
1613 stats.client_http_hit_kbytes_out = f->client_http.hit_kbytes_out.kb;
1614
1615 stats.server_all_requests = f->server.all.requests;
1616 stats.server_all_errors = f->server.all.errors;
1617 stats.server_all_kbytes_in = f->server.all.kbytes_in.kb;
1618 stats.server_all_kbytes_out = f->server.all.kbytes_out.kb;
1619
1620 stats.server_http_requests = f->server.http.requests;
1621 stats.server_http_errors = f->server.http.errors;
1622 stats.server_http_kbytes_in = f->server.http.kbytes_in.kb;
1623 stats.server_http_kbytes_out = f->server.http.kbytes_out.kb;
1624
1625 stats.server_ftp_requests = f->server.ftp.requests;
1626 stats.server_ftp_errors = f->server.ftp.errors;
1627 stats.server_ftp_kbytes_in = f->server.ftp.kbytes_in.kb;
1628 stats.server_ftp_kbytes_out = f->server.ftp.kbytes_out.kb;
1629
1630 stats.server_other_requests = f->server.other.requests;
1631 stats.server_other_errors = f->server.other.errors;
1632 stats.server_other_kbytes_in = f->server.other.kbytes_in.kb;
1633 stats.server_other_kbytes_out = f->server.other.kbytes_out.kb;
1634
1635 stats.icp_pkts_sent = f->icp.pkts_sent;
1636 stats.icp_pkts_recv = f->icp.pkts_recv;
1637 stats.icp_queries_sent = f->icp.queries_sent;
1638 stats.icp_replies_sent = f->icp.replies_sent;
1639 stats.icp_queries_recv = f->icp.queries_recv;
1640 stats.icp_replies_recv = f->icp.replies_recv;
1641 stats.icp_query_timeouts = f->icp.query_timeouts;
1642 stats.icp_replies_queued = f->icp.replies_queued;
1643 stats.icp_kbytes_sent = f->icp.kbytes_sent.kb;
1644 stats.icp_kbytes_recv = f->icp.kbytes_recv.kb;
1645 stats.icp_q_kbytes_sent = f->icp.q_kbytes_sent.kb;
1646 stats.icp_r_kbytes_sent = f->icp.r_kbytes_sent.kb;
1647 stats.icp_q_kbytes_recv = f->icp.q_kbytes_recv.kb;
1648 stats.icp_r_kbytes_recv = f->icp.r_kbytes_recv.kb;
1649
1650 #if USE_CACHE_DIGESTS
1651
1652 stats.icp_times_used = f->icp.times_used;
1653 stats.cd_times_used = f->cd.times_used;
1654 stats.cd_msgs_sent = f->cd.msgs_sent;
1655 stats.cd_msgs_recv = f->cd.msgs_recv;
1656 stats.cd_memory = f->cd.memory.kb;
1657 stats.cd_local_memory = store_digest ? store_digest->mask_size / 1024 : 0;
1658 stats.cd_kbytes_sent = f->cd.kbytes_sent.kb;
1659 stats.cd_kbytes_recv = f->cd.kbytes_recv.kb;
1660 #endif
1661
1662 stats.unlink_requests = f->unlink.requests;
1663 stats.page_faults = f->page_faults;
1664 stats.select_loops = f->select_loops;
1665 stats.cpu_time = f->cputime;
1666 stats.wall_time = tvSubDsec(f->timestamp, current_time);
1667 stats.swap_outs = f->swap.outs;
1668 stats.swap_ins = f->swap.ins;
1669 stats.swap_files_cleaned = f->swap.files_cleaned;
1670 stats.aborted_requests = f->aborted_requests;
1671 }
1672
1673 void
1674 DumpCountersStats(Mgr::CountersActionData& stats, StoreEntry* sentry)
1675 {
1676 storeAppendPrintf(sentry, "sample_time = %d.%d (%s)\n",
1677 (int) stats.sample_time.tv_sec,
1678 (int) stats.sample_time.tv_usec,
1679 mkrfc1123(stats.sample_time.tv_sec));
1680 storeAppendPrintf(sentry, "client_http.requests = %.0f\n",
1681 stats.client_http_requests);
1682 storeAppendPrintf(sentry, "client_http.hits = %.0f\n",
1683 stats.client_http_hits);
1684 storeAppendPrintf(sentry, "client_http.errors = %.0f\n",
1685 stats.client_http_errors);
1686 storeAppendPrintf(sentry, "client_http.kbytes_in = %.0f\n",
1687 stats.client_http_kbytes_in);
1688 storeAppendPrintf(sentry, "client_http.kbytes_out = %.0f\n",
1689 stats.client_http_kbytes_out);
1690 storeAppendPrintf(sentry, "client_http.hit_kbytes_out = %.0f\n",
1691 stats.client_http_hit_kbytes_out);
1692
1693 storeAppendPrintf(sentry, "server.all.requests = %.0f\n",
1694 stats.server_all_requests);
1695 storeAppendPrintf(sentry, "server.all.errors = %.0f\n",
1696 stats.server_all_errors);
1697 storeAppendPrintf(sentry, "server.all.kbytes_in = %.0f\n",
1698 stats.server_all_kbytes_in);
1699 storeAppendPrintf(sentry, "server.all.kbytes_out = %.0f\n",
1700 stats.server_all_kbytes_out);
1701
1702 storeAppendPrintf(sentry, "server.http.requests = %.0f\n",
1703 stats.server_http_requests);
1704 storeAppendPrintf(sentry, "server.http.errors = %.0f\n",
1705 stats.server_http_errors);
1706 storeAppendPrintf(sentry, "server.http.kbytes_in = %.0f\n",
1707 stats.server_http_kbytes_in);
1708 storeAppendPrintf(sentry, "server.http.kbytes_out = %.0f\n",
1709 stats.server_http_kbytes_out);
1710
1711 storeAppendPrintf(sentry, "server.ftp.requests = %.0f\n",
1712 stats.server_ftp_requests);
1713 storeAppendPrintf(sentry, "server.ftp.errors = %.0f\n",
1714 stats.server_ftp_errors);
1715 storeAppendPrintf(sentry, "server.ftp.kbytes_in = %.0f\n",
1716 stats.server_ftp_kbytes_in);
1717 storeAppendPrintf(sentry, "server.ftp.kbytes_out = %.0f\n",
1718 stats.server_ftp_kbytes_out);
1719
1720 storeAppendPrintf(sentry, "server.other.requests = %.0f\n",
1721 stats.server_other_requests);
1722 storeAppendPrintf(sentry, "server.other.errors = %.0f\n",
1723 stats.server_other_errors);
1724 storeAppendPrintf(sentry, "server.other.kbytes_in = %.0f\n",
1725 stats.server_other_kbytes_in);
1726 storeAppendPrintf(sentry, "server.other.kbytes_out = %.0f\n",
1727 stats.server_other_kbytes_out);
1728
1729 storeAppendPrintf(sentry, "icp.pkts_sent = %.0f\n",
1730 stats.icp_pkts_sent);
1731 storeAppendPrintf(sentry, "icp.pkts_recv = %.0f\n",
1732 stats.icp_pkts_recv);
1733 storeAppendPrintf(sentry, "icp.queries_sent = %.0f\n",
1734 stats.icp_queries_sent);
1735 storeAppendPrintf(sentry, "icp.replies_sent = %.0f\n",
1736 stats.icp_replies_sent);
1737 storeAppendPrintf(sentry, "icp.queries_recv = %.0f\n",
1738 stats.icp_queries_recv);
1739 storeAppendPrintf(sentry, "icp.replies_recv = %.0f\n",
1740 stats.icp_replies_recv);
1741 storeAppendPrintf(sentry, "icp.query_timeouts = %.0f\n",
1742 stats.icp_query_timeouts);
1743 storeAppendPrintf(sentry, "icp.replies_queued = %.0f\n",
1744 stats.icp_replies_queued);
1745 storeAppendPrintf(sentry, "icp.kbytes_sent = %.0f\n",
1746 stats.icp_kbytes_sent);
1747 storeAppendPrintf(sentry, "icp.kbytes_recv = %.0f\n",
1748 stats.icp_kbytes_recv);
1749 storeAppendPrintf(sentry, "icp.q_kbytes_sent = %.0f\n",
1750 stats.icp_q_kbytes_sent);
1751 storeAppendPrintf(sentry, "icp.r_kbytes_sent = %.0f\n",
1752 stats.icp_r_kbytes_sent);
1753 storeAppendPrintf(sentry, "icp.q_kbytes_recv = %.0f\n",
1754 stats.icp_q_kbytes_recv);
1755 storeAppendPrintf(sentry, "icp.r_kbytes_recv = %.0f\n",
1756 stats.icp_r_kbytes_recv);
1757
1758 #if USE_CACHE_DIGESTS
1759
1760 storeAppendPrintf(sentry, "icp.times_used = %.0f\n",
1761 stats.icp_times_used);
1762 storeAppendPrintf(sentry, "cd.times_used = %.0f\n",
1763 stats.cd_times_used);
1764 storeAppendPrintf(sentry, "cd.msgs_sent = %.0f\n",
1765 stats.cd_msgs_sent);
1766 storeAppendPrintf(sentry, "cd.msgs_recv = %.0f\n",
1767 stats.cd_msgs_recv);
1768 storeAppendPrintf(sentry, "cd.memory = %.0f\n",
1769 stats.cd_memory);
1770 storeAppendPrintf(sentry, "cd.local_memory = %.0f\n",
1771 stats.cd_local_memory);
1772 storeAppendPrintf(sentry, "cd.kbytes_sent = %.0f\n",
1773 stats.cd_kbytes_sent);
1774 storeAppendPrintf(sentry, "cd.kbytes_recv = %.0f\n",
1775 stats.cd_kbytes_recv);
1776 #endif
1777
1778 storeAppendPrintf(sentry, "unlink.requests = %.0f\n",
1779 stats.unlink_requests);
1780 storeAppendPrintf(sentry, "page_faults = %.0f\n",
1781 stats.page_faults);
1782 storeAppendPrintf(sentry, "select_loops = %.0f\n",
1783 stats.select_loops);
1784 storeAppendPrintf(sentry, "cpu_time = %f\n",
1785 stats.cpu_time);
1786 storeAppendPrintf(sentry, "wall_time = %f\n",
1787 stats.wall_time);
1788 storeAppendPrintf(sentry, "swap.outs = %.0f\n",
1789 stats.swap_outs);
1790 storeAppendPrintf(sentry, "swap.ins = %.0f\n",
1791 stats.swap_ins);
1792 storeAppendPrintf(sentry, "swap.files_cleaned = %.0f\n",
1793 stats.swap_files_cleaned);
1794 storeAppendPrintf(sentry, "aborted_requests = %.0f\n",
1795 stats.aborted_requests);
1796 }
1797
1798 void
1799 statFreeMemory(void)
1800 {
1801 int i;
1802
1803 for (i = 0; i < N_COUNT_HIST; ++i)
1804 statCountersClean(&CountHist[i]);
1805
1806 for (i = 0; i < N_COUNT_HOUR_HIST; ++i)
1807 statCountersClean(&CountHourHist[i]);
1808 }
1809
1810 static void
1811 statPeerSelect(StoreEntry * sentry)
1812 {
1813 #if USE_CACHE_DIGESTS
1814 StatCounters *f = &statCounter;
1815 CachePeer *peer;
1816 const int tot_used = f->cd.times_used + f->icp.times_used;
1817
1818 /* totals */
1819 cacheDigestGuessStatsReport(&f->cd.guess, sentry, "all peers");
1820 /* per-peer */
1821 storeAppendPrintf(sentry, "\nPer-peer statistics:\n");
1822
1823 for (peer = getFirstPeer(); peer; peer = getNextPeer(peer)) {
1824 if (peer->digest)
1825 peerDigestStatsReport(peer->digest, sentry);
1826 else
1827 storeAppendPrintf(sentry, "\nNo peer digest from %s\n", peer->host);
1828
1829 storeAppendPrintf(sentry, "\n");
1830 }
1831
1832 storeAppendPrintf(sentry, "\nAlgorithm usage:\n");
1833 storeAppendPrintf(sentry, "Cache Digest: %7d (%3d%%)\n",
1834 f->cd.times_used, xpercentInt(f->cd.times_used, tot_used));
1835 storeAppendPrintf(sentry, "Icp: %7d (%3d%%)\n",
1836 f->icp.times_used, xpercentInt(f->icp.times_used, tot_used));
1837 storeAppendPrintf(sentry, "Total: %7d (%3d%%)\n",
1838 tot_used, xpercentInt(tot_used, tot_used));
1839 #else
1840
1841 storeAppendPrintf(sentry, "peer digests are disabled; no stats is available.\n");
1842 #endif
1843 }
1844
1845 static void
1846 statDigestBlob(StoreEntry * sentry)
1847 {
1848 storeAppendPrintf(sentry, "\nCounters:\n");
1849 statCountersDump(sentry);
1850 storeAppendPrintf(sentry, "\n5 Min Averages:\n");
1851 statAvgDump(sentry, 5, 0);
1852 storeAppendPrintf(sentry, "\nHistograms:\n");
1853 statCountersHistograms(sentry);
1854 storeAppendPrintf(sentry, "\nPeer Digests:\n");
1855 statPeerSelect(sentry);
1856 storeAppendPrintf(sentry, "\nLocal Digest:\n");
1857 storeDigestReport(sentry);
1858 }
1859
1860 static double
1861 statPctileSvc(double pctile, int interval, int which)
1862 {
1863 StatCounters *f;
1864 StatCounters *l;
1865 double x;
1866 assert(interval > 0);
1867
1868 if (interval > N_COUNT_HIST - 1)
1869 interval = N_COUNT_HIST - 1;
1870
1871 f = &CountHist[0];
1872
1873 l = &CountHist[interval];
1874
1875 assert(f);
1876
1877 assert(l);
1878
1879 switch (which) {
1880
1881 case PCTILE_HTTP:
1882 x = statHistDeltaPctile(l->client_http.allSvcTime,f->client_http.allSvcTime, pctile);
1883 break;
1884
1885 case PCTILE_HIT:
1886 x = statHistDeltaPctile(l->client_http.hitSvcTime,f->client_http.hitSvcTime, pctile);
1887 break;
1888
1889 case PCTILE_MISS:
1890 x = statHistDeltaPctile(l->client_http.missSvcTime,f->client_http.missSvcTime, pctile);
1891 break;
1892
1893 case PCTILE_NM:
1894 x = statHistDeltaPctile(l->client_http.nearMissSvcTime,f->client_http.nearMissSvcTime, pctile);
1895 break;
1896
1897 case PCTILE_NH:
1898 x = statHistDeltaPctile(l->client_http.nearHitSvcTime,f->client_http.nearHitSvcTime, pctile);
1899 break;
1900
1901 case PCTILE_ICP_QUERY:
1902 x = statHistDeltaPctile(l->icp.querySvcTime,f->icp.querySvcTime, pctile);
1903 break;
1904
1905 case PCTILE_DNS:
1906 x = statHistDeltaPctile(l->dns.svcTime,f->dns.svcTime, pctile);
1907 break;
1908
1909 default:
1910 debugs(49, 5, "statPctileSvc: unknown type.");
1911 x = 0;
1912 }
1913
1914 return x;
1915 }
1916
1917 StatCounters *
1918 snmpStatGet(int minutes)
1919 {
1920 return &CountHist[minutes];
1921 }
1922
1923 int
1924 stat5minClientRequests(void)
1925 {
1926 assert(N_COUNT_HIST > 5);
1927 return statCounter.client_http.requests - CountHist[5].client_http.requests;
1928 }
1929
1930 static double
1931 statCPUUsage(int minutes)
1932 {
1933 assert(minutes < N_COUNT_HIST);
1934 return Math::doublePercent(CountHist[0].cputime - CountHist[minutes].cputime,
1935 tvSubDsec(CountHist[minutes].timestamp, CountHist[0].timestamp));
1936 }
1937
1938 extern double
1939 statRequestHitRatio(int minutes)
1940 {
1941 assert(minutes < N_COUNT_HIST);
1942 return Math::doublePercent(CountHist[0].client_http.hits -
1943 CountHist[minutes].client_http.hits,
1944 CountHist[0].client_http.requests -
1945 CountHist[minutes].client_http.requests);
1946 }
1947
1948 extern double
1949 statRequestHitMemoryRatio(int minutes)
1950 {
1951 assert(minutes < N_COUNT_HIST);
1952 return Math::doublePercent(CountHist[0].client_http.mem_hits -
1953 CountHist[minutes].client_http.mem_hits,
1954 CountHist[0].client_http.hits -
1955 CountHist[minutes].client_http.hits);
1956 }
1957
1958 extern double
1959 statRequestHitDiskRatio(int minutes)
1960 {
1961 assert(minutes < N_COUNT_HIST);
1962 return Math::doublePercent(CountHist[0].client_http.disk_hits -
1963 CountHist[minutes].client_http.disk_hits,
1964 CountHist[0].client_http.hits -
1965 CountHist[minutes].client_http.hits);
1966 }
1967
1968 extern double
1969 statByteHitRatio(int minutes)
1970 {
1971 size_t s;
1972 size_t c;
1973 #if USE_CACHE_DIGESTS
1974
1975 size_t cd;
1976 #endif
1977 /* size_t might be unsigned */
1978 assert(minutes < N_COUNT_HIST);
1979 c = CountHist[0].client_http.kbytes_out.kb - CountHist[minutes].client_http.kbytes_out.kb;
1980 s = CountHist[0].server.all.kbytes_in.kb - CountHist[minutes].server.all.kbytes_in.kb;
1981 #if USE_CACHE_DIGESTS
1982 /*
1983 * This ugly hack is here to prevent the user from seeing a
1984 * negative byte hit ratio. When we fetch a cache digest from
1985 * a neighbor, it gets treated like a cache miss because the
1986 * object is consumed internally. Thus, we subtract cache
1987 * digest bytes out before calculating the byte hit ratio.
1988 */
1989 cd = CountHist[0].cd.kbytes_recv.kb - CountHist[minutes].cd.kbytes_recv.kb;
1990
1991 if (s < cd)
1992 debugs(18, DBG_IMPORTANT, "STRANGE: srv_kbytes=" << s << ", cd_kbytes=" << cd);
1993
1994 s -= cd;
1995
1996 #endif
1997
1998 if (c > s)
1999 return Math::doublePercent(c - s, c);
2000 else
2001 return (-1.0 * Math::doublePercent(s - c, c));
2002 }
2003
2004 static void
2005 statClientRequests(StoreEntry * s)
2006 {
2007 dlink_node *i;
2008 ClientHttpRequest *http;
2009 StoreEntry *e;
2010 char buf[MAX_IPSTRLEN];
2011
2012 for (i = ClientActiveRequests.head; i; i = i->next) {
2013 const char *p = NULL;
2014 http = static_cast<ClientHttpRequest *>(i->data);
2015 assert(http);
2016 ConnStateData * conn = http->getConn();
2017 storeAppendPrintf(s, "Connection: %p\n", conn);
2018
2019 if (conn != NULL) {
2020 const int fd = conn->clientConnection->fd;
2021 storeAppendPrintf(s, "\tFD %d, read %" PRId64 ", wrote %" PRId64 "\n", fd,
2022 fd_table[fd].bytes_read, fd_table[fd].bytes_written);
2023 storeAppendPrintf(s, "\tFD desc: %s\n", fd_table[fd].desc);
2024 storeAppendPrintf(s, "\tin: buf %p, offset %ld, size %ld\n",
2025 conn->in.buf, (long int) conn->in.notYetUsed, (long int) conn->in.allocatedSize);
2026 storeAppendPrintf(s, "\tremote: %s\n",
2027 conn->clientConnection->remote.ToURL(buf,MAX_IPSTRLEN));
2028 storeAppendPrintf(s, "\tlocal: %s\n",
2029 conn->clientConnection->local.ToURL(buf,MAX_IPSTRLEN));
2030 storeAppendPrintf(s, "\tnrequests: %d\n",
2031 conn->nrequests);
2032 }
2033
2034 storeAppendPrintf(s, "uri %s\n", http->uri);
2035 storeAppendPrintf(s, "logType %s\n", Format::log_tags[http->logType]);
2036 storeAppendPrintf(s, "out.offset %ld, out.size %lu\n",
2037 (long int) http->out.offset, (unsigned long int) http->out.size);
2038 storeAppendPrintf(s, "req_sz %ld\n", (long int) http->req_sz);
2039 e = http->storeEntry();
2040 storeAppendPrintf(s, "entry %p/%s\n", e, e ? e->getMD5Text() : "N/A");
2041 #if 0
2042 /* Not a member anymore */
2043 e = http->old_entry;
2044 storeAppendPrintf(s, "old_entry %p/%s\n", e, e ? e->getMD5Text() : "N/A");
2045 #endif
2046
2047 storeAppendPrintf(s, "start %ld.%06d (%f seconds ago)\n",
2048 (long int) http->start_time.tv_sec,
2049 (int) http->start_time.tv_usec,
2050 tvSubDsec(http->start_time, current_time));
2051 #if USE_AUTH
2052 if (http->request->auth_user_request != NULL)
2053 p = http->request->auth_user_request->username();
2054 else
2055 #endif
2056 if (http->request->extacl_user.defined()) {
2057 p = http->request->extacl_user.termedBuf();
2058 }
2059
2060 if (!p && conn != NULL && conn->clientConnection->rfc931[0])
2061 p = conn->clientConnection->rfc931;
2062
2063 #if USE_SSL
2064
2065 if (!p && conn != NULL && Comm::IsConnOpen(conn->clientConnection))
2066 p = sslGetUserEmail(fd_table[conn->clientConnection->fd].ssl);
2067
2068 #endif
2069
2070 if (!p)
2071 p = dash_str;
2072
2073 storeAppendPrintf(s, "username %s\n", p);
2074
2075 #if USE_DELAY_POOLS
2076 storeAppendPrintf(s, "delay_pool %d\n", DelayId::DelayClient(http).pool());
2077 #endif
2078
2079 storeAppendPrintf(s, "\n");
2080 }
2081 }
2082
2083 #if STAT_GRAPHS
2084 /*
2085 * urgh, i don't like these, but they do cut the amount of code down immensely
2086 */
2087
2088 #define GRAPH_PER_MIN(Y) \
2089 for (i=0;i<(N_COUNT_HIST-2);++i) { \
2090 dt = tvSubDsec(CountHist[i+1].timestamp, CountHist[i].timestamp); \
2091 if (dt <= 0.0) \
2092 break; \
2093 storeAppendPrintf(e, "%lu,%0.2f:", \
2094 CountHist[i].timestamp.tv_sec, \
2095 ((CountHist[i].Y - CountHist[i+1].Y) / dt)); \
2096 }
2097
2098 #define GRAPH_PER_HOUR(Y) \
2099 for (i=0;i<(N_COUNT_HOUR_HIST-2);++i) { \
2100 dt = tvSubDsec(CountHourHist[i+1].timestamp, CountHourHist[i].timestamp); \
2101 if (dt <= 0.0) \
2102 break; \
2103 storeAppendPrintf(e, "%lu,%0.2f:", \
2104 CountHourHist[i].timestamp.tv_sec, \
2105 ((CountHourHist[i].Y - CountHourHist[i+1].Y) / dt)); \
2106 }
2107
2108 #define GRAPH_TITLE(X,Y) storeAppendPrintf(e,"%s\t%s\t",X,Y);
2109 #define GRAPH_END storeAppendPrintf(e,"\n");
2110
2111 #define GENGRAPH(X,Y,Z) \
2112 GRAPH_TITLE(Y,Z) \
2113 GRAPH_PER_MIN(X) \
2114 GRAPH_PER_HOUR(X) \
2115 GRAPH_END
2116
2117 static void
2118 statGraphDump(StoreEntry * e)
2119 {
2120 int i;
2121 double dt;
2122
2123 GENGRAPH(client_http.requests, "client_http.requests", "Client HTTP requests/sec");
2124 GENGRAPH(client_http.hits, "client_http.hits", "Client HTTP hits/sec");
2125 GENGRAPH(client_http.errors, "client_http.errors", "Client HTTP errors/sec");
2126 GENGRAPH(client_http.kbytes_in.kb, "client_http.kbytes_in", "Client HTTP kbytes_in/sec");
2127 GENGRAPH(client_http.kbytes_out.kb, "client_http.kbytes_out", "Client HTTP kbytes_out/sec");
2128
2129 /* XXX todo: http median service times */
2130
2131 GENGRAPH(server.all.requests, "server.all.requests", "Server requests/sec");
2132 GENGRAPH(server.all.errors, "server.all.errors", "Server errors/sec");
2133 GENGRAPH(server.all.kbytes_in.kb, "server.all.kbytes_in", "Server total kbytes_in/sec");
2134 GENGRAPH(server.all.kbytes_out.kb, "server.all.kbytes_out", "Server total kbytes_out/sec");
2135
2136 GENGRAPH(server.http.requests, "server.http.requests", "Server HTTP requests/sec");
2137 GENGRAPH(server.http.errors, "server.http.errors", "Server HTTP errors/sec");
2138 GENGRAPH(server.http.kbytes_in.kb, "server.http.kbytes_in", "Server HTTP kbytes_in/sec");
2139 GENGRAPH(server.http.kbytes_out.kb, "server.http.kbytes_out", "Server HTTP kbytes_out/sec");
2140
2141 GENGRAPH(server.ftp.requests, "server.ftp.requests", "Server FTP requests/sec");
2142 GENGRAPH(server.ftp.errors, "server.ftp.errors", "Server FTP errors/sec");
2143 GENGRAPH(server.ftp.kbytes_in.kb, "server.ftp.kbytes_in", "Server FTP kbytes_in/sec");
2144 GENGRAPH(server.ftp.kbytes_out.kb, "server.ftp.kbytes_out", "Server FTP kbytes_out/sec");
2145
2146 GENGRAPH(server.other.requests, "server.other.requests", "Server other requests/sec");
2147 GENGRAPH(server.other.errors, "server.other.errors", "Server other errors/sec");
2148 GENGRAPH(server.other.kbytes_in.kb, "server.other.kbytes_in", "Server other kbytes_in/sec");
2149 GENGRAPH(server.other.kbytes_out.kb, "server.other.kbytes_out", "Server other kbytes_out/sec");
2150
2151 GENGRAPH(icp.pkts_sent, "icp.pkts_sent", "ICP packets sent/sec");
2152 GENGRAPH(icp.pkts_recv, "icp.pkts_recv", "ICP packets received/sec");
2153 GENGRAPH(icp.kbytes_sent.kb, "icp.kbytes_sent", "ICP kbytes_sent/sec");
2154 GENGRAPH(icp.kbytes_recv.kb, "icp.kbytes_recv", "ICP kbytes_received/sec");
2155
2156 /* XXX todo: icp median service times */
2157 /* XXX todo: dns median service times */
2158
2159 GENGRAPH(unlink.requests, "unlink.requests", "Cache File unlink requests/sec");
2160 GENGRAPH(page_faults, "page_faults", "System Page Faults/sec");
2161 GENGRAPH(select_loops, "select_loops", "System Select Loop calls/sec");
2162 GENGRAPH(cputime, "cputime", "CPU utilisation");
2163 }
2164
2165 #endif /* STAT_GRAPHS */
2166
2167 int
2168 statMemoryAccounted(void)
2169 {
2170 return memPoolsTotalAllocated();
2171 }