[master] 8aec529 New varnishstat curses implementation

Martin Blix Grydeland martin at varnish-cache.org
Wed May 15 14:46:13 CEST 2013


commit 8aec529fadd7cb97ceccb8bef455676c39886661
Author: Martin Blix Grydeland <martin at varnish-software.com>
Date:   Wed Mar 13 14:20:56 2013 +0100

    New varnishstat curses implementation

diff --git a/bin/varnishstat/Makefile.am b/bin/varnishstat/Makefile.am
index 1a38329..6060438 100644
--- a/bin/varnishstat/Makefile.am
+++ b/bin/varnishstat/Makefile.am
@@ -12,7 +12,8 @@ varnishstat_SOURCES = \
 	varnishstat.c \
 	varnishstat_curses.c \
 	$(top_builddir)/lib/libvarnish/vas.c \
-	$(top_builddir)/lib/libvarnish/version.c
+	$(top_builddir)/lib/libvarnish/version.c \
+	$(top_builddir)/lib/libvarnish/vtim.c
 
 varnishstat_LDADD = \
 	$(top_builddir)/lib/libvarnishcompat/libvarnishcompat.la \
diff --git a/bin/varnishstat/varnishstat.c b/bin/varnishstat/varnishstat.c
index e06fe2c..fcd9bc3 100644
--- a/bin/varnishstat/varnishstat.c
+++ b/bin/varnishstat/varnishstat.c
@@ -192,7 +192,8 @@ do_once(struct VSM_data *vd, const struct VSC_C_main *VSC_C_main)
 	struct once_priv op;
 
 	memset(&op, 0, sizeof op);
-	op.up = VSC_C_main->uptime;
+	if (VSC_C_main != NULL)
+		op.up = VSC_C_main->uptime;
 	op.pad = 18;
 
 	(void)VSC_Iter(vd, do_once_cb, &op);
@@ -267,7 +268,6 @@ main(int argc, char * const *argv)
 {
 	int c;
 	struct VSM_data *vd;
-	const struct VSC_C_main *VSC_C_main;
 	int delay = 1, once = 0, xml = 0, json = 0, do_repeat = 0;
 
 	vd = VSM_New();
@@ -304,11 +304,8 @@ main(int argc, char * const *argv)
 		fprintf(stderr, "%s\n", VSM_Error(vd));
 		exit(1);
 	}
-	VSC_C_main = VSC_Main(vd);
-	AN(VSC_C_main);
-
 	if (!(xml || json || once)) {
-		do_curses(vd, VSC_C_main, delay);
+		do_curses(vd, delay);
 		exit(0);
 	}
 
@@ -318,7 +315,7 @@ main(int argc, char * const *argv)
 		else if (json)
 			do_json(vd);
 		else if (once)
-			do_once(vd, VSC_C_main);
+			do_once(vd, VSC_Main(vd));
 		else {
 			assert(0);
 		}
diff --git a/bin/varnishstat/varnishstat.h b/bin/varnishstat/varnishstat.h
index c229ed2..1f66476 100644
--- a/bin/varnishstat/varnishstat.h
+++ b/bin/varnishstat/varnishstat.h
@@ -35,6 +35,4 @@
 #include "vas.h"
 #include "vcs.h"
 
-
-void do_curses(struct VSM_data *vd, const struct VSC_C_main *VSC_C_main,
-    int delay);
+void do_curses(struct VSM_data *vd, int delay);
diff --git a/bin/varnishstat/varnishstat_curses.c b/bin/varnishstat/varnishstat_curses.c
index f1ecb77..5d19dc1 100644
--- a/bin/varnishstat/varnishstat_curses.c
+++ b/bin/varnishstat/varnishstat_curses.c
@@ -1,10 +1,11 @@
 /*-
  * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2010 Varnish Software AS
+ * Copyright (c) 2006-2013 Varnish Software AS
  * All rights reserved.
  *
  * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
  * Author: Dag-Erling Smørgrav <des at des.no>
+ * Author: Martin Blix Grydeland <martin at varnish-software.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,250 +31,863 @@
  * Statistics output program
  */
 
+
 #include "config.h"
 
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <time.h>
 #include <sys/time.h>
+#include <poll.h>
+#include <stdint.h>
+
+#include "vas.h"
+#include "miniobj.h"
+#include "vqueue.h"
+#include "vapi/vsm.h"
+#include "vapi/vsc.h"
+#include "vtim.h"
+
+#include "varnishstat.h"
 
 #ifdef HAVE_NCURSES_CURSES_H
 #  include <ncurses/curses.h>
-#endif
-
-#ifndef HAVE_NCURSES_CURSES_H
+#else
 #  ifdef HAVE_CURSES_H
 #    include <curses.h>
 #  endif
 #endif
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
-#include "varnishstat.h"
+#define LINES_STATUS		3
+#define LINES_BAR_T		1
+#define LINES_BAR_B		1
+#define LINES_INFO		3
+#define LINES_POINTS_MIN	3
 
-#include "vapi/vsc.h"
-#include "vapi/vsm.h"
-#include "vqueue.h"
+#define N_COL			6
+#define COLW			13
+#define COLW_NAME_MIN		24
 
-#if 0
-#define AC(x) assert((x) != ERR)
-#else
-#define AC(x) x
-#endif
+struct ma {
+	unsigned n, nmax;
+	double acc;
+};
 
 struct pt {
-	VTAILQ_ENTRY(pt)	next;
-	const volatile uint64_t	*ptr;
-	uint64_t		ref;
+	unsigned		magic;
+#define PT_MAGIC		0x41698E4F
+	VTAILQ_ENTRY(pt)	list;
+
+	const struct VSC_point	*vpt;
+
+	char			*key;
+	char			*name;
 	int			flag;
+	const volatile uint64_t	*ptr;
+
 	char			seen;
-	char			*name;
+
+	uint64_t		cur, last;
+	double			t_cur, t_last;
+	double			chg, avg;
+
+	struct ma		ma_10, ma_100, ma_1000;
 };
 
-static VTAILQ_HEAD(, pt) pthead = VTAILQ_HEAD_INITIALIZER(pthead);
+static VTAILQ_HEAD(, pt) ptlist = VTAILQ_HEAD_INITIALIZER(ptlist);
+static int n_ptlist = 0;
+static int n_ptarray = 0;
+static struct pt **ptarray = NULL;
+static const struct VSC_C_mgt *VSC_C_mgt = NULL;
+static const struct VSC_C_main *VSC_C_main = NULL;
+
+static int l_status, l_bar_t, l_points, l_bar_b, l_info;
+static int colw_name = COLW_NAME_MIN;
+static WINDOW *w_status = NULL;
+static WINDOW *w_bar_t = NULL;
+static WINDOW *w_points = NULL;
+static WINDOW *w_bar_b = NULL;
+static WINDOW *w_info = NULL;
+
+static int keep_running = 1;
+static int show_info = 1;
+static int hide_unseen = 1;
+static int page_start = 0;
+static int current = 0;
+static int rebuild = 0;
+static int redraw = 0;
+static int sample = 0;
+static double t_sample = 0.;
+static double interval = 1.;
+
+static void
+update_ma(struct ma *ma, double val)
+{
+	AN(ma);
+	AN(ma->nmax);
+	if (ma->n < ma->nmax)
+		ma->n++;
+	ma->acc += (val - ma->acc) / (double)ma->n;
+}
+
+static void
+update_position(void)
+{
+	int old_current, old_page_start;
+
+	old_current = current;
+	old_page_start = page_start;
+
+	if (n_ptarray == 0) {
+		current = 0;
+		page_start = 0;
+	} else {
+		if (current < 0)
+			current = 0;
+		if (current > n_ptarray - 1)
+			current = n_ptarray - 1;
+		if (current < page_start)
+			page_start = current;
+		if (current > page_start + (l_points - 1))
+			page_start = current - (l_points - 1);
+		if (page_start < 0)
+			page_start = 0;
+		if (page_start > n_ptarray - 1)
+			page_start = n_ptarray - 1;
+	}
+
+	if (current != old_current || page_start != old_page_start)
+		redraw = 1;
+}
+
+static void
+delete_pt_array(void)
+{
+	if (ptarray != NULL)
+		free(ptarray);
+	ptarray = NULL;
+	n_ptarray = 0;
+
+	update_position();
+}
+
+static void
+build_pt_array(void)
+{
+	int i;
+	struct pt *pt;
+	struct pt *pt_current = NULL;
+	int current_line = 0;
+
+	if (current < n_ptarray) {
+		pt_current = ptarray[current];
+		current_line = current - page_start;
+	}
+
+	if (ptarray != NULL)
+		delete_pt_array();
+	AZ(n_ptarray);
+	ptarray = calloc(n_ptlist, sizeof *ptarray);
+	AN(ptarray);
+
+	VTAILQ_FOREACH(pt, &ptlist, list) {
+		CHECK_OBJ_NOTNULL(pt, PT_MAGIC);
+		if (!pt->seen && hide_unseen)
+			continue;
+		assert(n_ptarray < n_ptlist);
+		ptarray[n_ptarray++] = pt;
+	}
+	assert(n_ptarray <= n_ptlist);
+
+	for (i = 0; pt_current != NULL && i < n_ptarray; i++)
+		if (ptarray[i] == pt_current)
+			break;
+	current = i;
+	page_start = current - current_line;
+	update_position();
+
+	rebuild = 0;
+	redraw = 1;
+}
+
+static void
+delete_pt_list(void)
+{
+	struct pt *pt;
+	unsigned i = 0;
+
+	delete_pt_array();
+
+	while (!VTAILQ_EMPTY(&ptlist)) {
+		pt = VTAILQ_FIRST(&ptlist);
+		CHECK_OBJ_NOTNULL(pt, PT_MAGIC);
+		VTAILQ_REMOVE(&ptlist, pt, list);
+		free(pt->name);
+		FREE_OBJ(pt);
+		i++;
+	}
+	assert(i == n_ptlist);
+	n_ptlist = 0;
+
+	update_position();
+}
+
+struct pt_priv {
+	unsigned		magic;
+#define PT_PRIV_MAGIC		0x34ACBAD6
+	VTAILQ_HEAD(, pt)	ptlist;
+	unsigned		n_ptlist;
+};
 
 static int
-do_curses_cb(void *priv, const struct VSC_point * const sp)
+build_pt_list_cb(void *priv, const struct VSC_point *vpt)
 {
+	struct pt_priv *pt_priv;
 	struct pt *pt;
 	char buf[128];
 
-	(void)priv;
-	if (sp == NULL)
+	if (vpt == NULL)
 		return (0);
-	assert(!strcmp(sp->desc->fmt, "uint64_t"));
 
-	pt = calloc(sizeof *pt, 1);
+	CAST_OBJ_NOTNULL(pt_priv, priv, PT_PRIV_MAGIC);
+
+	assert(!strcmp(vpt->desc->fmt, "uint64_t"));
+	snprintf(buf, sizeof buf, "%s.%s.%s", vpt->section->type,
+	    vpt->section->ident, vpt->desc->name);
+	buf[sizeof buf - 1] = '\0';
+
+	VTAILQ_FOREACH(pt, &ptlist, list) {
+		CHECK_OBJ_NOTNULL(pt, PT_MAGIC);
+		AN(pt->key);
+		if (strcmp(buf, pt->key))
+			continue;
+		VTAILQ_REMOVE(&ptlist, pt, list);
+		AN(n_ptlist);
+		n_ptlist--;
+		pt->vpt = vpt;
+		VTAILQ_INSERT_TAIL(&pt_priv->ptlist, pt, list);
+		pt_priv->n_ptlist++;
+		return (0);
+	}
+	AZ(pt);
+
+	ALLOC_OBJ(pt, PT_MAGIC);
 	AN(pt);
-	VTAILQ_INSERT_TAIL(&pthead, pt, next);
 
-	pt->ptr = sp->ptr;
-	pt->ref = *pt->ptr;
-	pt->flag = sp->desc->flag;
+	pt->key = strdup(buf);
+	AN(pt->key);
 
 	*buf = '\0';
-	if (strcmp(sp->section->fantom->type, "")) {
-		strcat(buf, sp->section->fantom->type);
+	if (strcmp(vpt->section->type, "")) {
+		strcat(buf, vpt->section->type);
 		strcat(buf, ".");
 	}
-	if (strcmp(sp->section->fantom->ident, "")) {
-		strcat(buf, sp->section->fantom->ident);
+	if (strcmp(vpt->section->ident, "")) {
+		strcat(buf, vpt->section->ident);
 		strcat(buf, ".");
 	}
-	strcat(buf, sp->desc->name);
-	strcat(buf, " - ");
-	strcat(buf, sp->desc->sdesc);
+	strcat(buf, vpt->desc->name);
 	pt->name = strdup(buf);
 	AN(pt->name);
+
+	pt->vpt = vpt;
+
+	pt->ptr = vpt->ptr;
+	pt->last = *pt->ptr;
+	pt->flag = vpt->desc->flag;
+	if (pt->flag == 'a')
+		pt->flag = 'c';
+	if (pt->flag == 'i')
+		pt->flag = 'g';
+
+	pt->ma_10.nmax = 10;
+	pt->ma_100.nmax = 100;
+	pt->ma_1000.nmax = 1000;
+
+	VTAILQ_INSERT_TAIL(&pt_priv->ptlist, pt, list);
+	pt_priv->n_ptlist++;
+
 	return (0);
 }
 
 static void
-prep_pts(struct VSM_data *vd)
+build_pt_list(struct VSM_data *vd)
 {
-	struct pt *pt, *pt2;
+	struct pt_priv pt_priv;
+	int i;
+	struct pt *pt_current = NULL;
+	int current_line = 0;
 
-	VTAILQ_FOREACH_SAFE(pt, &pthead, next, pt2) {
-		VTAILQ_REMOVE(&pthead, pt, next);
-		free(pt->name);
-		free(pt);
+	if (current < n_ptarray) {
+		pt_current = ptarray[current];
+		current_line = current - page_start;
 	}
 
-	(void)VSC_Iter(vd, do_curses_cb, NULL);
+	pt_priv.magic = PT_PRIV_MAGIC;
+	VTAILQ_INIT(&pt_priv.ptlist);
+	pt_priv.n_ptlist = 0;
+
+	(void)VSC_Iter(vd, build_pt_list_cb, &pt_priv);
+	delete_pt_list();
+	AN(VTAILQ_EMPTY(&ptlist));
+	AZ(n_ptlist);
+	VTAILQ_CONCAT(&ptlist, &pt_priv.ptlist, list);
+	n_ptlist = pt_priv.n_ptlist;
+	build_pt_array();
+
+	for (i = 0; pt_current != NULL && i < n_ptarray; i++)
+		if (ptarray[i] == pt_current)
+			break;
+	current = i;
+	page_start = current - current_line;
+	update_position();
 }
 
 static void
-myexp(double *acc, double val, unsigned *n, unsigned nmax)
+sample_points(void)
 {
+	struct pt *pt;
+
+	t_sample = VTIM_mono();
+	sample = 0;
+	redraw = 1;
+
+	VTAILQ_FOREACH(pt, &ptlist, list) {
+		AN(pt->vpt);
+		AN(pt->ptr);
+		if (*pt->ptr == 0 && !pt->seen)
+			continue;
+		if (!pt->seen) {
+			pt->seen = 1;
+			rebuild = 1;
+		}
+		pt->last = pt->cur;
+		pt->cur = *pt->ptr;
+		pt->t_last = pt->t_cur;
+		pt->t_cur = VTIM_mono();
 
-	if (*n < nmax)
-		(*n)++;
-	(*acc) += (val - *acc) / (double)*n;
+		if (pt->t_last)
+			pt->chg = (pt->cur - (intmax_t)pt->last) /
+			    (pt->t_cur - pt->t_last);
+
+		if (pt->flag == 'g') {
+			pt->avg = 0.;
+			update_ma(&pt->ma_10, pt->cur);
+			update_ma(&pt->ma_100, pt->cur);
+			update_ma(&pt->ma_1000, pt->cur);
+		} else if (pt->flag == 'c') {
+			if (VSC_C_main != NULL && VSC_C_main->uptime)
+				pt->avg = pt->cur / VSC_C_main->uptime;
+			else
+				pt->avg = 0.;
+			if (pt->t_last) {
+				update_ma(&pt->ma_10, pt->chg);
+				update_ma(&pt->ma_100, pt->chg);
+				update_ma(&pt->ma_1000, pt->chg);
+			}
+		}
+	}
 }
 
-void
-do_curses(struct VSM_data *vd, const struct VSC_C_main *VSC_C_main,
-    int delay)
+static void
+make_windows(void)
 {
-	intmax_t ju;
-	struct timeval tv;
-	double tt, lt, lhit, hit, lmiss, miss, hr, mr, ratio, up;
-	double a1, a2, a3;
-	unsigned n1, n2, n3;
-	time_t rt;
-	int ch, line;
-	struct pt *pt;
+	int Y, X;
+	int y;
+	int y_status, y_bar_t, y_points, y_bar_b, y_info;
 
-	(void)initscr();
-	AC(raw());
-	AC(noecho());
-	AC(nonl());
-	AC(intrflush(stdscr, FALSE));
-	(void)curs_set(0);	/* XXX: too many implementations are bogus */
-
-	while (1) {
-		/*
-		 * Initialization goes in outher loop
-		 */
-		prep_pts(vd);
-		AC(erase());
-		AC(refresh());
-
-		a1 = a2 = a3 = 0.0;
-		n1 = n2 = n3 = 0;
-		lt = 0;
-		lhit = 0;
-		lmiss = 0;
-
-		while (1) {
-			/*
-			 * Break to outher loop if we need to re-read file.
-			 * Only check if it looks like nothing is happening.
-			 */
-			AZ(gettimeofday(&tv, NULL));
-			tt = tv.tv_usec * 1e-6 + tv.tv_sec;
-			lt = tt - lt;
-
-			rt = VSC_C_main->uptime;
-			up = rt;
-
-			AC(mvprintw(0, 0, "%*s", COLS - 1, VSM_Name(vd)));
-			AC(mvprintw(0, 0, "%d+%02d:%02d:%02d", rt / 86400,
-			    (rt % 86400) / 3600, (rt % 3600) / 60, rt % 60));
-
-			hit = VSC_C_main->cache_hit;
-			miss = VSC_C_main->cache_miss;
-			hr = (hit - lhit) / lt;
-			mr = (miss - lmiss) / lt;
-			lhit = hit;
-			lmiss = miss;
-			if (hr + mr != 0) {
-				ratio = hr / (hr + mr);
-				myexp(&a1, ratio, &n1, 10);
-				myexp(&a2, ratio, &n2, 100);
-				myexp(&a3, ratio, &n3, 1000);
-			}
-			AC(mvprintw(1, 0, "Hitrate ratio: %8u %8u %8u",
-			    n1, n2, n3));
-			AC(mvprintw(2, 0, "Hitrate avg:   %8.4f %8.4f %8.4f",
-			    a1, a2, a3));
-
-			line = 3;
-			VTAILQ_FOREACH(pt, &pthead, next) {
-				ju = *pt->ptr;
-				if (ju == 0 && !pt->seen)
-					continue;
-				pt->seen = 1;
-				line++;
-				if (line >= LINES)
-					break;
-				if (pt->flag == 'a' || pt->flag == 'c') {
-					AC(mvprintw(line, 0,
-					    "%12ju %12.2f %12.2f %s\n",
-					    ju, (ju - (intmax_t)pt->ref)/lt,
-					    ju / up, pt->name));
-					pt->ref = ju;
-				} else if (pt->flag == 'b') {
-					AC(mvprintw(line, 0, "  %010.10jx <",
-					    (ju >> 24) & 0xffffffffffLL));
-					for (ch = 0x800000; ch; ch >>= 1)
-						if (ju & ch)
-							AC(addstr("V"));
-						else
-							AC(addstr("_"));
-					AC(addstr(" "));
-					AC(addstr(pt->name));
-				} else {
-					AC(mvprintw(line, 0,
-					    "%12ju %12s %12s %s\n",
-					    ju, ".  ", ".  ", pt->name));
-				}
-			}
-			lt = tt;
-			AC(refresh());
-			timeout(delay * 1000);
-			switch ((ch = getch())) {
-			case ERR:
-				break;
-#ifdef KEY_RESIZE
-			case KEY_RESIZE:
-				AC(erase());
-				break;
-#endif
-			case '\014': /* Ctrl-L */
-			case '\024': /* Ctrl-T */
-				AC(redrawwin(stdscr));
-				AC(refresh());
-				break;
-			case '\003': /* Ctrl-C */
-				AZ(raise(SIGINT));
-				break;
-			case '\032': /* Ctrl-Z */
-				AZ(raise(SIGTSTP));
-				break;
-			case '\021': /* Ctrl-Q */
-			case 'Q':
-			case 'q':
-				AC(endwin());
-				exit(0);
-			case '0':
-			case '1':
-			case '2':
-			case '3':
-			case '4':
-			case '5':
-			case '6':
-			case '7':
-			case '8':
-			case '9':
-				delay = 1U << (ch - '0');
-				break;
-			default:
-				AC(beep());
-				break;
+	if (w_status) {
+		delwin(w_status);
+		w_status = NULL;
+	}
+	if (w_bar_t) {
+		delwin(w_bar_t);
+		w_bar_t = NULL;
+	}
+	if (w_points) {
+		delwin(w_points);
+		w_points = NULL;
+	}
+	if (w_bar_b) {
+		delwin(w_bar_b);
+		w_bar_b = NULL;
+	}
+	if (w_info) {
+		delwin(w_info);
+		w_info = NULL;
+	}
+
+	Y = LINES;
+	X = COLS;
+
+	l_status = LINES_STATUS;
+	l_bar_t = LINES_BAR_T;
+	l_bar_b = LINES_BAR_B;
+	l_info = (show_info ? LINES_INFO : 0);
+	l_points = Y - (l_status + l_bar_t + l_bar_b + l_info);
+	if (l_points < LINES_POINTS_MIN) {
+		l_points += l_info;
+		l_info = 0;
+	}
+	if (l_points < LINES_POINTS_MIN)
+		l_points = LINES_POINTS_MIN;
+
+	y = 0;
+	y_status = y;
+	y += l_status;
+	y_bar_t = y;
+	y += l_bar_t;
+	y_points = y;
+	y += l_points;
+	y_bar_b = y;
+	y += l_bar_b;
+	y_info = y;
+	y += l_info;
+	assert(y >= Y);
+
+	w_status = newwin(l_status, X, y_status, 0);
+	AN(w_status);
+	nodelay(w_status, 1);
+	keypad(w_status, 1);
+	wnoutrefresh(w_status);
+
+	w_bar_t = newwin(l_bar_t, X, y_bar_t, 0);
+	AN(w_bar_t);
+	wbkgd(w_bar_t, A_REVERSE);
+	wnoutrefresh(w_bar_t);
+
+	w_points = newwin(l_points, X, y_points, 0);
+	AN(w_points);
+	wnoutrefresh(w_points);
+
+	w_bar_b = newwin(l_bar_b, X, y_bar_b, 0);
+	AN(w_bar_b);
+	wbkgd(w_bar_b, A_REVERSE);
+	wnoutrefresh(w_bar_b);
+
+	if (l_info) {
+		w_info = newwin(l_info, X, y_info, 0);
+		AN(w_info);
+		wnoutrefresh(w_info);
+	}
+
+	if (X - COLW_NAME_MIN > N_COL * COLW)
+		colw_name = X - (N_COL * COLW);
+	else
+		colw_name = COLW_NAME_MIN;
+
+	redraw = 1;
+}
+
+static void
+draw_status(void)
+{
+	time_t up_mgt = 0;
+	time_t up_chld = 0;
+
+	AN(w_status);
+
+	werase(w_status);
+	if (VSC_C_mgt != NULL)
+		up_mgt = VSC_C_mgt->uptime;
+	if (VSC_C_main != NULL)
+		up_chld = VSC_C_main->uptime;
+
+	mvwprintw(w_status, 0, 0, "Uptime mgt:   %d+%02d:%02d:%02d",
+	    up_mgt / 86400, (up_mgt % 86400) / 3600, (up_mgt % 3600) / 60,
+	    up_mgt % 60);
+	mvwprintw(w_status, 1, 0, "Uptime child: %d+%02d:%02d:%02d",
+	    up_chld / 86400, (up_chld % 86400) / 3600, (up_chld % 3600) / 60,
+	    up_chld % 60);
+
+	wnoutrefresh(w_status);
+}
+
+static void
+draw_bar_t(void)
+{
+	int X, x;
+	enum {
+		COL_CUR,
+		COL_CHG,
+		COL_AVG,
+		COL_MA10,
+		COL_MA100,
+		COL_MA1000,
+		COL_LAST
+	} col;
+
+	AN(w_bar_t);
+
+	X = getmaxx(w_bar_t);
+	x = 0;
+	werase(w_bar_t);
+	if (page_start > 0)
+		mvwaddch(w_bar_t, 0, x, ACS_UARROW);
+	x += 2;
+	mvwprintw(w_bar_t, 0, x, "%.*s", colw_name - 2, "NAME");
+	x += colw_name - 2;
+	col = 0;
+	while (col < COL_LAST) {
+		if (X - x < COLW)
+			break;
+		switch (col) {
+		case COL_CUR:
+			mvwprintw(w_bar_t, 0, x, " %12.12s", "CURRENT");
+			break;
+		case COL_CHG:
+			mvwprintw(w_bar_t, 0, x, " %12.12s", "CHANGE");
+			break;
+		case COL_AVG:
+			mvwprintw(w_bar_t, 0, x, " %12.12s", "AVERAGE");
+			break;
+		case COL_MA10:
+			mvwprintw(w_bar_t, 0, x, " %12.12s", "AVG_10");
+			break;
+		case COL_MA100:
+			mvwprintw(w_bar_t, 0, x, " %12.12s", "AVG_100");
+			break;
+		case COL_MA1000:
+			mvwprintw(w_bar_t, 0, x, " %12.12s", "AVG_1000");
+			break;
+		default:
+			break;
+		}
+		x += COLW;
+		col++;
+	}
+
+	wnoutrefresh(w_bar_t);
+}
+
+static void
+draw_line_default(WINDOW *w, int y, int x, int X, struct pt *pt)
+{
+	enum {
+		COL_CUR,
+		COL_CHG,
+		COL_AVG,
+		COL_MA10,
+		COL_MA100,
+		COL_MA1000,
+		COL_LAST
+	} col;
+
+	AN(w);
+	AN(pt);
+
+	col = 0;
+	while (col < COL_LAST) {
+		if (X - x < COLW)
+			break;
+		switch (col) {
+		case COL_CUR:
+			mvwprintw(w, y, x, " %12ju", (uintmax_t)pt->cur);
+			break;
+		case COL_CHG:
+			if (pt->t_last)
+				mvwprintw(w, y, x, " %12.2f", pt->chg);
+			else
+				mvwprintw(w, y, x, " %12s", ".  ");
+			break;
+		case COL_AVG:
+			if (pt->avg)
+				mvwprintw(w, y, x, " %12.2f", pt->avg);
+			else
+				mvwprintw(w, y, x, " %12s", ".  ");
+			break;
+		case COL_MA10:
+			mvwprintw(w, y, x, " %12.2f", pt->ma_10.acc);
+			break;
+		case COL_MA100:
+			mvwprintw(w, y, x, " %12.2f", pt->ma_100.acc);
+			break;
+		case COL_MA1000:
+			mvwprintw(w, y, x, " %12.2f", pt->ma_1000.acc);
+			break;
+		default:
+			break;
+		}
+		x += COLW;
+		col++;
+	}
+}
+
+static void
+draw_line_bitmap(WINDOW *w, int y, int x, int X, struct pt *pt)
+{
+	int ch;
+	enum {
+		COL_VAL,
+		COL_MAP,
+		COL_LAST
+	} col;
+
+	AN(w);
+	AN(pt);
+	assert(pt->flag == 'b');
+
+	col = 0;
+	while (col < COL_LAST) {
+		switch (col) {
+		case COL_VAL:
+			if (X - x < COLW)
+				return;
+			mvwprintw(w, y, x, "   %010.10jx",
+			    (pt->cur >> 24) & 0xffffffffffLL);
+			x += COLW;
+			break;
+		case COL_MAP:
+			if (X - x < 2 * COLW)
+				return;
+			x += (2 * COLW) - 24;
+			for (ch = 0x800000; ch; ch >>= 1) {
+				if (pt->cur & ch)
+					mvwaddch(w, y, x, 'V');
+				else
+					mvwaddch(w, y, x, '_');
+				x++;
 			}
+			break;
+		default:
+			x += COLW;
+			break;
+		}
+		col++;
+	}
+}
+
+static void
+draw_line(WINDOW *w, int y, struct pt *pt)
+{
+	int x, X;
+
+	assert(colw_name >= COLW_NAME_MIN);
+	X = getmaxx(w);
+	x = 0;
+	if (strlen(pt->name) > colw_name)
+		mvwprintw(w, y, x, "%.*s...", colw_name - 3, pt->name);
+	else
+		mvwprintw(w, y, x, "%.*s", colw_name, pt->name);
+	x += colw_name;
+
+	if (pt->flag == 'b')
+		draw_line_bitmap(w, y, x, X, pt);
+	else
+		draw_line_default(w, y, x, X, pt);
+}
+
+static void
+draw_points(void)
+{
+	int Y, X;
+	int line;
+	int n;
+
+	AN(w_points);
+
+	werase(w_points);
+	if (n_ptarray == 0) {
+		wnoutrefresh(w_points);
+		return;
+	}
+
+	assert(current >= 0);
+	assert(current < n_ptarray);
+	assert(page_start >= 0);
+	assert(page_start < n_ptarray);
+	assert(current >= page_start);
+	assert(current - page_start < l_points);
+
+	getmaxyx(w_points, Y, X);
+	(void)Y;
+	(void)X;
+	for (line = 0; line < l_points; line++) {
+		n = line + page_start;
+		if (n >= n_ptarray)
+			break;
+		if (n == current)
+			wattron(w_points, A_BOLD);
+		draw_line(w_points, line, ptarray[n]);
+		if (n == current)
+			wattroff(w_points, A_BOLD);
+	}
+	wnoutrefresh(w_points);
+}
+
+static void
+draw_bar_b(void)
+{
+	int x;
+
+	AN(w_bar_b);
+
+	x = 0;
+	werase(w_bar_b);
+	if (page_start + l_points < n_ptarray)
+		mvwaddch(w_bar_b, 0, x, ACS_DARROW);
+	x += 2;
+	if (current < n_ptarray - 1)
+		mvwprintw(w_bar_b, 0, x, "%s", ptarray[current]->name);
+
+	wnoutrefresh(w_bar_b);
+}
+
+static void
+draw_info(void)
+{
+	int Y, X;
+
+	if (w_info == NULL)
+		return;
+
+	getmaxyx(w_info, Y, X);
+	mvwprintw(w_info, 0, 0, "infotest Y=%d X=%d", Y, X);
+	wnoutrefresh(w_info);
+}
+
+static void
+draw_screen(void)
+{
+	draw_status();
+	draw_bar_t();
+	draw_points();
+	draw_bar_b();
+	draw_info();
+	doupdate();
+	redraw = 0;
+}
+
+static void
+handle_keypress(int ch)
+{
+	fprintf(stderr, "key: 0x%x\n", ch);
+
+	switch (ch) {
+	case KEY_UP:
+		if (current == 0)
+			return;
+		current--;
+		break;
+	case KEY_DOWN:
+		if (current == n_ptarray - 1)
+			return;
+		current++;
+		break;
+	case KEY_PPAGE:
+	case 'b':
+		current -= l_points;
+		page_start -= l_points;
+		break;
+	case KEY_NPAGE:
+	case ' ':
+		current += l_points;
+		if (page_start + l_points < n_ptarray - 1)
+			page_start += l_points;
+		break;
+	case 'g':
+		current = 0;
+		page_start = 0;
+		break;
+	case 'G':
+		current = n_ptarray - 1;
+		page_start = current - l_points + 1;
+		break;
+	case 'h':
+		hide_unseen = 1 - hide_unseen;
+		rebuild = 1;
+		break;
+	case 'q':
+	case 'Q':
+		keep_running = 0;
+		return;
+	case '\024':		/* Ctrl-T */
+		sample = 1;
+		return;
+	default:
+		return;
+	}
+
+	update_position();
+	redraw = 1;
+}
+
+void
+do_curses(struct VSM_data *vd, int delay)
+{
+	struct pollfd pollfd;
+	long timeout;
+	int ch;
+	double now;
+
+	AN(freopen("errlog", "w", stderr));
+	setbuf(stderr, NULL);
+
+	(void)delay;
+
+	initscr();
+	raw();
+	noecho();
+	nonl();
+	curs_set(0);
+
+	pollfd.fd = STDIN_FILENO;
+	pollfd.events = POLLIN;
+
+	make_windows();
+	doupdate();
+
+	VSC_C_mgt = VSC_Mgt(vd);
+	VSC_C_main = VSC_Main(vd);
+	while (keep_running) {
+		if (VSM_Abandoned(vd)) {
+			fprintf(stderr, "abandoned\n");
+			delete_pt_list();
+			VSM_Close(vd);
+			if (VSM_Open(vd) < 0)
+				fprintf(stderr, "VSM_Open failed: %s\n",
+				    VSM_Error(vd));
+		}
+		VSC_C_mgt = VSC_Mgt(vd);
+		VSC_C_main = VSC_Main(vd);
+		if (!VSC_IterValid(vd)) {
+			fprintf(stderr, "iter not valid\n");
+			build_pt_list(vd);
+		} else
+			fprintf(stderr, "iter valid\n");
+
+		now = VTIM_mono();
+		if (now - t_sample > interval)
+			sample = 1;
+		if (sample)
+			sample_points();
+		if (rebuild)
+			build_pt_array();
+		if (redraw)
+			draw_screen();
+
+		timeout = (t_sample + interval - now) * 1000;
+		if (timeout > 0)
+			(void)poll(&pollfd, 1, timeout);
+
+		switch (ch = wgetch(w_status)) {
+		case ERR:
+			break;
+		case KEY_RESIZE:
+			make_windows();
+			update_position();
+			break;
+		default:
+			handle_keypress(ch);
+			break;
 		}
 	}
+	VSM_Close(vd);
+	AZ(endwin());
+
+	fclose(stderr);
 }



More information about the varnish-commit mailing list