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