PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/varnish-3.0.2/bin/varnishhist/varnishhist.c

#
C | 356 lines | 271 code | 44 blank | 41 comment | 42 complexity | 4bfb31492ca569add19ce8fca953884c MD5 | raw file
  1. /*-
  2. * Copyright (c) 2006 Verdens Gang AS
  3. * Copyright (c) 2006-2010 Varnish Software AS
  4. * All rights reserved.
  5. *
  6. * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
  7. * Author: Dag-Erling Sm?¸rgrav <des@des.no>
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  22. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * Log tailer for Varnish
  31. */
  32. #include "config.h"
  33. #include <sys/types.h>
  34. #include <curses.h>
  35. #include <errno.h>
  36. #include <limits.h>
  37. #include <math.h>
  38. #include <pthread.h>
  39. #include <regex.h>
  40. #include <signal.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <unistd.h>
  45. #include "libvarnish.h"
  46. #include "vsl.h"
  47. #include "varnishapi.h"
  48. #define HIST_N 2000 /* how far back we remember */
  49. #define HIST_LOW -6 /* low end of log range */
  50. #define HIST_HIGH 3 /* high end of log range */
  51. #define HIST_RANGE (HIST_HIGH - HIST_LOW)
  52. #define HIST_RES 100 /* bucket resolution */
  53. #define HIST_BUCKETS (HIST_RANGE * HIST_RES)
  54. static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
  55. static int delay = 1;
  56. static unsigned rr_hist[HIST_N];
  57. static unsigned nhist;
  58. static unsigned next_hist;
  59. static unsigned bucket_miss[HIST_BUCKETS];
  60. static unsigned bucket_hit[HIST_BUCKETS];
  61. static unsigned char hh[FD_SETSIZE];
  62. static uint64_t bitmap[FD_SETSIZE];
  63. static double log_ten;
  64. static int scales[] = {
  65. 1,
  66. 2,
  67. 3,
  68. 4,
  69. 5,
  70. 10,
  71. 15,
  72. 20,
  73. 25,
  74. 50,
  75. 100,
  76. 250,
  77. 500,
  78. 1000,
  79. 2500,
  80. 5000,
  81. 10000,
  82. 25000,
  83. 50000,
  84. 100000,
  85. INT_MAX
  86. };
  87. static void
  88. update(struct VSM_data *vd)
  89. {
  90. int w = COLS / HIST_RANGE;
  91. int n = w * HIST_RANGE;
  92. unsigned bm[n], bh[n];
  93. unsigned max;
  94. int i, j, scale;
  95. erase();
  96. /* Draw horizontal axis */
  97. w = COLS / HIST_RANGE;
  98. n = w * HIST_RANGE;
  99. for (i = 0; i < n; ++i)
  100. (void)mvaddch(LINES - 2, i, '-');
  101. for (i = 0, j = HIST_LOW; i < HIST_RANGE; ++i, ++j) {
  102. (void)mvaddch(LINES - 2, w * i, '+');
  103. mvprintw(LINES - 1, w * i, "|1e%d", j);
  104. }
  105. mvprintw(0, 0, "%*s", COLS - 1, VSM_Name(vd));
  106. /* count our flock */
  107. for (i = 0; i < n; ++i)
  108. bm[i] = bh[i] = 0;
  109. for (i = 0, max = 1; i < HIST_BUCKETS; ++i) {
  110. j = i * n / HIST_BUCKETS;
  111. bm[j] += bucket_miss[i];
  112. bh[j] += bucket_hit[i];
  113. if (bm[j] + bh[j] > max)
  114. max = bm[j] + bh[j];
  115. }
  116. /* scale */
  117. for (i = 0; max / scales[i] > LINES - 3; ++i)
  118. /* nothing */ ;
  119. scale = scales[i];
  120. mvprintw(0, 0, "1:%d, n = %d", scale, nhist);
  121. /* show them */
  122. for (i = 0; i < n; ++i) {
  123. for (j = 0; j < bm[i] / scale; ++j)
  124. (void)mvaddch(LINES - 3 - j, i, '#');
  125. for (; j < (bm[i] + bh[i]) / scale; ++j)
  126. (void)mvaddch(LINES - 3 - j, i, '|');
  127. }
  128. refresh();
  129. }
  130. static int
  131. h_hist(void *priv, enum VSL_tag_e tag, unsigned fd, unsigned len,
  132. unsigned spec, const char *ptr, uint64_t bm)
  133. {
  134. double b;
  135. int i, j;
  136. struct VSM_data *vd = priv;
  137. (void)len;
  138. (void)spec;
  139. if (fd >= FD_SETSIZE)
  140. /* oops */
  141. return (0);
  142. bitmap[fd] |= bm;
  143. if (tag == SLT_Hit) {
  144. hh[fd] = 1;
  145. return (0);
  146. }
  147. if (tag != SLT_ReqEnd)
  148. return (0);
  149. if (!VSL_Matched(vd, bitmap[fd])) {
  150. bitmap[fd] = 0;
  151. hh[fd] = 0;
  152. return (0);
  153. }
  154. /* determine processing time */
  155. #if 1
  156. i = sscanf(ptr, "%*d %*f %*f %*f %lf", &b);
  157. #else
  158. i = sscanf(ptr, "%*d %*f %*f %lf", &b);
  159. #endif
  160. assert(i == 1);
  161. /* select bucket */
  162. i = HIST_RES * (log(b) / log_ten);
  163. if (i < HIST_LOW * HIST_RES)
  164. i = HIST_LOW * HIST_RES;
  165. if (i >= HIST_HIGH * HIST_RES)
  166. i = HIST_HIGH * HIST_RES - 1;
  167. i -= HIST_LOW * HIST_RES;
  168. assert(i >= 0);
  169. assert(i < HIST_BUCKETS);
  170. pthread_mutex_lock(&mtx);
  171. /* phase out old data */
  172. if (nhist == HIST_N) {
  173. j = rr_hist[next_hist];
  174. if (j < 0) {
  175. assert(bucket_miss[-j] > 0);
  176. bucket_miss[-j]--;
  177. } else {
  178. assert(bucket_hit[j] > 0);
  179. bucket_hit[j]--;
  180. }
  181. } else {
  182. ++nhist;
  183. }
  184. /* phase in new data */
  185. if (hh[fd] || i == 0) {
  186. bucket_hit[i]++;
  187. rr_hist[next_hist] = i;
  188. } else {
  189. bucket_miss[i]++;
  190. rr_hist[next_hist] = -i;
  191. }
  192. if (++next_hist == HIST_N) {
  193. next_hist = 0;
  194. }
  195. hh[fd] = 0;
  196. bitmap[fd] = 0;
  197. pthread_mutex_unlock(&mtx);
  198. return (0);
  199. }
  200. static void *
  201. accumulate_thread(void *arg)
  202. {
  203. struct VSM_data *vd = arg;
  204. int i;
  205. for (;;) {
  206. i = VSL_Dispatch(vd, h_hist, vd);
  207. if (i < 0)
  208. break;
  209. if (i == 0)
  210. usleep(50000);
  211. }
  212. return (arg);
  213. }
  214. static void
  215. do_curses(struct VSM_data *vd)
  216. {
  217. pthread_t thr;
  218. int ch;
  219. if (pthread_create(&thr, NULL, accumulate_thread, vd) != 0) {
  220. fprintf(stderr, "pthread_create(): %s\n", strerror(errno));
  221. exit(1);
  222. }
  223. initscr();
  224. raw();
  225. noecho();
  226. nonl();
  227. intrflush(stdscr, FALSE);
  228. curs_set(0);
  229. erase();
  230. for (;;) {
  231. pthread_mutex_lock(&mtx);
  232. update(vd);
  233. pthread_mutex_unlock(&mtx);
  234. timeout(delay * 1000);
  235. switch ((ch = getch())) {
  236. case ERR:
  237. break;
  238. #ifdef KEY_RESIZE
  239. case KEY_RESIZE:
  240. erase();
  241. break;
  242. #endif
  243. case '\014': /* Ctrl-L */
  244. case '\024': /* Ctrl-T */
  245. redrawwin(stdscr);
  246. refresh();
  247. break;
  248. case '\003': /* Ctrl-C */
  249. raise(SIGINT);
  250. break;
  251. case '\032': /* Ctrl-Z */
  252. endwin();
  253. raise(SIGTSTP);
  254. break;
  255. case '\021': /* Ctrl-Q */
  256. case 'Q':
  257. case 'q':
  258. endwin();
  259. return;
  260. case '0':
  261. case '1':
  262. case '2':
  263. case '3':
  264. case '4':
  265. case '5':
  266. case '6':
  267. case '7':
  268. case '8':
  269. case '9':
  270. delay = 1 << (ch - '0');
  271. break;
  272. default:
  273. beep();
  274. break;
  275. }
  276. }
  277. }
  278. /*--------------------------------------------------------------------*/
  279. static void
  280. usage(void)
  281. {
  282. fprintf(stderr, "usage: varnishhist "
  283. "%s [-n varnish_name] [-V] [-w delay]\n", VSL_USAGE);
  284. exit(1);
  285. }
  286. int
  287. main(int argc, char **argv)
  288. {
  289. int o;
  290. struct VSM_data *vd;
  291. vd = VSM_New();
  292. VSL_Setup(vd);
  293. while ((o = getopt(argc, argv, VSL_ARGS "Vw:")) != -1) {
  294. switch (o) {
  295. case 'V':
  296. VCS_Message("varnishhist");
  297. exit(0);
  298. case 'w':
  299. delay = atoi(optarg);
  300. break;
  301. default:
  302. if (VSL_Arg(vd, o, optarg) > 0)
  303. break;
  304. usage();
  305. }
  306. }
  307. if (VSL_Open(vd, 1))
  308. exit(1);
  309. log_ten = log(10.0);
  310. do_curses(vd);
  311. exit(0);
  312. }