stat.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:50k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: stat.c,v 1.311.2.2 1999/02/13 07:45:28 wessels Exp $
  3.  *
  4.  * DEBUG: section 18    Cache Manager Statistics
  5.  * AUTHOR: Harvest Derived
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  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. #include "squid.h"
  35. #define DEBUG_OPENFD 1
  36. typedef int STOBJFLT(const StoreEntry *);
  37. typedef struct {
  38.     StoreEntry *sentry;
  39.     int bucket;
  40.     STOBJFLT *filter;
  41. } StatObjectsState;
  42. /* LOCALS */
  43. static const char *describeStatuses(const StoreEntry *);
  44. static const char *describeTimestamps(const StoreEntry *);
  45. static void statAvgTick(void *notused);
  46. static void statAvgDump(StoreEntry *, int minutes, int hours);
  47. #if STAT_GRAPHS
  48. static void statGraphDump(StoreEntry *);
  49. #endif
  50. static void statCountersInit(StatCounters *);
  51. static void statCountersInitSpecial(StatCounters *);
  52. static void statCountersClean(StatCounters *);
  53. static void statCountersCopy(StatCounters * dest, const StatCounters * orig);
  54. static double statMedianSvc(int, int);
  55. static void statStoreEntry(StoreEntry * s, StoreEntry * e);
  56. static double statCPUUsage(int minutes);
  57. static OBJH stat_io_get;
  58. static OBJH stat_objects_get;
  59. static OBJH stat_vmobjects_get;
  60. #if DEBUG_OPENFD
  61. static OBJH statOpenfdObj;
  62. #endif
  63. static EVH statObjects;
  64. static OBJH info_get;
  65. static OBJH statFiledescriptors;
  66. static OBJH statCountersDump;
  67. static OBJH statPeerSelect;
  68. static OBJH statDigestBlob;
  69. static OBJH statAvg5min;
  70. static OBJH statAvg60min;
  71. static OBJH statUtilization;
  72. static OBJH statCountersHistograms;
  73. static OBJH statClientRequests;
  74. #ifdef XMALLOC_STATISTICS
  75. static void info_get_mallstat(int, int, StoreEntry *);
  76. #endif
  77. StatCounters CountHist[N_COUNT_HIST];
  78. static int NCountHist = 0;
  79. static StatCounters CountHourHist[N_COUNT_HOUR_HIST];
  80. static int NCountHourHist = 0;
  81. static void
  82. statUtilization(StoreEntry * e)
  83. {
  84.     storeAppendPrintf(e, "Cache Utilisation:n");
  85.     storeAppendPrintf(e, "n");
  86.     storeAppendPrintf(e, "Last 5 minutes:n");
  87.     if (NCountHist >= 5)
  88. statAvgDump(e, 5, 0);
  89.     else
  90. storeAppendPrintf(e, "(no values recorded yet)n");
  91.     storeAppendPrintf(e, "n");
  92.     storeAppendPrintf(e, "Last 15 minutes:n");
  93.     if (NCountHist >= 15)
  94. statAvgDump(e, 15, 0);
  95.     else
  96. storeAppendPrintf(e, "(no values recorded yet)n");
  97.     storeAppendPrintf(e, "n");
  98.     storeAppendPrintf(e, "Last hour:n");
  99.     if (NCountHist >= 60)
  100. statAvgDump(e, 60, 0);
  101.     else
  102. storeAppendPrintf(e, "(no values recorded yet)n");
  103.     storeAppendPrintf(e, "n");
  104.     storeAppendPrintf(e, "Last 8 hours:n");
  105.     if (NCountHourHist >= 8)
  106. statAvgDump(e, 0, 8);
  107.     else
  108. storeAppendPrintf(e, "(no values recorded yet)n");
  109.     storeAppendPrintf(e, "n");
  110.     storeAppendPrintf(e, "Last day:n");
  111.     if (NCountHourHist >= 24)
  112. statAvgDump(e, 0, 24);
  113.     else
  114. storeAppendPrintf(e, "(no values recorded yet)n");
  115.     storeAppendPrintf(e, "n");
  116.     storeAppendPrintf(e, "Last 3 days:n");
  117.     if (NCountHourHist >= 72)
  118. statAvgDump(e, 0, 72);
  119.     else
  120. storeAppendPrintf(e, "(no values recorded yet)n");
  121.     storeAppendPrintf(e, "n");
  122.     storeAppendPrintf(e, "Totals since cache startup:n");
  123.     statCountersDump(e);
  124. }
  125. static void
  126. stat_io_get(StoreEntry * sentry)
  127. {
  128.     int i;
  129.     storeAppendPrintf(sentry, "HTTP I/On");
  130.     storeAppendPrintf(sentry, "number of reads: %dn", IOStats.Http.reads);
  131.     storeAppendPrintf(sentry, "Read Histogram:n");
  132.     for (i = 0; i < 16; i++) {
  133. storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%n",
  134.     i ? (1 << (i - 1)) + 1 : 1,
  135.     1 << i,
  136.     IOStats.Http.read_hist[i],
  137.     percent(IOStats.Http.read_hist[i], IOStats.Http.reads));
  138.     }
  139.     storeAppendPrintf(sentry, "n");
  140.     storeAppendPrintf(sentry, "FTP I/On");
  141.     storeAppendPrintf(sentry, "number of reads: %dn", IOStats.Ftp.reads);
  142.     storeAppendPrintf(sentry, "Read Histogram:n");
  143.     for (i = 0; i < 16; i++) {
  144. storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%n",
  145.     i ? (1 << (i - 1)) + 1 : 1,
  146.     1 << i,
  147.     IOStats.Ftp.read_hist[i],
  148.     percent(IOStats.Ftp.read_hist[i], IOStats.Ftp.reads));
  149.     }
  150.     storeAppendPrintf(sentry, "n");
  151.     storeAppendPrintf(sentry, "Gopher I/On");
  152.     storeAppendPrintf(sentry, "number of reads: %dn", IOStats.Gopher.reads);
  153.     storeAppendPrintf(sentry, "Read Histogram:n");
  154.     for (i = 0; i < 16; i++) {
  155. storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%n",
  156.     i ? (1 << (i - 1)) + 1 : 1,
  157.     1 << i,
  158.     IOStats.Gopher.read_hist[i],
  159.     percent(IOStats.Gopher.read_hist[i], IOStats.Gopher.reads));
  160.     }
  161.     storeAppendPrintf(sentry, "n");
  162.     storeAppendPrintf(sentry, "WAIS I/On");
  163.     storeAppendPrintf(sentry, "number of reads: %dn", IOStats.Wais.reads);
  164.     storeAppendPrintf(sentry, "Read Histogram:n");
  165.     for (i = 0; i < 16; i++) {
  166. storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%n",
  167.     i ? (1 << (i - 1)) + 1 : 1,
  168.     1 << i,
  169.     IOStats.Wais.read_hist[i],
  170.     percent(IOStats.Wais.read_hist[i], IOStats.Wais.reads));
  171.     }
  172. }
  173. static const char *
  174. describeStatuses(const StoreEntry * entry)
  175. {
  176.     LOCAL_ARRAY(char, buf, 256);
  177.     snprintf(buf, 256, "%-13s %-13s %-12s %-12s",
  178. storeStatusStr[entry->store_status],
  179. memStatusStr[entry->mem_status],
  180. swapStatusStr[entry->swap_status],
  181. pingStatusStr[entry->ping_status]);
  182.     return buf;
  183. }
  184. const char *
  185. storeEntryFlags(const StoreEntry * entry)
  186. {
  187.     LOCAL_ARRAY(char, buf, 256);
  188.     int flags = (int) entry->flags;
  189.     char *t;
  190.     buf[0] = '';
  191.     if (EBIT_TEST(flags, ENTRY_SPECIAL))
  192. strcat(buf, "SPECIAL,");
  193.     if (EBIT_TEST(flags, ENTRY_REVALIDATE))
  194. strcat(buf, "REVALIDATE,");
  195.     if (EBIT_TEST(flags, DELAY_SENDING))
  196. strcat(buf, "DELAY_SENDING,");
  197.     if (EBIT_TEST(flags, RELEASE_REQUEST))
  198. strcat(buf, "RELEASE_REQUEST,");
  199.     if (EBIT_TEST(flags, REFRESH_REQUEST))
  200. strcat(buf, "REFRESH_REQUEST,");
  201.     if (EBIT_TEST(flags, ENTRY_CACHABLE))
  202. strcat(buf, "CACHABLE,");
  203.     if (EBIT_TEST(flags, ENTRY_DISPATCHED))
  204. strcat(buf, "DISPATCHED,");
  205.     if (EBIT_TEST(flags, KEY_PRIVATE))
  206. strcat(buf, "PRIVATE,");
  207.     if (EBIT_TEST(flags, ENTRY_FWD_HDR_WAIT))
  208. strcat(buf, "FWD_HDR_WAIT,");
  209.     if (EBIT_TEST(flags, ENTRY_NEGCACHED))
  210. strcat(buf, "NEGCACHED,");
  211.     if (EBIT_TEST(flags, ENTRY_VALIDATED))
  212. strcat(buf, "VALIDATED,");
  213.     if (EBIT_TEST(flags, ENTRY_BAD_LENGTH))
  214. strcat(buf, "BAD_LENGTH,");
  215.     if (EBIT_TEST(flags, ENTRY_ABORTED))
  216. strcat(buf, "ABORTED,");
  217.     if ((t = strrchr(buf, ',')))
  218. *t = '';
  219.     return buf;
  220. }
  221. static const char *
  222. describeTimestamps(const StoreEntry * entry)
  223. {
  224.     LOCAL_ARRAY(char, buf, 256);
  225.     snprintf(buf, 256, "LV:%-9d LU:%-9d LM:%-9d EX:%-9d",
  226. (int) entry->timestamp,
  227. (int) entry->lastref,
  228. (int) entry->lastmod,
  229. (int) entry->expires);
  230.     return buf;
  231. }
  232. static void
  233. statStoreEntry(StoreEntry * s, StoreEntry * e)
  234. {
  235.     MemObject *mem = e->mem_obj;
  236.     int i;
  237.     struct _store_client *sc;
  238.     storeAppendPrintf(s, "KEY %sn", storeKeyText(e->key));
  239.     if (mem)
  240. storeAppendPrintf(s, "t%s %sn",
  241.     RequestMethodStr[mem->method], mem->log_url);
  242.     storeAppendPrintf(s, "t%sn", describeStatuses(e));
  243.     storeAppendPrintf(s, "t%sn", storeEntryFlags(e));
  244.     storeAppendPrintf(s, "t%sn", describeTimestamps(e));
  245.     storeAppendPrintf(s, "t%d locks, %d clients, %d refsn",
  246. (int) e->lock_count,
  247. storePendingNClients(e),
  248. (int) e->refcount);
  249.     storeAppendPrintf(s, "tSwap File %#08Xn",
  250. e->swap_file_number);
  251.     if (mem != NULL) {
  252. storeAppendPrintf(s, "tinmem_lo: %dn", (int) mem->inmem_lo);
  253. storeAppendPrintf(s, "tinmem_hi: %dn", (int) mem->inmem_hi);
  254. storeAppendPrintf(s, "tswapout: %d bytes done, %d queued, FD %dn",
  255.     (int) mem->swapout.done_offset,
  256.     (int) mem->swapout.queue_offset,
  257.     mem->swapout.fd);
  258. for (i = 0, sc = &mem->clients[i]; sc != NULL; sc = sc->next, i++) {
  259.     if (sc->callback_data == NULL)
  260. continue;
  261.     storeAppendPrintf(s, "tClient #%d, %pn", i, sc->callback_data);
  262.     storeAppendPrintf(s, "ttcopy_offset: %dn",
  263. (int) sc->copy_offset);
  264.     storeAppendPrintf(s, "ttseen_offset: %dn",
  265. (int) sc->seen_offset);
  266.     storeAppendPrintf(s, "ttcopy_size: %dn",
  267. (int) sc->copy_size);
  268.     storeAppendPrintf(s, "ttswapin_fd: %dn",
  269. (int) sc->swapin_fd);
  270.     storeAppendPrintf(s, "ttflags:");
  271.     if (sc->flags.disk_io_pending)
  272. storeAppendPrintf(s, " disk_io_pending");
  273.     if (sc->flags.store_copying)
  274. storeAppendPrintf(s, " store_copying");
  275.     if (sc->flags.copy_event_pending)
  276. storeAppendPrintf(s, " copy_event_pending");
  277.     storeAppendPrintf(s, "n");
  278. }
  279.     }
  280.     storeAppendPrintf(s, "n");
  281. }
  282. /* process objects list */
  283. static void
  284. statObjects(void *data)
  285. {
  286.     StatObjectsState *state = data;
  287.     StoreEntry *e;
  288.     hash_link *link_ptr = NULL;
  289.     hash_link *link_next = NULL;
  290.     if (state->bucket >= store_hash_buckets) {
  291. storeComplete(state->sentry);
  292. storeUnlockObject(state->sentry);
  293. cbdataFree(state);
  294. return;
  295.     } else if (EBIT_TEST(state->sentry->flags, ENTRY_ABORTED)) {
  296. storeUnlockObject(state->sentry);
  297. cbdataFree(state);
  298. return;
  299.     } else if (fwdCheckDeferRead(-1, state->sentry)) {
  300. eventAdd("statObjects", statObjects, state, 0.1, 1);
  301. return;
  302.     }
  303.     storeBuffer(state->sentry);
  304.     debug(49, 3) ("statObjects: Bucket #%dn", state->bucket);
  305.     link_next = hash_get_bucket(store_table, state->bucket);
  306.     while (NULL != (link_ptr = link_next)) {
  307. link_next = link_ptr->next;
  308. e = (StoreEntry *) link_ptr;
  309. if (state->filter && 0 == state->filter(e))
  310.     continue;
  311. statStoreEntry(state->sentry, e);
  312.     }
  313.     state->bucket++;
  314.     eventAdd("statObjects", statObjects, state, 0.0, 1);
  315.     storeBufferFlush(state->sentry);
  316. }
  317. static void
  318. statObjectsStart(StoreEntry * sentry, STOBJFLT * filter)
  319. {
  320.     StatObjectsState *state = xcalloc(1, sizeof(*state));
  321.     state->sentry = sentry;
  322.     state->filter = filter;
  323.     storeLockObject(sentry);
  324.     cbdataAdd(state, cbdataXfree, 0);
  325.     eventAdd("statObjects", statObjects, state, 0.0, 1);
  326. }
  327. static void
  328. stat_objects_get(StoreEntry * sentry)
  329. {
  330.     statObjectsStart(sentry, NULL);
  331. }
  332. static int
  333. statObjectsVmFilter(const StoreEntry * e)
  334. {
  335.     return e->mem_obj ? 1 : 0;
  336. }
  337. static void
  338. stat_vmobjects_get(StoreEntry * sentry)
  339. {
  340.     statObjectsStart(sentry, statObjectsVmFilter);
  341. }
  342. #if DEBUG_OPENFD
  343. static int
  344. statObjectsOpenfdFilter(const StoreEntry * e)
  345. {
  346.     if (e->mem_obj == NULL)
  347. return 0;
  348.     if (e->mem_obj->swapout.fd < 0)
  349. return 0;;
  350.     return 1;
  351. }
  352. static void
  353. statOpenfdObj(StoreEntry * sentry)
  354. {
  355.     statObjectsStart(sentry, statObjectsOpenfdFilter);
  356. }
  357. #endif
  358. #ifdef XMALLOC_STATISTICS
  359. static void
  360. info_get_mallstat(int size, int number, StoreEntry * sentry)
  361. {
  362.     if (number > 0)
  363. storeAppendPrintf(sentry, "t%d = %dn", size, number);
  364. }
  365. #endif
  366. static const char *
  367. fdRemoteAddr(const fde * f)
  368. {
  369.     LOCAL_ARRAY(char, buf, 32);
  370.     if (f->type != FD_SOCKET)
  371. return null_string;
  372.     snprintf(buf, 32, "%s.%d", f->ipaddr, (int) f->remote_port);
  373.     return buf;
  374. }
  375. static void
  376. statFiledescriptors(StoreEntry * sentry)
  377. {
  378.     int i;
  379.     fde *f;
  380.     storeAppendPrintf(sentry, "Active file descriptors:n");
  381.     storeAppendPrintf(sentry, "%-4s %-6s %-4s %-7s %-7s %-21s %sn",
  382. "File",
  383. "Type",
  384. "Tout",
  385. "Nread",
  386. "Nwrite",
  387. "Remote Address",
  388. "Description");
  389.     storeAppendPrintf(sentry, "---- ------ ---- ------- ------- --------------------- ------------------------------n");
  390.     for (i = 0; i < Squid_MaxFD; i++) {
  391. f = &fd_table[i];
  392. if (!f->flags.open)
  393.     continue;
  394. storeAppendPrintf(sentry, "%4d %-6.6s %4d %7d %7d %-21s %sn",
  395.     i,
  396.     fdTypeStr[f->type],
  397.     f->timeout_handler ? (int) (f->timeout - squid_curtime) / 60 : 0,
  398.     f->bytes_read,
  399.     f->bytes_written,
  400.     fdRemoteAddr(f),
  401.     f->desc);
  402.     }
  403. }
  404. static void
  405. info_get(StoreEntry * sentry)
  406. {
  407.     struct rusage rusage;
  408.     double cputime;
  409.     double runtime;
  410. #if HAVE_MSTATS && HAVE_GNUMALLOC_H
  411.     struct mstats ms;
  412. #elif HAVE_MALLINFO
  413.     struct mallinfo mp;
  414.     int t;
  415. #endif
  416.     runtime = tvSubDsec(squid_start, current_time);
  417.     if (runtime == 0.0)
  418. runtime = 1.0;
  419.     storeAppendPrintf(sentry, "Squid Object Cache: Version %sn",
  420. version_string);
  421.     storeAppendPrintf(sentry, "Start Time:t%sn",
  422. mkrfc1123(squid_start.tv_sec));
  423.     storeAppendPrintf(sentry, "Current Time:t%sn",
  424. mkrfc1123(current_time.tv_sec));
  425.     storeAppendPrintf(sentry, "Connection information for %s:n",
  426. appname);
  427.     storeAppendPrintf(sentry, "tNumber of clients accessing cache:t%un",
  428. Counter.client_http.clients);
  429.     storeAppendPrintf(sentry, "tNumber of HTTP requests received:t%un",
  430. Counter.client_http.requests);
  431.     storeAppendPrintf(sentry, "tNumber of ICP messages received:t%un",
  432. Counter.icp.pkts_recv);
  433.     storeAppendPrintf(sentry, "tNumber of ICP messages sent:t%un",
  434. Counter.icp.pkts_sent);
  435.     storeAppendPrintf(sentry, "tNumber of queued ICP replies:t%un",
  436. Counter.icp.replies_queued);
  437.     storeAppendPrintf(sentry, "tRequest failure ratio:t%5.2f%%n",
  438. request_failure_ratio);
  439.     storeAppendPrintf(sentry, "tHTTP requests per minute:t%.1fn",
  440. Counter.client_http.requests / (runtime / 60.0));
  441.     storeAppendPrintf(sentry, "tICP messages per minute:t%.1fn",
  442. (Counter.icp.pkts_sent + Counter.icp.pkts_recv) / (runtime / 60.0));
  443.     storeAppendPrintf(sentry, "tSelect loop called: %d times, %0.3f ms avgn",
  444. Counter.select_loops, 1000.0 * runtime / Counter.select_loops);
  445.     storeAppendPrintf(sentry, "Cache information for %s:n",
  446. appname);
  447.     storeAppendPrintf(sentry, "tRequest Hit Ratios:t5min: %3.1f%%, 60min: %3.1f%%n",
  448. statRequestHitRatio(5),
  449. statRequestHitRatio(60));
  450.     storeAppendPrintf(sentry, "tByte Hit Ratios:t5min: %3.1f%%, 60min: %3.1f%%n",
  451. statByteHitRatio(5),
  452. statByteHitRatio(60));
  453.     storeAppendPrintf(sentry, "tStorage Swap size:t%d KBn",
  454. store_swap_size);
  455.     storeAppendPrintf(sentry, "tStorage Mem size:t%d KBn",
  456. (int) (store_mem_size >> 10));
  457.     storeAppendPrintf(sentry, "tStorage LRU Expiration Age:t%6.2f daysn",
  458. (double) storeExpiredReferenceAge() / 86400.0);
  459.     storeAppendPrintf(sentry, "tMean Object Size:t%0.2f KBn",
  460. n_disk_objects ? (double) store_swap_size / n_disk_objects : 0.0);
  461.     storeAppendPrintf(sentry, "tRequests given to unlinkd:t%dn",
  462. Counter.unlink.requests);
  463.     storeAppendPrintf(sentry, "Median Service Times (seconds)  5 min    60 min:n");
  464.     storeAppendPrintf(sentry, "tHTTP Requests (All):  %8.5f %8.5fn",
  465. statMedianSvc(5, MEDIAN_HTTP) / 1000.0,
  466. statMedianSvc(60, MEDIAN_HTTP) / 1000.0);
  467.     storeAppendPrintf(sentry, "tCache Misses:         %8.5f %8.5fn",
  468. statMedianSvc(5, MEDIAN_MISS) / 1000.0,
  469. statMedianSvc(60, MEDIAN_MISS) / 1000.0);
  470.     storeAppendPrintf(sentry, "tCache Hits:           %8.5f %8.5fn",
  471. statMedianSvc(5, MEDIAN_HIT) / 1000.0,
  472. statMedianSvc(60, MEDIAN_HIT) / 1000.0);
  473.     storeAppendPrintf(sentry, "tNear Hits:            %8.5f %8.5fn",
  474. statMedianSvc(5, MEDIAN_NH) / 1000.0,
  475. statMedianSvc(60, MEDIAN_NH) / 1000.0);
  476.     storeAppendPrintf(sentry, "tNot-Modified Replies: %8.5f %8.5fn",
  477. statMedianSvc(5, MEDIAN_NM) / 1000.0,
  478. statMedianSvc(60, MEDIAN_NM) / 1000.0);
  479.     storeAppendPrintf(sentry, "tDNS Lookups:          %8.5f %8.5fn",
  480. statMedianSvc(5, MEDIAN_DNS) / 1000.0,
  481. statMedianSvc(60, MEDIAN_DNS) / 1000.0);
  482.     storeAppendPrintf(sentry, "tICP Queries:          %8.5f %8.5fn",
  483. statMedianSvc(5, MEDIAN_ICP_QUERY) / 1000000.0,
  484. statMedianSvc(60, MEDIAN_ICP_QUERY) / 1000000.0);
  485.     squid_getrusage(&rusage);
  486.     cputime = rusage_cputime(&rusage);
  487.     storeAppendPrintf(sentry, "Resource usage for %s:n", appname);
  488.     storeAppendPrintf(sentry, "tUP Time:t%.3f secondsn", runtime);
  489.     storeAppendPrintf(sentry, "tCPU Time:t%.3f secondsn", cputime);
  490.     storeAppendPrintf(sentry, "tCPU Usage:t%.2f%%n",
  491. dpercent(cputime, runtime));
  492.     storeAppendPrintf(sentry, "tCPU Usage, 5 minute avg:t%.2f%%n",
  493. statCPUUsage(5));
  494.     storeAppendPrintf(sentry, "tCPU Usage, 60 minute avg:t%.2f%%n",
  495. statCPUUsage(60));
  496.     storeAppendPrintf(sentry, "tMaximum Resident Size: %d KBn",
  497. rusage_maxrss(&rusage));
  498.     storeAppendPrintf(sentry, "tPage faults with physical i/o: %dn",
  499. rusage_pagefaults(&rusage));
  500. #if HAVE_MSTATS && HAVE_GNUMALLOC_H
  501.     ms = mstats();
  502.     storeAppendPrintf(sentry, "Memory usage for %s via mstats():n",
  503. appname);
  504.     storeAppendPrintf(sentry, "tTotal space in arena:  %6d KBn",
  505. ms.bytes_total >> 10);
  506.     storeAppendPrintf(sentry, "tTotal free:            %6d KB %d%%n",
  507. ms.bytes_free >> 10, percent(ms.bytes_free, ms.bytes_total));
  508. #elif HAVE_MALLINFO
  509.     mp = mallinfo();
  510.     storeAppendPrintf(sentry, "Memory usage for %s via mallinfo():n",
  511. appname);
  512.     storeAppendPrintf(sentry, "tTotal space in arena:  %6d KBn",
  513. mp.arena >> 10);
  514.     storeAppendPrintf(sentry, "tOrdinary blocks:       %6d KB %6d blksn",
  515. mp.uordblks >> 10, mp.ordblks);
  516.     storeAppendPrintf(sentry, "tSmall blocks:          %6d KB %6d blksn",
  517. mp.usmblks >> 10, mp.smblks);
  518.     storeAppendPrintf(sentry, "tHolding blocks:        %6d KB %6d blksn",
  519. mp.hblkhd >> 10, mp.hblks);
  520.     storeAppendPrintf(sentry, "tFree Small blocks:     %6d KBn",
  521. mp.fsmblks >> 10);
  522.     storeAppendPrintf(sentry, "tFree Ordinary blocks:  %6d KBn",
  523. mp.fordblks >> 10);
  524.     t = mp.uordblks + mp.usmblks + mp.hblkhd;
  525.     storeAppendPrintf(sentry, "tTotal in use:          %6d KB %d%%n",
  526. t >> 10, percent(t, mp.arena));
  527.     t = mp.fsmblks + mp.fordblks;
  528.     storeAppendPrintf(sentry, "tTotal free:            %6d KB %d%%n",
  529. t >> 10, percent(t, mp.arena));
  530. #if HAVE_EXT_MALLINFO
  531.     storeAppendPrintf(sentry, "tmax size of small blocks:t%dn", mp.mxfast);
  532.     storeAppendPrintf(sentry, "tnumber of small blocks in a holding block:t%dn",
  533. mp.nlblks);
  534.     storeAppendPrintf(sentry, "tsmall block rounding factor:t%dn", mp.grain);
  535.     storeAppendPrintf(sentry, "tspace (including overhead) allocated in ord. blks:t%dn"
  536. ,mp.uordbytes);
  537.     storeAppendPrintf(sentry, "tnumber of ordinary blocks allocated:t%dn",
  538. mp.allocated);
  539.     storeAppendPrintf(sentry, "tbytes used in maintaining the free tree:t%dn",
  540. mp.treeoverhead);
  541. #endif /* HAVE_EXT_MALLINFO */
  542. #endif /* HAVE_MALLINFO */
  543.     storeAppendPrintf(sentry, "Memory accounted for:n");
  544.     storeAppendPrintf(sentry, "tTotal accounted:       %6d KBn",
  545. memTotalAllocated() >> 10);
  546.     storeAppendPrintf(sentry, "File descriptor usage for %s:n", appname);
  547.     storeAppendPrintf(sentry, "tMaximum number of file descriptors:   %4dn",
  548. Squid_MaxFD);
  549.     storeAppendPrintf(sentry, "tLargest file desc currently in use:   %4dn",
  550. Biggest_FD);
  551.     storeAppendPrintf(sentry, "tNumber of file desc currently in use: %4dn",
  552. Number_FD);
  553.     storeAppendPrintf(sentry, "tFiles queued for open:                %4dn",
  554. Opening_FD);
  555.     storeAppendPrintf(sentry, "tAvailable number of file descriptors: %4dn",
  556. fdNFree());
  557.     storeAppendPrintf(sentry, "tReserved number of file descriptors:  %4dn",
  558. RESERVED_FD);
  559.     storeAppendPrintf(sentry, "tStore Disk files open:                %4dn",
  560. store_open_disk_fd);
  561.     storeAppendPrintf(sentry, "Internal Data Structures:n");
  562.     storeAppendPrintf(sentry, "t%6d StoreEntriesn",
  563. memInUse(MEM_STOREENTRY));
  564.     storeAppendPrintf(sentry, "t%6d StoreEntries with MemObjectsn",
  565. memInUse(MEM_MEMOBJECT));
  566.     storeAppendPrintf(sentry, "t%6d Hot Object Cache Itemsn",
  567. hot_obj_count);
  568.     storeAppendPrintf(sentry, "t%6d Filemap bits setn",
  569. storeDirMapBitsInUse());
  570.     storeAppendPrintf(sentry, "t%6d on-disk objectsn",
  571. n_disk_objects);
  572. #if XMALLOC_STATISTICS
  573.     storeAppendPrintf(sentry, "Memory allocation statisticsn");
  574.     malloc_statistics(info_get_mallstat, sentry);
  575. #endif
  576. }
  577. #define XAVG(X) (dt ? (double) (f->X - l->X) / dt : 0.0)
  578. static void
  579. statAvgDump(StoreEntry * sentry, int minutes, int hours)
  580. {
  581.     StatCounters *f;
  582.     StatCounters *l;
  583.     double dt;
  584.     double ct;
  585.     double x;
  586.     assert(N_COUNT_HIST > 1);
  587.     assert(minutes > 0 || hours > 0);
  588.     f = &CountHist[0];
  589.     l = f;
  590.     if (minutes > 0 && hours == 0) {
  591. /* checking minute readings ... */
  592. if (minutes > N_COUNT_HIST - 1)
  593.     minutes = N_COUNT_HIST - 1;
  594. l = &CountHist[minutes];
  595.     } else if (minutes == 0 && hours > 0) {
  596. /* checking hour readings ... */
  597. if (hours > N_COUNT_HOUR_HIST - 1)
  598.     hours = N_COUNT_HOUR_HIST - 1;
  599. l = &CountHourHist[hours];
  600.     } else {
  601. debug(18, 1) ("statAvgDump: Invalid args, minutes=%d, hours=%dn",
  602.     minutes, hours);
  603. return;
  604.     }
  605.     dt = tvSubDsec(l->timestamp, f->timestamp);
  606.     ct = f->cputime - l->cputime;
  607.     storeAppendPrintf(sentry, "sample_start_time = %d.%d (%s)n",
  608. (int) l->timestamp.tv_sec,
  609. (int) l->timestamp.tv_usec,
  610. mkrfc1123(l->timestamp.tv_sec));
  611.     storeAppendPrintf(sentry, "sample_end_time = %d.%d (%s)n",
  612. (int) f->timestamp.tv_sec,
  613. (int) f->timestamp.tv_usec,
  614. mkrfc1123(f->timestamp.tv_sec));
  615.     storeAppendPrintf(sentry, "client_http.requests = %f/secn",
  616. XAVG(client_http.requests));
  617.     storeAppendPrintf(sentry, "client_http.hits = %f/secn",
  618. XAVG(client_http.hits));
  619.     storeAppendPrintf(sentry, "client_http.errors = %f/secn",
  620. XAVG(client_http.errors));
  621.     storeAppendPrintf(sentry, "client_http.kbytes_in = %f/secn",
  622. XAVG(client_http.kbytes_in.kb));
  623.     storeAppendPrintf(sentry, "client_http.kbytes_out = %f/secn",
  624. XAVG(client_http.kbytes_out.kb));
  625.     x = statHistDeltaMedian(&l->client_http.all_svc_time,
  626. &f->client_http.all_svc_time);
  627.     storeAppendPrintf(sentry, "client_http.all_median_svc_time = %f secondsn",
  628. x / 1000.0);
  629.     x = statHistDeltaMedian(&l->client_http.miss_svc_time,
  630. &f->client_http.miss_svc_time);
  631.     storeAppendPrintf(sentry, "client_http.miss_median_svc_time = %f secondsn",
  632. x / 1000.0);
  633.     x = statHistDeltaMedian(&l->client_http.nm_svc_time,
  634. &f->client_http.nm_svc_time);
  635.     storeAppendPrintf(sentry, "client_http.nm_median_svc_time = %f secondsn",
  636. x / 1000.0);
  637.     x = statHistDeltaMedian(&l->client_http.nh_svc_time,
  638. &f->client_http.nh_svc_time);
  639.     storeAppendPrintf(sentry, "client_http.nh_median_svc_time = %f secondsn",
  640. x / 1000.0);
  641.     x = statHistDeltaMedian(&l->client_http.hit_svc_time,
  642. &f->client_http.hit_svc_time);
  643.     storeAppendPrintf(sentry, "client_http.hit_median_svc_time = %f secondsn",
  644. x / 1000.0);
  645.     storeAppendPrintf(sentry, "server.all.requests = %f/secn",
  646. XAVG(server.all.requests));
  647.     storeAppendPrintf(sentry, "server.all.errors = %f/secn",
  648. XAVG(server.all.errors));
  649.     storeAppendPrintf(sentry, "server.all.kbytes_in = %f/secn",
  650. XAVG(server.all.kbytes_in.kb));
  651.     storeAppendPrintf(sentry, "server.all.kbytes_out = %f/secn",
  652. XAVG(server.all.kbytes_out.kb));
  653.     storeAppendPrintf(sentry, "server.http.requests = %f/secn",
  654. XAVG(server.http.requests));
  655.     storeAppendPrintf(sentry, "server.http.errors = %f/secn",
  656. XAVG(server.http.errors));
  657.     storeAppendPrintf(sentry, "server.http.kbytes_in = %f/secn",
  658. XAVG(server.http.kbytes_in.kb));
  659.     storeAppendPrintf(sentry, "server.http.kbytes_out = %f/secn",
  660. XAVG(server.http.kbytes_out.kb));
  661.     storeAppendPrintf(sentry, "server.ftp.requests = %f/secn",
  662. XAVG(server.ftp.requests));
  663.     storeAppendPrintf(sentry, "server.ftp.errors = %f/secn",
  664. XAVG(server.ftp.errors));
  665.     storeAppendPrintf(sentry, "server.ftp.kbytes_in = %f/secn",
  666. XAVG(server.ftp.kbytes_in.kb));
  667.     storeAppendPrintf(sentry, "server.ftp.kbytes_out = %f/secn",
  668. XAVG(server.ftp.kbytes_out.kb));
  669.     storeAppendPrintf(sentry, "server.other.requests = %f/secn",
  670. XAVG(server.other.requests));
  671.     storeAppendPrintf(sentry, "server.other.errors = %f/secn",
  672. XAVG(server.other.errors));
  673.     storeAppendPrintf(sentry, "server.other.kbytes_in = %f/secn",
  674. XAVG(server.other.kbytes_in.kb));
  675.     storeAppendPrintf(sentry, "server.other.kbytes_out = %f/secn",
  676. XAVG(server.other.kbytes_out.kb));
  677.     storeAppendPrintf(sentry, "icp.pkts_sent = %f/secn",
  678. XAVG(icp.pkts_sent));
  679.     storeAppendPrintf(sentry, "icp.pkts_recv = %f/secn",
  680. XAVG(icp.pkts_recv));
  681.     storeAppendPrintf(sentry, "icp.queries_sent = %f/secn",
  682. XAVG(icp.queries_sent));
  683.     storeAppendPrintf(sentry, "icp.replies_sent = %f/secn",
  684. XAVG(icp.replies_sent));
  685.     storeAppendPrintf(sentry, "icp.queries_recv = %f/secn",
  686. XAVG(icp.queries_recv));
  687.     storeAppendPrintf(sentry, "icp.replies_recv = %f/secn",
  688. XAVG(icp.replies_recv));
  689.     storeAppendPrintf(sentry, "icp.replies_queued = %f/secn",
  690. XAVG(icp.replies_queued));
  691.     storeAppendPrintf(sentry, "icp.query_timeouts = %f/secn",
  692. XAVG(icp.query_timeouts));
  693.     storeAppendPrintf(sentry, "icp.kbytes_sent = %f/secn",
  694. XAVG(icp.kbytes_sent.kb));
  695.     storeAppendPrintf(sentry, "icp.kbytes_recv = %f/secn",
  696. XAVG(icp.kbytes_recv.kb));
  697.     storeAppendPrintf(sentry, "icp.q_kbytes_sent = %f/secn",
  698. XAVG(icp.q_kbytes_sent.kb));
  699.     storeAppendPrintf(sentry, "icp.r_kbytes_sent = %f/secn",
  700. XAVG(icp.r_kbytes_sent.kb));
  701.     storeAppendPrintf(sentry, "icp.q_kbytes_recv = %f/secn",
  702. XAVG(icp.q_kbytes_recv.kb));
  703.     storeAppendPrintf(sentry, "icp.r_kbytes_recv = %f/secn",
  704. XAVG(icp.r_kbytes_recv.kb));
  705.     x = statHistDeltaMedian(&l->icp.query_svc_time, &f->icp.query_svc_time);
  706.     storeAppendPrintf(sentry, "icp.query_median_svc_time = %f secondsn",
  707. x / 1000000.0);
  708.     x = statHistDeltaMedian(&l->icp.reply_svc_time, &f->icp.reply_svc_time);
  709.     storeAppendPrintf(sentry, "icp.reply_median_svc_time = %f secondsn",
  710. x / 1000000.0);
  711.     x = statHistDeltaMedian(&l->dns.svc_time, &f->dns.svc_time);
  712.     storeAppendPrintf(sentry, "dns.median_svc_time = %f secondsn",
  713. x / 1000.0);
  714.     storeAppendPrintf(sentry, "unlink.requests = %f/secn",
  715. XAVG(unlink.requests));
  716.     storeAppendPrintf(sentry, "page_faults = %f/secn",
  717. XAVG(page_faults));
  718.     storeAppendPrintf(sentry, "select_loops = %f/secn",
  719. XAVG(select_loops));
  720.     storeAppendPrintf(sentry, "select_fds = %f/secn",
  721. XAVG(select_fds));
  722.     storeAppendPrintf(sentry, "average_select_fd_period = %f/fdn",
  723. f->select_fds > l->select_fds ?
  724. (f->select_time - l->select_time) / (f->select_fds - l->select_fds)
  725. : 0.0);
  726.     x = statHistDeltaMedian(&l->select_fds_hist, &f->select_fds_hist);
  727.     storeAppendPrintf(sentry, "median_select_fds = %fn", x);
  728.     storeAppendPrintf(sentry, "swap_files_cleaned = %f/secn",
  729. XAVG(swap_files_cleaned));
  730.     storeAppendPrintf(sentry, "aborted_requests = %f/secn",
  731. XAVG(aborted_requests));
  732. #if HAVE_POLL
  733.     storeAppendPrintf(sentry, "syscalls.polls = %f/secn", XAVG(syscalls.polls));
  734. #else
  735.     storeAppendPrintf(sentry, "syscalls.selects = %f/secn", XAVG(syscalls.selects));
  736. #endif
  737.     storeAppendPrintf(sentry, "syscalls.disk.opens = %f/secn", XAVG(syscalls.disk.opens));
  738.     storeAppendPrintf(sentry, "syscalls.disk.closes = %f/secn", XAVG(syscalls.disk.closes));
  739.     storeAppendPrintf(sentry, "syscalls.disk.reads = %f/secn", XAVG(syscalls.disk.reads));
  740.     storeAppendPrintf(sentry, "syscalls.disk.writes = %f/secn", XAVG(syscalls.disk.writes));
  741.     storeAppendPrintf(sentry, "syscalls.disk.seeks = %f/secn", XAVG(syscalls.disk.seeks));
  742.     storeAppendPrintf(sentry, "syscalls.disk.unlinks = %f/secn", XAVG(syscalls.disk.unlinks));
  743.     storeAppendPrintf(sentry, "syscalls.sock.accepts = %f/secn", XAVG(syscalls.sock.accepts));
  744.     storeAppendPrintf(sentry, "syscalls.sock.sockets = %f/secn", XAVG(syscalls.sock.sockets));
  745.     storeAppendPrintf(sentry, "syscalls.sock.connects = %f/secn", XAVG(syscalls.sock.connects));
  746.     storeAppendPrintf(sentry, "syscalls.sock.binds = %f/secn", XAVG(syscalls.sock.binds));
  747.     storeAppendPrintf(sentry, "syscalls.sock.closes = %f/secn", XAVG(syscalls.sock.closes));
  748.     storeAppendPrintf(sentry, "syscalls.sock.reads = %f/secn", XAVG(syscalls.sock.reads));
  749.     storeAppendPrintf(sentry, "syscalls.sock.writes = %f/secn", XAVG(syscalls.sock.writes));
  750.     storeAppendPrintf(sentry, "syscalls.sock.recvfroms = %f/secn", XAVG(syscalls.sock.recvfroms));
  751.     storeAppendPrintf(sentry, "syscalls.sock.sendtos = %f/secn", XAVG(syscalls.sock.sendtos));
  752.     storeAppendPrintf(sentry, "cpu_time = %f secondsn", ct);
  753.     storeAppendPrintf(sentry, "wall_time = %f secondsn", dt);
  754.     storeAppendPrintf(sentry, "cpu_usage = %f%%n", dpercent(ct, dt));
  755. }
  756. void
  757. statInit(void)
  758. {
  759.     int i;
  760.     debug(18, 5) ("statInit: Initializing...n");
  761.     for (i = 0; i < N_COUNT_HIST; i++)
  762. statCountersInit(&CountHist[i]);
  763.     for (i = 0; i < N_COUNT_HOUR_HIST; i++)
  764. statCountersInit(&CountHourHist[i]);
  765.     statCountersInit(&Counter);
  766.     eventAdd("statAvgTick", statAvgTick, NULL, (double) COUNT_INTERVAL, 1);
  767.     cachemgrRegister("info",
  768. "General Runtime Information",
  769. info_get, 0, 1);
  770.     cachemgrRegister("filedescriptors",
  771. "Process Filedescriptor Allocation",
  772. statFiledescriptors, 0, 1);
  773.     cachemgrRegister("objects",
  774. "All Cache Objects",
  775. stat_objects_get, 0, 0);
  776.     cachemgrRegister("vm_objects",
  777. "In-Memory and In-Transit Objects",
  778. stat_vmobjects_get, 0, 0);
  779. #if DEBUG_OPENFD
  780.     cachemgrRegister("openfd_objects",
  781. "Objects with Swapout files open",
  782. statOpenfdObj, 0, 0);
  783. #endif
  784.     cachemgrRegister("io",
  785. "Server-side network read() size histograms",
  786. stat_io_get, 0, 1);
  787.     cachemgrRegister("counters",
  788. "Traffic and Resource Counters",
  789. statCountersDump, 0, 1);
  790.     cachemgrRegister("peer_select",
  791. "Peer Selection Algorithms",
  792. statPeerSelect, 0, 1);
  793.     cachemgrRegister("digest_stats",
  794. "Cache Digest and ICP blob",
  795. statDigestBlob, 0, 1);
  796.     cachemgrRegister("5min",
  797. "5 Minute Average of Counters",
  798. statAvg5min, 0, 1);
  799.     cachemgrRegister("60min",
  800. "60 Minute Average of Counters",
  801. statAvg60min, 0, 1);
  802.     cachemgrRegister("utilization",
  803. "Cache Utilization",
  804. statUtilization, 0, 1);
  805. #if STAT_GRAPHS
  806.     cachemgrRegister("graph_variables",
  807. "Display cache metrics graphically",
  808. statGraphDump, 0, 1);
  809. #endif
  810.     cachemgrRegister("histograms",
  811. "Full Histogram Counts",
  812. statCountersHistograms, 0, 1);
  813.     ClientActiveRequests.head = NULL;
  814.     ClientActiveRequests.tail = NULL;
  815.     cachemgrRegister("active_requests",
  816. "Client-side Active Requests",
  817. statClientRequests, 0, 1);
  818. }
  819. static void
  820. statAvgTick(void *notused)
  821. {
  822.     StatCounters *t = &CountHist[0];
  823.     StatCounters *p = &CountHist[1];
  824.     StatCounters *c = &Counter;
  825.     struct rusage rusage;
  826.     eventAdd("statAvgTick", statAvgTick, NULL, COUNT_INTERVAL, 1);
  827.     squid_getrusage(&rusage);
  828.     c->page_faults = rusage_pagefaults(&rusage);
  829.     c->cputime = rusage_cputime(&rusage);
  830.     c->timestamp = current_time;
  831.     /* even if NCountHist is small, we already Init()ed the tail */
  832.     statCountersClean(CountHist + N_COUNT_HIST - 1);
  833.     xmemmove(p, t, (N_COUNT_HIST - 1) * sizeof(StatCounters));
  834.     statCountersCopy(t, c);
  835.     NCountHist++;
  836.     if ((NCountHist % COUNT_INTERVAL) == 0) {
  837. /* we have an hours worth of readings.  store previous hour */
  838. StatCounters *t = &CountHourHist[0];
  839. StatCounters *p = &CountHourHist[1];
  840. StatCounters *c = &CountHist[N_COUNT_HIST - 1];
  841. statCountersClean(CountHourHist + N_COUNT_HOUR_HIST - 1);
  842. xmemmove(p, t, (N_COUNT_HOUR_HIST - 1) * sizeof(StatCounters));
  843. statCountersCopy(t, c);
  844. NCountHourHist++;
  845.     }
  846. }
  847. static void
  848. statCountersInit(StatCounters * C)
  849. {
  850.     assert(C);
  851.     memset(C, 0, sizeof(*C));
  852.     C->timestamp = current_time;
  853.     statCountersInitSpecial(C);
  854. }
  855. /* add special cases here as they arrive */
  856. static void
  857. statCountersInitSpecial(StatCounters * C)
  858. {
  859.     /*
  860.      * HTTP svc_time hist is kept in milli-seconds; max of 3 hours.
  861.      */
  862.     statHistLogInit(&C->client_http.all_svc_time, 300, 0.0, 3600000.0 * 3.0);
  863.     statHistLogInit(&C->client_http.miss_svc_time, 300, 0.0, 3600000.0 * 3.0);
  864.     statHistLogInit(&C->client_http.nm_svc_time, 300, 0.0, 3600000.0 * 3.0);
  865.     statHistLogInit(&C->client_http.nh_svc_time, 300, 0.0, 3600000.0 * 3.0);
  866.     statHistLogInit(&C->client_http.hit_svc_time, 300, 0.0, 3600000.0 * 3.0);
  867.     /*
  868.      * ICP svc_time hist is kept in micro-seconds; max of 1 minute.
  869.      */
  870.     statHistLogInit(&C->icp.query_svc_time, 300, 0.0, 1000000.0 * 60.0);
  871.     statHistLogInit(&C->icp.reply_svc_time, 300, 0.0, 1000000.0 * 60.0);
  872.     /*
  873.      * DNS svc_time hist is kept in milli-seconds; max of 10 minutes.
  874.      */
  875.     statHistLogInit(&C->dns.svc_time, 300, 0.0, 60000.0 * 10.0);
  876.     /*
  877.      * Cache Digest Stuff
  878.      */
  879.     statHistEnumInit(&C->cd.on_xition_count, CacheDigestHashFuncCount);
  880.     statHistEnumInit(&C->comm_icp_incoming, INCOMING_ICP_MAX);
  881.     statHistEnumInit(&C->comm_http_incoming, INCOMING_HTTP_MAX);
  882.     statHistIntInit(&C->select_fds_hist, SQUID_MAXFD);
  883. }
  884. /* add special cases here as they arrive */
  885. static void
  886. statCountersClean(StatCounters * C)
  887. {
  888.     assert(C);
  889.     statHistClean(&C->client_http.all_svc_time);
  890.     statHistClean(&C->client_http.miss_svc_time);
  891.     statHistClean(&C->client_http.nm_svc_time);
  892.     statHistClean(&C->client_http.nh_svc_time);
  893.     statHistClean(&C->client_http.hit_svc_time);
  894.     statHistClean(&C->icp.query_svc_time);
  895.     statHistClean(&C->icp.reply_svc_time);
  896.     statHistClean(&C->dns.svc_time);
  897.     statHistClean(&C->cd.on_xition_count);
  898.     statHistClean(&C->comm_icp_incoming);
  899.     statHistClean(&C->comm_http_incoming);
  900.     statHistClean(&C->select_fds_hist);
  901. }
  902. /* add special cases here as they arrive */
  903. static void
  904. statCountersCopy(StatCounters * dest, const StatCounters * orig)
  905. {
  906.     assert(dest && orig);
  907.     /* this should take care of all the fields, but "special" ones */
  908.     memcpy(dest, orig, sizeof(*dest));
  909.     /* prepare space where to copy special entries */
  910.     statCountersInitSpecial(dest);
  911.     /* now handle special cases */
  912.     /* note: we assert that histogram capacities do not change */
  913.     statHistCopy(&dest->client_http.all_svc_time, &orig->client_http.all_svc_time);
  914.     statHistCopy(&dest->client_http.miss_svc_time, &orig->client_http.miss_svc_time);
  915.     statHistCopy(&dest->client_http.nm_svc_time, &orig->client_http.nm_svc_time);
  916.     statHistCopy(&dest->client_http.nh_svc_time, &orig->client_http.nh_svc_time);
  917.     statHistCopy(&dest->client_http.hit_svc_time, &orig->client_http.hit_svc_time);
  918.     statHistCopy(&dest->icp.query_svc_time, &orig->icp.query_svc_time);
  919.     statHistCopy(&dest->icp.reply_svc_time, &orig->icp.reply_svc_time);
  920.     statHistCopy(&dest->dns.svc_time, &orig->dns.svc_time);
  921.     statHistCopy(&dest->cd.on_xition_count, &orig->cd.on_xition_count);
  922.     statHistCopy(&dest->comm_icp_incoming, &orig->comm_icp_incoming);
  923.     statHistCopy(&dest->comm_http_incoming, &orig->comm_http_incoming);
  924.     statHistCopy(&dest->select_fds_hist, &orig->select_fds_hist);
  925. }
  926. static void
  927. statCountersHistograms(StoreEntry * sentry)
  928. {
  929.     StatCounters *f = &Counter;
  930.     storeAppendPrintf(sentry, "client_http.all_svc_time histogram:n");
  931.     statHistDump(&f->client_http.all_svc_time, sentry, NULL);
  932.     storeAppendPrintf(sentry, "client_http.miss_svc_time histogram:n");
  933.     statHistDump(&f->client_http.miss_svc_time, sentry, NULL);
  934.     storeAppendPrintf(sentry, "client_http.nm_svc_time histogram:n");
  935.     statHistDump(&f->client_http.nm_svc_time, sentry, NULL);
  936.     storeAppendPrintf(sentry, "client_http.nh_svc_time histogram:n");
  937.     statHistDump(&f->client_http.nh_svc_time, sentry, NULL);
  938.     storeAppendPrintf(sentry, "client_http.hit_svc_time histogram:n");
  939.     statHistDump(&f->client_http.hit_svc_time, sentry, NULL);
  940.     storeAppendPrintf(sentry, "icp.query_svc_time histogram:n");
  941.     statHistDump(&f->icp.query_svc_time, sentry, NULL);
  942.     storeAppendPrintf(sentry, "icp.reply_svc_time histogram:n");
  943.     statHistDump(&f->icp.reply_svc_time, sentry, NULL);
  944.     storeAppendPrintf(sentry, "dns.svc_time histogram:n");
  945.     statHistDump(&f->dns.svc_time, sentry, NULL);
  946. }
  947. static void
  948. statCountersDump(StoreEntry * sentry)
  949. {
  950.     StatCounters *f = &Counter;
  951.     struct rusage rusage;
  952.     squid_getrusage(&rusage);
  953.     f->page_faults = rusage_pagefaults(&rusage);
  954.     f->cputime = rusage_cputime(&rusage);
  955.     storeAppendPrintf(sentry, "sample_time = %d.%d (%s)n",
  956. (int) f->timestamp.tv_sec,
  957. (int) f->timestamp.tv_usec,
  958. mkrfc1123(f->timestamp.tv_sec));
  959.     storeAppendPrintf(sentry, "client_http.requests = %dn",
  960. f->client_http.requests);
  961.     storeAppendPrintf(sentry, "client_http.hits = %dn",
  962. f->client_http.hits);
  963.     storeAppendPrintf(sentry, "client_http.errors = %dn",
  964. f->client_http.errors);
  965.     storeAppendPrintf(sentry, "client_http.kbytes_in = %dn",
  966. (int) f->client_http.kbytes_in.kb);
  967.     storeAppendPrintf(sentry, "client_http.kbytes_out = %dn",
  968. (int) f->client_http.kbytes_out.kb);
  969.     storeAppendPrintf(sentry, "client_http.hit_kbytes_out = %dn",
  970. (int) f->client_http.hit_kbytes_out.kb);
  971.     storeAppendPrintf(sentry, "server.all.requests = %dn",
  972. (int) f->server.all.requests);
  973.     storeAppendPrintf(sentry, "server.all.errors = %dn",
  974. (int) f->server.all.errors);
  975.     storeAppendPrintf(sentry, "server.all.kbytes_in = %dn",
  976. (int) f->server.all.kbytes_in.kb);
  977.     storeAppendPrintf(sentry, "server.all.kbytes_out = %dn",
  978. (int) f->server.all.kbytes_out.kb);
  979.     storeAppendPrintf(sentry, "server.http.requests = %dn",
  980. (int) f->server.http.requests);
  981.     storeAppendPrintf(sentry, "server.http.errors = %dn",
  982. (int) f->server.http.errors);
  983.     storeAppendPrintf(sentry, "server.http.kbytes_in = %dn",
  984. (int) f->server.http.kbytes_in.kb);
  985.     storeAppendPrintf(sentry, "server.http.kbytes_out = %dn",
  986. (int) f->server.http.kbytes_out.kb);
  987.     storeAppendPrintf(sentry, "server.ftp.requests = %dn",
  988. (int) f->server.ftp.requests);
  989.     storeAppendPrintf(sentry, "server.ftp.errors = %dn",
  990. (int) f->server.ftp.errors);
  991.     storeAppendPrintf(sentry, "server.ftp.kbytes_in = %dn",
  992. (int) f->server.ftp.kbytes_in.kb);
  993.     storeAppendPrintf(sentry, "server.ftp.kbytes_out = %dn",
  994. (int) f->server.ftp.kbytes_out.kb);
  995.     storeAppendPrintf(sentry, "server.other.requests = %dn",
  996. (int) f->server.other.requests);
  997.     storeAppendPrintf(sentry, "server.other.errors = %dn",
  998. (int) f->server.other.errors);
  999.     storeAppendPrintf(sentry, "server.other.kbytes_in = %dn",
  1000. (int) f->server.other.kbytes_in.kb);
  1001.     storeAppendPrintf(sentry, "server.other.kbytes_out = %dn",
  1002. (int) f->server.other.kbytes_out.kb);
  1003.     storeAppendPrintf(sentry, "icp.pkts_sent = %dn",
  1004. f->icp.pkts_sent);
  1005.     storeAppendPrintf(sentry, "icp.pkts_recv = %dn",
  1006. f->icp.pkts_recv);
  1007.     storeAppendPrintf(sentry, "icp.queries_sent = %dn",
  1008. f->icp.queries_sent);
  1009.     storeAppendPrintf(sentry, "icp.replies_sent = %dn",
  1010. f->icp.replies_sent);
  1011.     storeAppendPrintf(sentry, "icp.queries_recv = %dn",
  1012. f->icp.queries_recv);
  1013.     storeAppendPrintf(sentry, "icp.replies_recv = %dn",
  1014. f->icp.replies_recv);
  1015.     storeAppendPrintf(sentry, "icp.query_timeouts = %dn",
  1016. f->icp.query_timeouts);
  1017.     storeAppendPrintf(sentry, "icp.replies_queued = %dn",
  1018. f->icp.replies_queued);
  1019.     storeAppendPrintf(sentry, "icp.kbytes_sent = %dn",
  1020. (int) f->icp.kbytes_sent.kb);
  1021.     storeAppendPrintf(sentry, "icp.kbytes_recv = %dn",
  1022. (int) f->icp.kbytes_recv.kb);
  1023.     storeAppendPrintf(sentry, "icp.q_kbytes_sent = %dn",
  1024. (int) f->icp.q_kbytes_sent.kb);
  1025.     storeAppendPrintf(sentry, "icp.r_kbytes_sent = %dn",
  1026. (int) f->icp.r_kbytes_sent.kb);
  1027.     storeAppendPrintf(sentry, "icp.q_kbytes_recv = %dn",
  1028. (int) f->icp.q_kbytes_recv.kb);
  1029.     storeAppendPrintf(sentry, "icp.r_kbytes_recv = %dn",
  1030. (int) f->icp.r_kbytes_recv.kb);
  1031. #if USE_CACHE_DIGESTS
  1032.     storeAppendPrintf(sentry, "icp.times_used = %dn",
  1033. f->icp.times_used);
  1034.     storeAppendPrintf(sentry, "cd.times_used = %dn",
  1035. f->cd.times_used);
  1036.     storeAppendPrintf(sentry, "cd.msgs_sent = %dn",
  1037. f->cd.msgs_sent);
  1038.     storeAppendPrintf(sentry, "cd.msgs_recv = %dn",
  1039. f->cd.msgs_recv);
  1040.     storeAppendPrintf(sentry, "cd.memory = %dn",
  1041. (int) f->cd.memory.kb);
  1042.     storeAppendPrintf(sentry, "cd.local_memory = %dn",
  1043. (int) (store_digest ? store_digest->mask_size / 1024 : 0));
  1044.     storeAppendPrintf(sentry, "cd.kbytes_sent = %dn",
  1045. (int) f->cd.kbytes_sent.kb);
  1046.     storeAppendPrintf(sentry, "cd.kbytes_recv = %dn",
  1047. (int) f->cd.kbytes_recv.kb);
  1048. #endif
  1049.     storeAppendPrintf(sentry, "unlink.requests = %dn",
  1050. f->unlink.requests);
  1051.     storeAppendPrintf(sentry, "page_faults = %dn",
  1052. f->page_faults);
  1053.     storeAppendPrintf(sentry, "select_loops = %dn",
  1054. f->select_loops);
  1055.     storeAppendPrintf(sentry, "cpu_time = %fn",
  1056. f->cputime);
  1057.     storeAppendPrintf(sentry, "wall_time = %fn",
  1058. tvSubDsec(f->timestamp, current_time));
  1059.     storeAppendPrintf(sentry, "swap_files_cleaned = %dn",
  1060. f->swap_files_cleaned);
  1061.     storeAppendPrintf(sentry, "aborted_requests = %dn",
  1062. f->aborted_requests);
  1063. }
  1064. void
  1065. statFreeMemory(void)
  1066. {
  1067.     int i;
  1068.     for (i = 0; i < N_COUNT_HIST; i++)
  1069. statCountersClean(&CountHist[i]);
  1070.     for (i = 0; i < N_COUNT_HOUR_HIST; i++)
  1071. statCountersClean(&CountHourHist[i]);
  1072. }
  1073. static void
  1074. statPeerSelect(StoreEntry * sentry)
  1075. {
  1076. #if USE_CACHE_DIGESTS
  1077.     StatCounters *f = &Counter;
  1078.     peer *peer;
  1079.     const int tot_used = f->cd.times_used + f->icp.times_used;
  1080.     /* totals */
  1081.     cacheDigestGuessStatsReport(&f->cd.guess, sentry, "all peers");
  1082.     /* per-peer */
  1083.     storeAppendPrintf(sentry, "nPer-peer statistics:n");
  1084.     for (peer = getFirstPeer(); peer; peer = getNextPeer(peer)) {
  1085. if (peer->digest)
  1086.     peerDigestStatsReport(peer->digest, sentry);
  1087. else
  1088.     storeAppendPrintf(sentry, "nNo peer digest from %sn", peer->host);
  1089. storeAppendPrintf(sentry, "n");
  1090.     }
  1091.     storeAppendPrintf(sentry, "nAlgorithm usage:n");
  1092.     storeAppendPrintf(sentry, "Cache Digest: %7d (%3d%%)n",
  1093. f->cd.times_used, xpercentInt(f->cd.times_used, tot_used));
  1094.     storeAppendPrintf(sentry, "Icp:          %7d (%3d%%)n",
  1095. f->icp.times_used, xpercentInt(f->icp.times_used, tot_used));
  1096.     storeAppendPrintf(sentry, "Total:        %7d (%3d%%)n",
  1097. tot_used, xpercentInt(tot_used, tot_used));
  1098. #else
  1099.     storeAppendPrintf(sentry, "peer digests are disabled; no stats is available.n");
  1100. #endif
  1101. }
  1102. static void
  1103. statDigestBlob(StoreEntry * sentry)
  1104. {
  1105.     storeAppendPrintf(sentry, "nCounters:n");
  1106.     statCountersDump(sentry);
  1107.     storeAppendPrintf(sentry, "n5 Min Averages:n");
  1108.     statAvgDump(sentry, 5, 0);
  1109.     storeAppendPrintf(sentry, "nHistograms:n");
  1110.     statCountersHistograms(sentry);
  1111.     storeAppendPrintf(sentry, "nPeer Digests:n");
  1112.     statPeerSelect(sentry);
  1113.     storeAppendPrintf(sentry, "nLocal Digest:n");
  1114.     storeDigestReport(sentry);
  1115. }
  1116. static void
  1117. statAvg5min(StoreEntry * e)
  1118. {
  1119.     statAvgDump(e, 5, 0);
  1120. }
  1121. static void
  1122. statAvg60min(StoreEntry * e)
  1123. {
  1124.     statAvgDump(e, 60, 0);
  1125. }
  1126. static double
  1127. statMedianSvc(int interval, int which)
  1128. {
  1129.     StatCounters *f;
  1130.     StatCounters *l;
  1131.     double x;
  1132.     assert(interval > 0);
  1133.     if (interval > N_COUNT_HIST - 1)
  1134. interval = N_COUNT_HIST - 1;
  1135.     f = &CountHist[0];
  1136.     l = &CountHist[interval];
  1137.     assert(f);
  1138.     assert(l);
  1139.     switch (which) {
  1140.     case MEDIAN_HTTP:
  1141. x = statHistDeltaMedian(&l->client_http.all_svc_time, &f->client_http.all_svc_time);
  1142. break;
  1143.     case MEDIAN_HIT:
  1144. x = statHistDeltaMedian(&l->client_http.hit_svc_time, &f->client_http.hit_svc_time);
  1145. break;
  1146.     case MEDIAN_MISS:
  1147. x = statHistDeltaMedian(&l->client_http.miss_svc_time, &f->client_http.miss_svc_time);
  1148. break;
  1149.     case MEDIAN_NM:
  1150. x = statHistDeltaMedian(&l->client_http.nm_svc_time, &f->client_http.nm_svc_time);
  1151. break;
  1152.     case MEDIAN_NH:
  1153. x = statHistDeltaMedian(&l->client_http.nh_svc_time, &f->client_http.nh_svc_time);
  1154. break;
  1155.     case MEDIAN_ICP_QUERY:
  1156. x = statHistDeltaMedian(&l->icp.query_svc_time, &f->icp.query_svc_time);
  1157. break;
  1158.     case MEDIAN_DNS:
  1159. x = statHistDeltaMedian(&l->dns.svc_time, &f->dns.svc_time);
  1160. break;
  1161.     default:
  1162. debug(49, 5) ("get_median_val: unknown type.n");
  1163. x = 0;
  1164.     }
  1165.     return x;
  1166. }
  1167. /*
  1168.  * SNMP wants ints, ick
  1169.  */
  1170. int
  1171. get_median_svc(int interval, int which)
  1172. {
  1173.     return (int) statMedianSvc(interval, which);
  1174. }
  1175. StatCounters *
  1176. snmpStatGet(int minutes)
  1177. {
  1178.     return &CountHist[minutes];
  1179. }
  1180. int
  1181. stat5minClientRequests(void)
  1182. {
  1183.     assert(N_COUNT_HIST > 5);
  1184.     return Counter.client_http.requests - CountHist[5].client_http.requests;
  1185. }
  1186. static double
  1187. statCPUUsage(int minutes)
  1188. {
  1189.     assert(minutes < N_COUNT_HIST);
  1190.     return dpercent(CountHist[0].cputime - CountHist[minutes].cputime,
  1191. tvSubDsec(CountHist[minutes].timestamp, CountHist[0].timestamp));
  1192. }
  1193. extern double
  1194. statRequestHitRatio(int minutes)
  1195. {
  1196.     assert(minutes < N_COUNT_HIST);
  1197.     return dpercent(CountHist[0].client_http.hits -
  1198. CountHist[minutes].client_http.hits,
  1199. CountHist[0].client_http.requests -
  1200. CountHist[minutes].client_http.requests);
  1201. }
  1202. extern double
  1203. statByteHitRatio(int minutes)
  1204. {
  1205.     size_t s;
  1206.     size_t c;
  1207.     assert(minutes < N_COUNT_HIST);
  1208.     c = CountHist[0].client_http.kbytes_out.kb - CountHist[minutes].client_http.kbytes_out.kb;
  1209.     s = CountHist[0].server.all.kbytes_in.kb - CountHist[minutes].server.all.kbytes_in.kb;
  1210.     /* size_t might be unsigned */
  1211.     if (c > s)
  1212. return dpercent(c - s, c);
  1213.     else
  1214. return (-1.0 * dpercent(s - c, c));
  1215. }
  1216. static void
  1217. statClientRequests(StoreEntry * s)
  1218. {
  1219.     dlink_node *i;
  1220.     clientHttpRequest *http;
  1221.     ConnStateData *conn;
  1222.     StoreEntry *e;
  1223.     int fd;
  1224.     for (i = ClientActiveRequests.head; i; i = i->next) {
  1225. http = i->data;
  1226. assert(http);
  1227. conn = http->conn;
  1228. storeAppendPrintf(s, "Connection: %pn", conn);
  1229. if (conn) {
  1230.     fd = conn->fd;
  1231.     storeAppendPrintf(s, "tFD %d, read %d, wrote %dn", fd,
  1232. fd_table[fd].bytes_read, fd_table[fd].bytes_written);
  1233.     storeAppendPrintf(s, "tFD desc: %sn", fd_table[fd].desc);
  1234.     storeAppendPrintf(s, "tin: buf %p, offset %d, size %dn",
  1235. conn->in.buf, conn->in.offset, conn->in.size);
  1236.     storeAppendPrintf(s, "tpeer: %s:%dn",
  1237. inet_ntoa(conn->peer.sin_addr),
  1238. ntohs(conn->peer.sin_port));
  1239.     storeAppendPrintf(s, "tme: %s:%dn",
  1240. inet_ntoa(conn->me.sin_addr),
  1241. ntohs(conn->me.sin_port));
  1242.     storeAppendPrintf(s, "tnrequests: %dn",
  1243. conn->nrequests);
  1244.     storeAppendPrintf(s, "tpersistent: %dn",
  1245. conn->persistent);
  1246.     storeAppendPrintf(s, "tdefer: n %d, until %dn",
  1247. conn->defer.n, conn->defer.until);
  1248. }
  1249. storeAppendPrintf(s, "uri %sn", http->uri);
  1250. storeAppendPrintf(s, "out.offset %d, out.size %dn",
  1251.     http->out.offset, http->out.size);
  1252. storeAppendPrintf(s, "req_sz %dn", http->req_sz);
  1253. e = http->entry;
  1254. storeAppendPrintf(s, "entry %p/%sn", e, e ? storeKeyText(e->key) : "N/A");
  1255. e = http->old_entry;
  1256. storeAppendPrintf(s, "old_entry %p/%sn", e, e ? storeKeyText(e->key) : "N/A");
  1257. storeAppendPrintf(s, "start %d.%06d (%f seconds ago)n", http->start.tv_sec,
  1258.     http->start.tv_usec,
  1259.     tvSubDsec(http->start, current_time));
  1260. storeAppendPrintf(s, "n");
  1261.     }
  1262. }
  1263. #if STAT_GRAPHS
  1264. /*
  1265.  * urgh, i don't like these, but they do cut the amount of code down immensely
  1266.  */
  1267. #define GRAPH_PER_MIN(Y) 
  1268.     for (i=0;i<(N_COUNT_HIST-2);i++) { 
  1269. dt = tvSubDsec(CountHist[i].timestamp, CountHist[i+1].timestamp); 
  1270. if (dt <= 0.0) 
  1271.     break; 
  1272. storeAppendPrintf(e, "%lu,%0.2f:", 
  1273.     CountHist[i].timestamp.tv_sec, 
  1274.     ((CountHist[i].Y - CountHist[i+1].Y) / dt)); 
  1275.     }
  1276. #define GRAPH_PER_HOUR(Y) 
  1277.     for (i=0;i<(N_COUNT_HOUR_HIST-2);i++) { 
  1278. dt = tvSubDsec(CountHourHist[i].timestamp, CountHourHist[i+1].timestamp); 
  1279. if (dt <= 0.0) 
  1280.     break; 
  1281. storeAppendPrintf(e, "%lu,%0.2f:", 
  1282.     CountHourHist[i].timestamp.tv_sec, 
  1283.     ((CountHourHist[i].Y - CountHourHist[i+1].Y) / dt)); 
  1284.     }
  1285. #define GRAPH_TITLE(X,Y) storeAppendPrintf(e,"%st%st",X,Y);
  1286. #define GRAPH_END storeAppendPrintf(e,"n");
  1287. #define GENGRAPH(X,Y,Z) 
  1288.     GRAPH_TITLE(Y,Z) 
  1289.     GRAPH_PER_MIN(X) 
  1290.     GRAPH_PER_HOUR(X) 
  1291.     GRAPH_END
  1292. static void
  1293. statGraphDump(StoreEntry * e)
  1294. {
  1295.     int i;
  1296.     double dt;
  1297.     GENGRAPH(client_http.requests, "client_http.requests", "Client HTTP requests/sec");
  1298.     GENGRAPH(client_http.hits, "client_http.hits", "Client HTTP hits/sec");
  1299.     GENGRAPH(client_http.errors, "client_http.errors", "Client HTTP errors/sec");
  1300.     GENGRAPH(client_http.kbytes_in.kb, "client_http.kbytes_in", "Client HTTP kbytes_in/sec");
  1301.     GENGRAPH(client_http.kbytes_out.kb, "client_http.kbytes_out", "Client HTTP kbytes_out/sec");
  1302.     /* XXX todo: http median service times */
  1303.     GENGRAPH(server.all.requests, "server.all.requests", "Server requests/sec");
  1304.     GENGRAPH(server.all.errors, "server.all.errors", "Server errors/sec");
  1305.     GENGRAPH(server.all.kbytes_in.kb, "server.all.kbytes_in", "Server total kbytes_in/sec");
  1306.     GENGRAPH(server.all.kbytes_out.kb, "server.all.kbytes_out", "Server total kbytes_out/sec");
  1307.     GENGRAPH(server.http.requests, "server.http.requests", "Server HTTP requests/sec");
  1308.     GENGRAPH(server.http.errors, "server.http.errors", "Server HTTP errors/sec");
  1309.     GENGRAPH(server.http.kbytes_in.kb, "server.http.kbytes_in", "Server HTTP kbytes_in/sec");
  1310.     GENGRAPH(server.http.kbytes_out.kb, "server.http.kbytes_out", "Server HTTP kbytes_out/sec");
  1311.     GENGRAPH(server.ftp.requests, "server.ftp.requests", "Server FTP requests/sec");
  1312.     GENGRAPH(server.ftp.errors, "server.ftp.errors", "Server FTP errors/sec");
  1313.     GENGRAPH(server.ftp.kbytes_in.kb, "server.ftp.kbytes_in", "Server FTP kbytes_in/sec");
  1314.     GENGRAPH(server.ftp.kbytes_out.kb, "server.ftp.kbytes_out", "Server FTP kbytes_out/sec");
  1315.     GENGRAPH(server.other.requests, "server.other.requests", "Server other requests/sec");
  1316.     GENGRAPH(server.other.errors, "server.other.errors", "Server other errors/sec");
  1317.     GENGRAPH(server.other.kbytes_in.kb, "server.other.kbytes_in", "Server other kbytes_in/sec");
  1318.     GENGRAPH(server.other.kbytes_out.kb, "server.other.kbytes_out", "Server other kbytes_out/sec");
  1319.     GENGRAPH(icp.pkts_sent, "icp.pkts_sent", "ICP packets sent/sec");
  1320.     GENGRAPH(icp.pkts_recv, "icp.pkts_recv", "ICP packets received/sec");
  1321.     GENGRAPH(icp.kbytes_sent.kb, "icp.kbytes_sent", "ICP kbytes_sent/sec");
  1322.     GENGRAPH(icp.kbytes_recv.kb, "icp.kbytes_recv", "ICP kbytes_received/sec");
  1323.     /* XXX todo: icp median service times */
  1324.     /* XXX todo: dns median service times */
  1325.     GENGRAPH(unlink.requests, "unlink.requests", "Cache File unlink requests/sec");
  1326.     GENGRAPH(page_faults, "page_faults", "System Page Faults/sec");
  1327.     GENGRAPH(select_loops, "select_loops", "System Select Loop calls/sec");
  1328.     GENGRAPH(cputime, "cputime", "CPU utilisation");
  1329. }
  1330. #endif /* STAT_GRAPHS */