Home | History | Annotate | Line # | Download | only in tprof
      1  1.11   msaitoh /*	$NetBSD: tprof_top.c,v 1.11 2024/02/07 04:20:28 msaitoh Exp $	*/
      2   1.1       ryo 
      3   1.1       ryo /*-
      4  1.11   msaitoh  * Copyright (c) 2022 Ryo Shimizu
      5   1.1       ryo  * All rights reserved.
      6   1.1       ryo  *
      7   1.1       ryo  * Redistribution and use in source and binary forms, with or without
      8   1.1       ryo  * modification, are permitted provided that the following conditions
      9   1.1       ryo  * are met:
     10   1.1       ryo  * 1. Redistributions of source code must retain the above copyright
     11   1.1       ryo  *    notice, this list of conditions and the following disclaimer.
     12   1.1       ryo  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1       ryo  *    notice, this list of conditions and the following disclaimer in the
     14   1.1       ryo  *    documentation and/or other materials provided with the distribution.
     15   1.1       ryo  *
     16   1.1       ryo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     17   1.1       ryo  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18   1.1       ryo  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19   1.1       ryo  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     20   1.1       ryo  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21   1.1       ryo  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22   1.1       ryo  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23   1.1       ryo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     24   1.1       ryo  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     25   1.1       ryo  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26   1.1       ryo  * POSSIBILITY OF SUCH DAMAGE.
     27   1.1       ryo  */
     28   1.1       ryo 
     29   1.1       ryo #include <sys/cdefs.h>
     30   1.1       ryo #ifndef lint
     31  1.11   msaitoh __RCSID("$NetBSD: tprof_top.c,v 1.11 2024/02/07 04:20:28 msaitoh Exp $");
     32   1.1       ryo #endif /* not lint */
     33   1.1       ryo 
     34   1.1       ryo #include <sys/param.h>
     35   1.1       ryo #include <sys/types.h>
     36   1.4       ryo #include <sys/ioctl.h>
     37   1.1       ryo #include <sys/rbtree.h>
     38   1.4       ryo #include <sys/select.h>
     39   1.1       ryo #include <sys/time.h>
     40   1.1       ryo 
     41   1.4       ryo #include <assert.h>
     42   1.1       ryo #include <err.h>
     43   1.1       ryo #include <errno.h>
     44   1.1       ryo #include <fcntl.h>
     45   1.1       ryo #include <inttypes.h>
     46   1.1       ryo #include <math.h>
     47   1.1       ryo #include <signal.h>
     48   1.1       ryo #include <stdio.h>
     49  1.10       kre #include <stdbool.h>
     50   1.1       ryo #include <stdlib.h>
     51   1.1       ryo #include <string.h>
     52   1.4       ryo #include <term.h>
     53   1.4       ryo #include <termios.h>
     54   1.1       ryo #include <unistd.h>
     55   1.1       ryo #include <util.h>
     56   1.1       ryo 
     57   1.1       ryo #include <dev/tprof/tprof_ioctl.h>
     58   1.1       ryo #include "tprof.h"
     59   1.1       ryo #include "ksyms.h"
     60   1.1       ryo 
     61   1.3       ryo #define SAMPLE_MODE_ACCUMULATIVE	0
     62   1.3       ryo #define SAMPLE_MODE_INSTANTANEOUS	1
     63   1.3       ryo #define SAMPLE_MODE_NUM			2
     64   1.3       ryo 
     65   1.4       ryo #define LINESTR	"-------------------------------------------------------------"
     66   1.4       ryo #define SYMBOL_LEN			32	/* symbol and event name */
     67   1.4       ryo 
     68   1.3       ryo struct sample_elm {
     69   1.3       ryo 	struct rb_node node;
     70   1.3       ryo 	uint64_t addr;
     71   1.3       ryo 	const char *name;
     72   1.3       ryo 	uint32_t flags;
     73   1.3       ryo #define SAMPLE_ELM_FLAGS_USER	0x00000001
     74   1.3       ryo 	uint32_t num[SAMPLE_MODE_NUM];
     75   1.3       ryo 	uint32_t num_cpu[];	/* [SAMPLE_MODE_NUM][ncpu] */
     76   1.3       ryo #define SAMPLE_ELM_NUM_CPU(e, k)		\
     77   1.3       ryo 	((e)->num_cpu + (k) *  ncpu)
     78   1.3       ryo };
     79   1.3       ryo 
     80   1.3       ryo struct ptrarray {
     81   1.3       ryo 	void **pa_ptrs;
     82   1.3       ryo 	size_t pa_allocnum;
     83   1.3       ryo 	size_t pa_inuse;
     84   1.3       ryo };
     85   1.3       ryo 
     86   1.3       ryo static int opt_mode = SAMPLE_MODE_INSTANTANEOUS;
     87   1.3       ryo static int opt_userland = 0;
     88   1.3       ryo static int opt_showcounter = 0;
     89   1.3       ryo 
     90   1.3       ryo /* for display */
     91   1.4       ryo static char *term;
     92   1.3       ryo static struct winsize win;
     93   1.3       ryo static int nontty;
     94   1.4       ryo static struct termios termios_save;
     95   1.4       ryo static bool termios_saved;
     96   1.3       ryo static long top_interval = 1;
     97   1.4       ryo static bool do_redraw;
     98   1.4       ryo static u_int nshow;
     99   1.3       ryo 
    100   1.3       ryo /* for profiling and counting samples */
    101   1.3       ryo static sig_atomic_t sigalrm;
    102   1.1       ryo static struct sym **ksyms;
    103   1.1       ryo static size_t nksyms;
    104   1.1       ryo static u_int nevent;
    105   1.1       ryo static const char *eventname[TPROF_MAXCOUNTERS];
    106   1.3       ryo static size_t sizeof_sample_elm;
    107   1.3       ryo static rb_tree_t rb_tree_sample;
    108   1.3       ryo struct ptrarray sample_list[SAMPLE_MODE_NUM];
    109   1.3       ryo static u_int sample_n_kern[SAMPLE_MODE_NUM];
    110   1.3       ryo static u_int sample_n_user[SAMPLE_MODE_NUM];
    111   1.4       ryo static u_int sample_event_width = 7;
    112   1.4       ryo static u_int *sample_cpu_width;					/* [ncpu] */
    113   1.3       ryo static uint32_t *sample_n_kern_per_cpu[SAMPLE_MODE_NUM];	/* [ncpu] */
    114   1.3       ryo static uint32_t *sample_n_user_per_cpu[SAMPLE_MODE_NUM];	/* [ncpu] */
    115   1.3       ryo static uint64_t *sample_n_per_event[SAMPLE_MODE_NUM];		/* [nevent] */
    116   1.3       ryo static uint64_t *sample_n_per_event_cpu[SAMPLE_MODE_NUM];	/* [ncpu] */
    117   1.3       ryo 
    118   1.3       ryo /* raw event counter */
    119   1.3       ryo static uint64_t *counters;	/* counters[2][ncpu][nevent] */
    120   1.3       ryo static u_int counters_i;
    121   1.3       ryo 
    122   1.1       ryo static void
    123   1.4       ryo reset_cursor_pos(void)
    124   1.1       ryo {
    125   1.4       ryo 	int i;
    126   1.4       ryo 	char *p;
    127   1.4       ryo 
    128   1.4       ryo 	if (nontty || term == NULL)
    129   1.1       ryo 		return;
    130   1.4       ryo 
    131   1.4       ryo 	printf("\r");
    132   1.4       ryo 
    133   1.4       ryo 	/* cursor_up * n */
    134   1.4       ryo 	if ((p = tigetstr("cuu")) != NULL) {
    135   1.6       ryo 		putp(tparm(p, win.ws_row - 1, 0, 0, 0, 0, 0, 0, 0, 0));
    136   1.4       ryo 	} else if ((p = tigetstr("cuu1")) != NULL) {
    137   1.4       ryo 		for (i = win.ws_row - 1; i > 0; i--)
    138   1.6       ryo 			putp(p);
    139   1.4       ryo 	}
    140   1.1       ryo }
    141   1.1       ryo 
    142   1.1       ryo static void
    143   1.4       ryo clr_to_eol(void)
    144   1.1       ryo {
    145   1.4       ryo 	char *p;
    146   1.4       ryo 
    147   1.4       ryo 	if (nontty || term == NULL)
    148   1.1       ryo 		return;
    149   1.4       ryo 
    150   1.4       ryo 	if ((p = tigetstr("el")) != NULL)
    151   1.6       ryo 		putp(p);
    152   1.1       ryo }
    153   1.1       ryo 
    154   1.4       ryo /* newline, and clearing to end of line if needed */
    155   1.1       ryo static void
    156   1.4       ryo lim_newline(int *lim)
    157   1.1       ryo {
    158   1.4       ryo 	if (*lim >= 1)
    159   1.4       ryo 		clr_to_eol();
    160   1.4       ryo 
    161   1.4       ryo 	printf("\n");
    162   1.4       ryo 	*lim = win.ws_col;
    163   1.1       ryo }
    164   1.1       ryo 
    165   1.4       ryo static int
    166   1.4       ryo lim_printf(int *lim, const char *fmt, ...)
    167   1.1       ryo {
    168   1.4       ryo 	va_list ap;
    169   1.4       ryo 	size_t written;
    170   1.4       ryo 	char *p;
    171   1.4       ryo 
    172   1.4       ryo 	if (*lim <= 0)
    173   1.4       ryo 		return 0;
    174   1.4       ryo 
    175   1.8  christos 	p = malloc(*lim + 1);
    176   1.8  christos 	if (p == NULL)
    177   1.8  christos 		return -1;
    178   1.4       ryo 
    179   1.4       ryo 	va_start(ap, fmt);
    180   1.4       ryo 	vsnprintf(p, *lim + 1, fmt, ap);
    181   1.4       ryo 	va_end(ap);
    182   1.4       ryo 
    183   1.4       ryo 	written = strlen(p);
    184   1.4       ryo 	if (written == 0) {
    185   1.8  christos 		free(p);
    186   1.4       ryo 		*lim = 0;
    187   1.4       ryo 		return 0;
    188   1.4       ryo 	}
    189   1.4       ryo 
    190   1.4       ryo 	fwrite(p, written, 1, stdout);
    191   1.4       ryo 	*lim -= written;
    192   1.4       ryo 
    193   1.8  christos 	free(p);
    194   1.4       ryo 	return written;
    195   1.1       ryo }
    196   1.1       ryo 
    197   1.1       ryo static void
    198   1.1       ryo sigwinch_handler(int signo)
    199   1.1       ryo {
    200   1.4       ryo 	char *p;
    201   1.4       ryo 
    202   1.4       ryo 	win.ws_col = tigetnum("lines");
    203   1.4       ryo 	win.ws_row = tigetnum("cols");
    204   1.4       ryo 
    205   1.1       ryo 	nontty = ioctl(STDOUT_FILENO, TIOCGWINSZ, &win);
    206   1.4       ryo 	if (nontty != 0) {
    207   1.4       ryo 		nontty = !isatty(STDOUT_FILENO);
    208   1.4       ryo 		win.ws_col = 65535;
    209   1.4       ryo 		win.ws_row = 65535;
    210   1.4       ryo 	}
    211   1.4       ryo 
    212   1.4       ryo 	if ((p = getenv("LINES")) != NULL)
    213   1.4       ryo 		win.ws_row = strtoul(p, NULL, 0);
    214   1.4       ryo 	if ((p = getenv("COLUMNS")) != NULL)
    215   1.4       ryo 		win.ws_col = strtoul(p, NULL, 0);
    216   1.4       ryo 
    217   1.4       ryo 	do_redraw = true;
    218   1.4       ryo }
    219   1.4       ryo 
    220   1.4       ryo static void
    221   1.4       ryo tty_setup(void)
    222   1.4       ryo {
    223   1.4       ryo 	struct termios termios;
    224   1.4       ryo 
    225   1.4       ryo 	term = getenv("TERM");
    226   1.4       ryo 	if (term != NULL)
    227   1.4       ryo 		setupterm(term, 0, NULL);
    228   1.4       ryo 
    229   1.4       ryo 	sigwinch_handler(0);
    230   1.4       ryo 
    231   1.4       ryo 	if (tcgetattr(STDOUT_FILENO, &termios_save) == 0) {
    232   1.4       ryo 		termios_saved = true;
    233   1.4       ryo 
    234   1.4       ryo 		/* stty cbreak */
    235   1.4       ryo 		termios = termios_save;
    236   1.4       ryo 		termios.c_iflag |= BRKINT|IXON|IMAXBEL;
    237   1.4       ryo 		termios.c_oflag |= OPOST;
    238   1.4       ryo 		termios.c_lflag |= ISIG|IEXTEN;
    239   1.4       ryo 		termios.c_lflag &= ~(ICANON|ECHO);
    240   1.4       ryo 		tcsetattr(STDOUT_FILENO, TCSADRAIN, &termios);
    241   1.4       ryo 	}
    242   1.4       ryo }
    243   1.4       ryo 
    244   1.4       ryo static void
    245   1.4       ryo tty_restore(void)
    246   1.4       ryo {
    247   1.4       ryo 	if (termios_saved) {
    248   1.4       ryo 		tcsetattr(STDOUT_FILENO, TCSADRAIN, &termios_save);
    249   1.4       ryo 		termios_saved = false;
    250   1.4       ryo 	}
    251   1.4       ryo }
    252   1.4       ryo 
    253   1.4       ryo static void
    254   1.4       ryo sigtstp_handler(int signo)
    255   1.4       ryo {
    256   1.4       ryo 	tty_restore();
    257   1.4       ryo 
    258   1.4       ryo 	signal(SIGWINCH, SIG_DFL);
    259   1.4       ryo 	signal(SIGINT, SIG_DFL);
    260   1.4       ryo 	signal(SIGQUIT, SIG_DFL);
    261   1.4       ryo 	signal(SIGTERM, SIG_DFL);
    262   1.4       ryo 	signal(SIGTSTP, SIG_DFL);
    263   1.4       ryo 	kill(0, SIGTSTP);
    264   1.4       ryo 	nshow = 0;
    265   1.1       ryo }
    266   1.1       ryo 
    267   1.1       ryo static void
    268   1.1       ryo sigalrm_handler(int signo)
    269   1.1       ryo {
    270   1.1       ryo 	sigalrm = 1;
    271   1.1       ryo }
    272   1.1       ryo 
    273   1.6       ryo __dead static void
    274   1.4       ryo die(int signo)
    275   1.4       ryo {
    276   1.4       ryo 	tty_restore();
    277   1.4       ryo 	printf("\n");
    278   1.4       ryo 
    279   1.4       ryo 	exit(EXIT_SUCCESS);
    280   1.4       ryo }
    281   1.4       ryo 
    282   1.6       ryo __dead static void
    283   1.4       ryo die_errc(int status, int code, const char *fmt, ...)
    284   1.4       ryo {
    285   1.4       ryo 	va_list ap;
    286   1.4       ryo 
    287   1.4       ryo 	tty_restore();
    288   1.4       ryo 
    289   1.4       ryo 	va_start(ap, fmt);
    290   1.4       ryo 	if (code == 0)
    291   1.4       ryo 		verrx(status, fmt, ap);
    292   1.4       ryo 	else
    293   1.4       ryo 		verrc(status, code, fmt, ap);
    294   1.4       ryo 	va_end(ap);
    295   1.4       ryo }
    296   1.4       ryo 
    297   1.4       ryo static void
    298   1.3       ryo ptrarray_push(struct ptrarray *ptrarray, void *ptr)
    299   1.3       ryo {
    300   1.3       ryo 	int error;
    301   1.3       ryo 
    302   1.3       ryo 	if (ptrarray->pa_inuse >= ptrarray->pa_allocnum) {
    303   1.3       ryo 		/* increase buffer */
    304   1.3       ryo 		ptrarray->pa_allocnum += 1024;
    305   1.3       ryo 		error = reallocarr(&ptrarray->pa_ptrs, ptrarray->pa_allocnum,
    306   1.3       ryo 		    sizeof(*ptrarray->pa_ptrs));
    307   1.3       ryo 		if (error != 0)
    308   1.4       ryo 			die_errc(EXIT_FAILURE, error, "rellocarr failed");
    309   1.3       ryo 	}
    310   1.3       ryo 	ptrarray->pa_ptrs[ptrarray->pa_inuse++] = ptr;
    311   1.3       ryo }
    312   1.3       ryo 
    313   1.3       ryo static void
    314   1.3       ryo ptrarray_iterate(struct ptrarray *ptrarray, void (*ifunc)(void *))
    315   1.3       ryo {
    316   1.3       ryo 	size_t i;
    317   1.1       ryo 
    318   1.3       ryo 	for (i = 0; i < ptrarray->pa_inuse; i++) {
    319   1.3       ryo 		(*ifunc)(ptrarray->pa_ptrs[i]);
    320   1.3       ryo 	}
    321   1.3       ryo }
    322   1.1       ryo 
    323   1.3       ryo static void
    324   1.3       ryo ptrarray_clear(struct ptrarray *ptrarray)
    325   1.3       ryo {
    326   1.3       ryo 	ptrarray->pa_inuse = 0;
    327   1.3       ryo }
    328   1.1       ryo 
    329   1.1       ryo static int
    330   1.1       ryo sample_compare_key(void *ctx, const void *n1, const void *keyp)
    331   1.1       ryo {
    332   1.1       ryo 	const struct sample_elm *a1 = n1;
    333   1.1       ryo 	const struct sample_elm *a2 = (const struct sample_elm *)keyp;
    334   1.1       ryo 	return a1->addr - a2->addr;
    335   1.1       ryo }
    336   1.1       ryo 
    337   1.1       ryo static signed int
    338   1.1       ryo sample_compare_nodes(void *ctx, const void *n1, const void *n2)
    339   1.1       ryo {
    340   1.1       ryo 	const struct addr *a2 = n2;
    341   1.1       ryo 	return sample_compare_key(ctx, n1, a2);
    342   1.1       ryo }
    343   1.1       ryo 
    344   1.1       ryo static const rb_tree_ops_t sample_ops = {
    345   1.1       ryo 	.rbto_compare_nodes = sample_compare_nodes,
    346   1.1       ryo 	.rbto_compare_key = sample_compare_key
    347   1.1       ryo };
    348   1.1       ryo 
    349   1.3       ryo static u_int
    350   1.3       ryo n_align(u_int n, u_int align)
    351   1.3       ryo {
    352   1.3       ryo 	return (n + align - 1) / align * align;
    353   1.3       ryo }
    354   1.3       ryo 
    355   1.1       ryo static void
    356   1.1       ryo sample_init(void)
    357   1.1       ryo {
    358   1.3       ryo 	const struct sample_elm *e;
    359   1.4       ryo 	int l, mode, n;
    360   1.4       ryo 	u_int size;
    361   1.4       ryo 	char buf[16];
    362   1.3       ryo 
    363   1.4       ryo 	size = sizeof(struct sample_elm) +
    364   1.3       ryo 	    sizeof(e->num_cpu[0]) * SAMPLE_MODE_NUM * ncpu;
    365   1.3       ryo 	sizeof_sample_elm = n_align(size, __alignof(struct sample_elm));
    366   1.3       ryo 
    367   1.4       ryo 	sample_cpu_width = ecalloc(1, sizeof(*sample_cpu_width) * ncpu);
    368   1.4       ryo 	for (n = 0; n < ncpu; n++) {
    369   1.4       ryo 		sample_cpu_width[n] = 5;
    370   1.4       ryo 		l = snprintf(buf, sizeof(buf), "CPU%d", n);
    371   1.4       ryo 		if (sample_cpu_width[n] < (u_int)l)
    372   1.4       ryo 			sample_cpu_width[n] = l;
    373   1.4       ryo 	}
    374   1.4       ryo 
    375   1.3       ryo 	for (mode = 0; mode < SAMPLE_MODE_NUM; mode++) {
    376   1.3       ryo 		sample_n_kern_per_cpu[mode] = ecalloc(1,
    377   1.3       ryo 		    sizeof(typeof(*sample_n_kern_per_cpu[mode])) * ncpu);
    378   1.3       ryo 		sample_n_user_per_cpu[mode] = ecalloc(1,
    379   1.3       ryo 		    sizeof(typeof(*sample_n_user_per_cpu[mode])) * ncpu);
    380   1.3       ryo 		sample_n_per_event[mode] = ecalloc(1,
    381   1.3       ryo 		    sizeof(typeof(*sample_n_per_event[mode])) * nevent);
    382   1.3       ryo 		sample_n_per_event_cpu[mode] = ecalloc(1,
    383   1.3       ryo 		    sizeof(typeof(*sample_n_per_event_cpu[mode])) *
    384   1.3       ryo 		    nevent * ncpu);
    385   1.3       ryo 	}
    386   1.1       ryo }
    387   1.1       ryo 
    388   1.1       ryo static void
    389   1.3       ryo sample_clear_instantaneous(void *arg)
    390   1.1       ryo {
    391   1.3       ryo 	struct sample_elm *e = (void *)arg;
    392   1.1       ryo 
    393   1.3       ryo 	e->num[SAMPLE_MODE_INSTANTANEOUS] = 0;
    394   1.3       ryo 	memset(SAMPLE_ELM_NUM_CPU(e, SAMPLE_MODE_INSTANTANEOUS),
    395   1.3       ryo 	    0, sizeof(e->num_cpu[0]) * ncpu);
    396   1.1       ryo }
    397   1.1       ryo 
    398   1.3       ryo static void
    399   1.3       ryo sample_reset(bool reset_accumulative)
    400   1.1       ryo {
    401   1.3       ryo 	int mode;
    402   1.3       ryo 
    403   1.3       ryo 	for (mode = 0; mode < SAMPLE_MODE_NUM; mode++) {
    404   1.3       ryo 		if (mode == SAMPLE_MODE_ACCUMULATIVE && !reset_accumulative)
    405   1.3       ryo 			continue;
    406   1.1       ryo 
    407   1.3       ryo 		sample_n_kern[mode] = 0;
    408   1.3       ryo 		sample_n_user[mode] = 0;
    409   1.3       ryo 		memset(sample_n_kern_per_cpu[mode], 0,
    410   1.3       ryo 		    sizeof(typeof(*sample_n_kern_per_cpu[mode])) * ncpu);
    411   1.3       ryo 		memset(sample_n_user_per_cpu[mode], 0,
    412   1.3       ryo 		    sizeof(typeof(*sample_n_user_per_cpu[mode])) * ncpu);
    413   1.3       ryo 		memset(sample_n_per_event[mode], 0,
    414   1.3       ryo 		    sizeof(typeof(*sample_n_per_event[mode])) * nevent);
    415   1.3       ryo 		memset(sample_n_per_event_cpu[mode], 0,
    416   1.3       ryo 		    sizeof(typeof(*sample_n_per_event_cpu[mode])) *
    417   1.3       ryo 		    nevent * ncpu);
    418   1.1       ryo 	}
    419   1.1       ryo 
    420   1.3       ryo 	if (reset_accumulative) {
    421   1.3       ryo 		rb_tree_init(&rb_tree_sample, &sample_ops);
    422   1.3       ryo 		ptrarray_iterate(&sample_list[SAMPLE_MODE_ACCUMULATIVE], free);
    423   1.3       ryo 		ptrarray_clear(&sample_list[SAMPLE_MODE_ACCUMULATIVE]);
    424   1.3       ryo 		ptrarray_clear(&sample_list[SAMPLE_MODE_INSTANTANEOUS]);
    425   1.3       ryo 	} else {
    426   1.3       ryo 		ptrarray_iterate(&sample_list[SAMPLE_MODE_INSTANTANEOUS],
    427   1.3       ryo 		    sample_clear_instantaneous);
    428   1.3       ryo 		ptrarray_clear(&sample_list[SAMPLE_MODE_INSTANTANEOUS]);
    429   1.3       ryo 	}
    430   1.1       ryo }
    431   1.1       ryo 
    432   1.3       ryo static int __unused
    433   1.3       ryo sample_sortfunc_accumulative(const void *a, const void *b)
    434   1.1       ryo {
    435   1.3       ryo 	struct sample_elm * const *ea = a;
    436   1.3       ryo 	struct sample_elm * const *eb = b;
    437   1.3       ryo 	return (*eb)->num[SAMPLE_MODE_ACCUMULATIVE] -
    438   1.3       ryo 	    (*ea)->num[SAMPLE_MODE_ACCUMULATIVE];
    439   1.1       ryo }
    440   1.1       ryo 
    441   1.1       ryo static int
    442   1.3       ryo sample_sortfunc_instantaneous(const void *a, const void *b)
    443   1.1       ryo {
    444   1.3       ryo 	struct sample_elm * const *ea = a;
    445   1.3       ryo 	struct sample_elm * const *eb = b;
    446   1.3       ryo 	return (*eb)->num[SAMPLE_MODE_INSTANTANEOUS] -
    447   1.3       ryo 	    (*ea)->num[SAMPLE_MODE_INSTANTANEOUS];
    448   1.1       ryo }
    449   1.1       ryo 
    450   1.1       ryo static void
    451   1.3       ryo sample_sort_accumulative(void)
    452   1.1       ryo {
    453   1.3       ryo 	qsort(sample_list[SAMPLE_MODE_ACCUMULATIVE].pa_ptrs,
    454   1.3       ryo 	    sample_list[SAMPLE_MODE_ACCUMULATIVE].pa_inuse,
    455   1.3       ryo 	    sizeof(struct sample_elm *), sample_sortfunc_accumulative);
    456   1.3       ryo }
    457   1.3       ryo 
    458   1.3       ryo static void
    459   1.3       ryo sample_sort_instantaneous(void)
    460   1.3       ryo {
    461   1.3       ryo 	qsort(sample_list[SAMPLE_MODE_INSTANTANEOUS].pa_ptrs,
    462   1.3       ryo 	    sample_list[SAMPLE_MODE_INSTANTANEOUS].pa_inuse,
    463   1.3       ryo 	    sizeof(struct sample_elm *), sample_sortfunc_instantaneous);
    464   1.1       ryo }
    465   1.1       ryo 
    466   1.1       ryo static void
    467   1.1       ryo sample_collect(tprof_sample_t *s)
    468   1.1       ryo {
    469   1.1       ryo 	struct sample_elm *e, *o;
    470   1.1       ryo 	const char *name;
    471   1.1       ryo 	size_t symid;
    472   1.1       ryo 	uint64_t addr, offset;
    473   1.1       ryo 	uint32_t flags = 0;
    474   1.1       ryo 	uint32_t eventid, cpuid;
    475   1.3       ryo 	int mode;
    476   1.1       ryo 
    477   1.1       ryo 	eventid = __SHIFTOUT(s->s_flags, TPROF_SAMPLE_COUNTER_MASK);
    478   1.1       ryo 	cpuid = s->s_cpuid;
    479   1.1       ryo 
    480   1.3       ryo 	if (eventid >= nevent)	/* unknown event from tprof? */
    481   1.3       ryo 		return;
    482   1.3       ryo 
    483   1.3       ryo 	for (mode = 0; mode < SAMPLE_MODE_NUM; mode++) {
    484   1.3       ryo 		sample_n_per_event[mode][eventid]++;
    485   1.3       ryo 		sample_n_per_event_cpu[mode][nevent * cpuid + eventid]++;
    486   1.3       ryo 	}
    487   1.1       ryo 
    488   1.1       ryo 	if ((s->s_flags & TPROF_SAMPLE_INKERNEL) == 0) {
    489   1.3       ryo 		sample_n_user[SAMPLE_MODE_ACCUMULATIVE]++;
    490   1.3       ryo 		sample_n_user[SAMPLE_MODE_INSTANTANEOUS]++;
    491   1.3       ryo 		sample_n_user_per_cpu[SAMPLE_MODE_ACCUMULATIVE][cpuid]++;
    492   1.3       ryo 		sample_n_user_per_cpu[SAMPLE_MODE_INSTANTANEOUS][cpuid]++;
    493   1.1       ryo 
    494   1.1       ryo 		name = NULL;
    495   1.1       ryo 		addr = s->s_pid;	/* XXX */
    496   1.1       ryo 		flags |= SAMPLE_ELM_FLAGS_USER;
    497   1.1       ryo 
    498   1.1       ryo 		if (!opt_userland)
    499   1.1       ryo 			return;
    500   1.1       ryo 	} else {
    501   1.3       ryo 		sample_n_kern[SAMPLE_MODE_ACCUMULATIVE]++;
    502   1.3       ryo 		sample_n_kern[SAMPLE_MODE_INSTANTANEOUS]++;
    503   1.3       ryo 		sample_n_kern_per_cpu[SAMPLE_MODE_ACCUMULATIVE][cpuid]++;
    504   1.3       ryo 		sample_n_kern_per_cpu[SAMPLE_MODE_INSTANTANEOUS][cpuid]++;
    505   1.1       ryo 
    506   1.1       ryo 		name = ksymlookup(s->s_pc, &offset, &symid);
    507   1.1       ryo 		if (name != NULL) {
    508   1.1       ryo 			addr = ksyms[symid]->value;
    509   1.1       ryo 		} else {
    510   1.1       ryo 			addr = s->s_pc;
    511   1.1       ryo 		}
    512   1.1       ryo 	}
    513   1.1       ryo 
    514   1.3       ryo 	e = ecalloc(1, sizeof_sample_elm);
    515   1.1       ryo 	e->addr = addr;
    516   1.1       ryo 	e->name = name;
    517   1.1       ryo 	e->flags = flags;
    518   1.3       ryo 	e->num[SAMPLE_MODE_ACCUMULATIVE] = 1;
    519   1.3       ryo 	e->num[SAMPLE_MODE_INSTANTANEOUS] = 1;
    520   1.3       ryo 	SAMPLE_ELM_NUM_CPU(e, SAMPLE_MODE_ACCUMULATIVE)[cpuid] = 1;
    521   1.3       ryo 	SAMPLE_ELM_NUM_CPU(e, SAMPLE_MODE_INSTANTANEOUS)[cpuid] = 1;
    522   1.1       ryo 	o = rb_tree_insert_node(&rb_tree_sample, e);
    523   1.3       ryo 	if (o == e) {
    524   1.3       ryo 		/* new symbol. add to list for sort */
    525   1.3       ryo 		ptrarray_push(&sample_list[SAMPLE_MODE_ACCUMULATIVE], o);
    526   1.3       ryo 		ptrarray_push(&sample_list[SAMPLE_MODE_INSTANTANEOUS], o);
    527   1.3       ryo 	} else {
    528   1.1       ryo 		/* already exists */
    529   1.3       ryo 		free(e);
    530   1.3       ryo 
    531   1.3       ryo 		o->num[SAMPLE_MODE_ACCUMULATIVE]++;
    532   1.3       ryo 		if (o->num[SAMPLE_MODE_INSTANTANEOUS]++ == 0) {
    533   1.3       ryo 			/* new instantaneous symbols. add to list for sort */
    534   1.3       ryo 			ptrarray_push(&sample_list[SAMPLE_MODE_INSTANTANEOUS],
    535   1.3       ryo 			    o);
    536   1.3       ryo 		}
    537   1.3       ryo 		SAMPLE_ELM_NUM_CPU(o, SAMPLE_MODE_ACCUMULATIVE)[cpuid]++;
    538   1.3       ryo 		SAMPLE_ELM_NUM_CPU(o, SAMPLE_MODE_INSTANTANEOUS)[cpuid]++;
    539   1.1       ryo 	}
    540   1.1       ryo }
    541   1.1       ryo 
    542   1.1       ryo static void
    543   1.4       ryo show_tprof_stat(int *lim)
    544   1.1       ryo {
    545   1.1       ryo 	static struct tprof_stat tsbuf[2], *ts0, *ts;
    546   1.1       ryo 	static u_int ts_i = 0;
    547   1.4       ryo 	static int tprofstat_width[6];
    548   1.4       ryo 	int ret, l;
    549   1.4       ryo 	char tmpbuf[128];
    550   1.1       ryo 
    551   1.1       ryo 	ts0 = &tsbuf[ts_i++ & 1];
    552   1.1       ryo 	ts = &tsbuf[ts_i & 1];
    553   1.1       ryo 	ret = ioctl(devfd, TPROF_IOC_GETSTAT, ts);
    554   1.1       ryo 	if (ret == -1)
    555   1.4       ryo 		die_errc(EXIT_FAILURE, errno, "TPROF_IOC_GETSTAT");
    556   1.1       ryo 
    557   1.4       ryo #define TS_PRINT(idx, label, _m)					\
    558   1.4       ryo 	do {								\
    559   1.4       ryo 		__CTASSERT(idx < __arraycount(tprofstat_width));	\
    560   1.4       ryo 		lim_printf(lim, "%s", label);			\
    561   1.4       ryo 		l = snprintf(tmpbuf, sizeof(tmpbuf), "%"PRIu64, ts->_m);\
    562   1.4       ryo 		if (ts->_m != ts0->_m)					\
    563   1.4       ryo 			l += snprintf(tmpbuf + l, sizeof(tmpbuf) - l,	\
    564   1.4       ryo 			    "(+%"PRIu64")", ts->_m - ts0->_m);		\
    565   1.4       ryo 		assert(l < (int)sizeof(tmpbuf));			\
    566   1.4       ryo 		if (tprofstat_width[idx] < l)				\
    567   1.4       ryo 			tprofstat_width[idx] = l;			\
    568   1.4       ryo 		lim_printf(lim, "%-*.*s  ", tprofstat_width[idx],	\
    569   1.4       ryo 		    tprofstat_width[idx], tmpbuf);			\
    570   1.1       ryo 	} while (0)
    571   1.4       ryo 	lim_printf(lim, "tprof ");
    572   1.4       ryo 	TS_PRINT(0, "sample:", ts_sample);
    573   1.4       ryo 	TS_PRINT(1, "overflow:", ts_overflow);
    574   1.4       ryo 	TS_PRINT(2, "buf:", ts_buf);
    575   1.4       ryo 	TS_PRINT(3, "emptybuf:", ts_emptybuf);
    576   1.4       ryo 	TS_PRINT(4, "dropbuf:", ts_dropbuf);
    577   1.4       ryo 	TS_PRINT(5, "dropbuf_sample:", ts_dropbuf_sample);
    578   1.1       ryo }
    579   1.1       ryo 
    580   1.1       ryo static void
    581   1.1       ryo show_timestamp(void)
    582   1.1       ryo {
    583   1.1       ryo 	struct timeval tv;
    584   1.1       ryo 	gettimeofday(&tv, NULL);
    585   1.1       ryo 	printf("%-8.8s", &(ctime((time_t *)&tv.tv_sec)[11]));
    586   1.1       ryo }
    587   1.1       ryo 
    588   1.1       ryo static void
    589   1.1       ryo show_counters_alloc(void)
    590   1.1       ryo {
    591   1.3       ryo 	size_t sz = 2 * ncpu * nevent * sizeof(*counters);
    592   1.3       ryo 	counters = ecalloc(1, sz);
    593   1.1       ryo }
    594   1.1       ryo 
    595   1.1       ryo static void
    596   1.4       ryo show_counters(int *lim)
    597   1.1       ryo {
    598   1.1       ryo 	tprof_counts_t countsbuf;
    599   1.1       ryo 	uint64_t *cn[2], *c0, *c;
    600   1.1       ryo 	u_int i;
    601   1.1       ryo 	int n, ret;
    602   1.1       ryo 
    603   1.1       ryo 	cn[0] = counters;
    604   1.1       ryo 	cn[1] = counters + ncpu * nevent;
    605   1.1       ryo 	c0 = cn[counters_i++ & 1];
    606   1.1       ryo 	c = cn[counters_i & 1];
    607   1.1       ryo 
    608   1.1       ryo 	for (n = 0; n < ncpu; n++) {
    609   1.1       ryo 		countsbuf.c_cpu = n;
    610   1.1       ryo 		ret = ioctl(devfd, TPROF_IOC_GETCOUNTS, &countsbuf);
    611   1.1       ryo 		if (ret == -1)
    612   1.4       ryo 			die_errc(EXIT_FAILURE, errno, "TPROF_IOC_GETCOUNTS");
    613   1.1       ryo 
    614   1.1       ryo 		for (i = 0; i < nevent; i++)
    615   1.1       ryo 			c[n * nevent + i] = countsbuf.c_count[i];
    616   1.1       ryo 	}
    617   1.1       ryo 
    618   1.4       ryo 	if (do_redraw) {
    619   1.4       ryo 		lim_printf(lim, "%-22s", "Event counter (delta)");
    620   1.4       ryo 		for (n = 0; n < ncpu; n++) {
    621   1.4       ryo 			char cpuname[16];
    622   1.4       ryo 			snprintf(cpuname, sizeof(cpuname), "CPU%u", n);
    623   1.4       ryo 			lim_printf(lim, "%11s", cpuname);
    624   1.4       ryo 		}
    625   1.4       ryo 		lim_newline(lim);
    626   1.4       ryo 	} else {
    627   1.4       ryo 		printf("\n");
    628   1.1       ryo 	}
    629   1.1       ryo 
    630   1.1       ryo 	for (i = 0; i < nevent; i++) {
    631   1.4       ryo 		lim_printf(lim, "%-22.22s", eventname[i]);
    632   1.1       ryo 		for (n = 0; n < ncpu; n++) {
    633   1.4       ryo 			lim_printf(lim, "%11"PRIu64,
    634   1.1       ryo 			    c[n * nevent + i] - c0[n * nevent + i]);
    635   1.1       ryo 		}
    636   1.4       ryo 		lim_newline(lim);
    637   1.1       ryo 	}
    638   1.4       ryo 	lim_newline(lim);
    639   1.1       ryo }
    640   1.1       ryo 
    641   1.1       ryo static void
    642   1.4       ryo show_count_per_event(int *lim)
    643   1.1       ryo {
    644   1.1       ryo 	u_int i, nsample_total;
    645   1.4       ryo 	int n, l;
    646   1.4       ryo 	char buf[32];
    647   1.1       ryo 
    648   1.3       ryo 	nsample_total = sample_n_kern[opt_mode] + sample_n_user[opt_mode];
    649   1.4       ryo 	if (nsample_total == 0)
    650   1.4       ryo 		nsample_total = 1;
    651   1.4       ryo 
    652   1.4       ryo 	/* calc width in advance */
    653   1.4       ryo 	for (i = 0; i < nevent; i++) {
    654   1.4       ryo 		l = snprintf(buf, sizeof(buf), "%"PRIu64,
    655   1.4       ryo 		    sample_n_per_event[opt_mode][i]);
    656   1.5       ryo 		if (sample_event_width < (u_int)l) {
    657   1.4       ryo 			sample_event_width = l;
    658   1.5       ryo 			do_redraw = true;
    659   1.5       ryo 		}
    660   1.4       ryo 	}
    661   1.6       ryo 	for (n = 0; n < ncpu; n++) {
    662   1.6       ryo 		uint64_t sum = 0;
    663   1.6       ryo 		for (i = 0; i < nevent; i++)
    664   1.6       ryo 			sum += sample_n_per_event_cpu[opt_mode][nevent * n + i];
    665   1.6       ryo 		l = snprintf(buf, sizeof(buf), "%"PRIu64, sum);
    666   1.6       ryo 		if (sample_cpu_width[n] < (u_int)l) {
    667   1.6       ryo 			sample_cpu_width[n] = l;
    668   1.6       ryo 			do_redraw = true;
    669   1.4       ryo 		}
    670   1.4       ryo 	}
    671   1.4       ryo 
    672   1.4       ryo 	if (do_redraw) {
    673   1.6       ryo 		lim_printf(lim, "  Rate %*s %-*s",
    674   1.6       ryo 		    sample_event_width, "Sample#",
    675   1.6       ryo 		    SYMBOL_LEN, "Eventname");
    676   1.4       ryo 		for (n = 0; n < ncpu; n++) {
    677   1.4       ryo 			snprintf(buf, sizeof(buf), "CPU%d", n);
    678   1.4       ryo 			lim_printf(lim, " %*s", sample_cpu_width[n], buf);
    679   1.4       ryo 		}
    680   1.4       ryo 		lim_newline(lim);
    681   1.4       ryo 
    682   1.4       ryo 		lim_printf(lim, "------ %*.*s %*.*s",
    683   1.4       ryo 		    sample_event_width, sample_event_width, LINESTR,
    684   1.4       ryo 		    SYMBOL_LEN, SYMBOL_LEN, LINESTR);
    685   1.4       ryo 		for (n = 0; n < ncpu; n++) {
    686   1.4       ryo 			lim_printf(lim, " %*.*s",
    687   1.4       ryo 			    sample_cpu_width[n], sample_cpu_width[n], LINESTR);
    688   1.4       ryo 		}
    689   1.4       ryo 		lim_newline(lim);
    690   1.4       ryo 	} else {
    691   1.4       ryo 		printf("\n\n");
    692   1.4       ryo 	}
    693   1.1       ryo 
    694   1.1       ryo 	for (i = 0; i < nevent; i++) {
    695   1.3       ryo 		if (sample_n_per_event[opt_mode][i] >= nsample_total) {
    696   1.4       ryo 			lim_printf(lim, "%5.1f%%", 100.0 *
    697   1.4       ryo 			    sample_n_per_event[opt_mode][i] / nsample_total);
    698   1.1       ryo 		} else {
    699   1.4       ryo 			lim_printf(lim, "%5.2f%%", 100.0 *
    700   1.4       ryo 			    sample_n_per_event[opt_mode][i] / nsample_total);
    701   1.1       ryo 		}
    702   1.4       ryo 		lim_printf(lim, " %*"PRIu64" ", sample_event_width,
    703   1.4       ryo 		    sample_n_per_event[opt_mode][i]);
    704   1.1       ryo 
    705   1.4       ryo 		lim_printf(lim, "%-32.32s", eventname[i]);
    706   1.1       ryo 		for (n = 0; n < ncpu; n++) {
    707   1.4       ryo 			lim_printf(lim, " %*"PRIu64, sample_cpu_width[n],
    708   1.3       ryo 			    sample_n_per_event_cpu[opt_mode][nevent * n + i]);
    709   1.1       ryo 		}
    710   1.4       ryo 		lim_newline(lim);
    711   1.1       ryo 	}
    712   1.1       ryo }
    713   1.1       ryo 
    714   1.1       ryo static void
    715   1.1       ryo sample_show(void)
    716   1.1       ryo {
    717   1.1       ryo 	struct sample_elm *e;
    718   1.3       ryo 	struct ptrarray *samples;
    719   1.1       ryo 	u_int nsample_total;
    720   1.4       ryo 	int i, l, lim, n, ndisp;
    721   1.1       ryo 	char namebuf[32];
    722   1.1       ryo 	const char *name;
    723   1.1       ryo 
    724   1.4       ryo 	if (nshow++ == 0) {
    725   1.4       ryo 		printf("\n");
    726   1.4       ryo 		if (!nontty) {
    727   1.4       ryo 			signal(SIGWINCH, sigwinch_handler);
    728   1.4       ryo 			signal(SIGINT, die);
    729   1.4       ryo 			signal(SIGQUIT, die);
    730   1.4       ryo 			signal(SIGTERM, die);
    731   1.4       ryo 			signal(SIGTSTP, sigtstp_handler);
    732   1.4       ryo 
    733   1.4       ryo 			tty_setup();
    734   1.4       ryo 		}
    735   1.4       ryo 	} else {
    736   1.4       ryo 		reset_cursor_pos();
    737   1.4       ryo 	}
    738   1.4       ryo 
    739   1.1       ryo 	int margin_lines = 7;
    740   1.1       ryo 
    741   1.1       ryo 	margin_lines += 3 + nevent;	/* show_counter_per_event() */
    742   1.1       ryo 
    743   1.3       ryo 	if (opt_mode == SAMPLE_MODE_INSTANTANEOUS)
    744   1.3       ryo 		sample_sort_instantaneous();
    745   1.3       ryo 	else
    746   1.3       ryo 		sample_sort_accumulative();
    747   1.3       ryo 	samples = &sample_list[opt_mode];
    748   1.3       ryo 
    749   1.1       ryo 	if (opt_showcounter)
    750   1.1       ryo 		margin_lines += 2 + nevent;
    751   1.1       ryo 	if (opt_userland)
    752   1.1       ryo 		margin_lines += 1;
    753   1.1       ryo 
    754   1.3       ryo 	ndisp = samples->pa_inuse;
    755   1.1       ryo 	if (!nontty && ndisp > (win.ws_row - margin_lines))
    756   1.1       ryo 		ndisp = win.ws_row - margin_lines;
    757   1.1       ryo 
    758   1.4       ryo 	lim = win.ws_col;
    759   1.3       ryo 	if (opt_mode == SAMPLE_MODE_ACCUMULATIVE)
    760   1.4       ryo 		lim_printf(&lim, "[Accumulative mode] ");
    761   1.4       ryo 	show_tprof_stat(&lim);
    762   1.3       ryo 
    763   1.4       ryo 	if (lim >= 16) {
    764   1.4       ryo 		l = win.ws_col - lim;
    765   1.4       ryo 		if (!nontty) {
    766   1.4       ryo 			clr_to_eol();
    767   1.4       ryo 			for (; l <= win.ws_col - 17; l = ((l + 8) & -8))
    768   1.4       ryo 				printf("\t");
    769   1.4       ryo 		}
    770   1.4       ryo 		show_timestamp();
    771   1.4       ryo 	}
    772   1.4       ryo 	lim_newline(&lim);
    773   1.4       ryo 	lim_newline(&lim);
    774   1.1       ryo 
    775   1.4       ryo 	if (opt_showcounter)
    776   1.4       ryo 		show_counters(&lim);
    777   1.1       ryo 
    778   1.4       ryo 	show_count_per_event(&lim);
    779   1.4       ryo 	lim_newline(&lim);
    780   1.1       ryo 
    781   1.4       ryo 	if (do_redraw) {
    782   1.6       ryo 		lim_printf(&lim, "  Rate %*s %-*s",
    783   1.6       ryo 		    sample_event_width, "Sample#",
    784   1.6       ryo 		    SYMBOL_LEN, "Symbol");
    785   1.4       ryo 		for (n = 0; n < ncpu; n++) {
    786   1.1       ryo 			snprintf(namebuf, sizeof(namebuf), "CPU%d", n);
    787   1.4       ryo 			lim_printf(&lim, " %*s", sample_cpu_width[n], namebuf);
    788   1.1       ryo 		}
    789   1.4       ryo 		lim_newline(&lim);
    790   1.1       ryo 
    791   1.4       ryo 		lim_printf(&lim, "------ %*.*s %*.*s",
    792   1.4       ryo 		    sample_event_width, sample_event_width, LINESTR,
    793   1.4       ryo 		    SYMBOL_LEN, SYMBOL_LEN, LINESTR);
    794   1.4       ryo 		for (n = 0; n < ncpu; n++) {
    795   1.4       ryo 			lim_printf(&lim, " %*.*s", sample_cpu_width[n],
    796   1.4       ryo 			    sample_cpu_width[n], LINESTR);
    797   1.1       ryo 		}
    798   1.4       ryo 		lim_newline(&lim);
    799   1.4       ryo 	} else {
    800   1.4       ryo 		printf("\n\n");
    801   1.1       ryo 	}
    802   1.1       ryo 
    803   1.1       ryo 	for (i = 0; i < ndisp; i++) {
    804   1.3       ryo 		e = (struct sample_elm *)samples->pa_ptrs[i];
    805   1.1       ryo 		name = e->name;
    806   1.1       ryo 		if (name == NULL) {
    807   1.1       ryo 			if (e->flags & SAMPLE_ELM_FLAGS_USER) {
    808   1.3       ryo 				snprintf(namebuf, sizeof(namebuf),
    809   1.3       ryo 				    "<PID:%"PRIu64">", e->addr);
    810   1.1       ryo 			} else {
    811   1.3       ryo 				snprintf(namebuf, sizeof(namebuf),
    812   1.3       ryo 				    "0x%016"PRIx64, e->addr);
    813   1.1       ryo 			}
    814   1.1       ryo 			name = namebuf;
    815   1.1       ryo 		}
    816   1.1       ryo 
    817   1.3       ryo 		nsample_total = sample_n_kern[opt_mode];
    818   1.1       ryo 		if (opt_userland)
    819   1.3       ryo 			nsample_total += sample_n_user[opt_mode];
    820   1.1       ryo 		/*
    821   1.1       ryo 		 * even when only kernel mode events are configured,
    822   1.1       ryo 		 * interrupts may still occur in the user mode state.
    823   1.1       ryo 		 */
    824   1.1       ryo 		if (nsample_total == 0)
    825   1.1       ryo 			nsample_total = 1;
    826   1.1       ryo 
    827   1.3       ryo 		if (e->num[opt_mode] >= nsample_total) {
    828   1.4       ryo 			lim_printf(&lim, "%5.1f%%", 100.0 *
    829   1.4       ryo 			    e->num[opt_mode] / nsample_total);
    830   1.1       ryo 		} else {
    831   1.4       ryo 			lim_printf(&lim, "%5.2f%%", 100.0 *
    832   1.4       ryo 			    e->num[opt_mode] / nsample_total);
    833   1.1       ryo 		}
    834   1.4       ryo 		lim_printf(&lim, " %*u %-32.32s", sample_event_width,
    835   1.4       ryo 		    e->num[opt_mode], name);
    836   1.1       ryo 
    837   1.1       ryo 		for (n = 0; n < ncpu; n++) {
    838   1.3       ryo 			if (SAMPLE_ELM_NUM_CPU(e, opt_mode)[n] == 0) {
    839   1.4       ryo 				lim_printf(&lim, " %*s", sample_cpu_width[n],
    840   1.4       ryo 				    ".");
    841   1.3       ryo 			} else {
    842   1.4       ryo 				lim_printf(&lim, " %*u", sample_cpu_width[n],
    843   1.3       ryo 				    SAMPLE_ELM_NUM_CPU(e, opt_mode)[n]);
    844   1.3       ryo 			}
    845   1.1       ryo 		}
    846   1.4       ryo 		lim_newline(&lim);
    847   1.1       ryo 	}
    848   1.1       ryo 
    849   1.3       ryo 	if ((u_int)ndisp != samples->pa_inuse) {
    850   1.4       ryo 		lim_printf(&lim, "     : %*s (more %zu symbols omitted)",
    851   1.4       ryo 		    sample_event_width, ":", samples->pa_inuse - ndisp);
    852   1.4       ryo 		lim_newline(&lim);
    853   1.4       ryo 	} else if (!nontty) {
    854   1.1       ryo 		for (i = ndisp; i <= win.ws_row - margin_lines; i++) {
    855   1.1       ryo 			printf("~");
    856   1.4       ryo 			lim_newline(&lim);
    857   1.1       ryo 		}
    858   1.1       ryo 	}
    859   1.1       ryo 
    860   1.4       ryo 	if (do_redraw) {
    861   1.4       ryo 		lim_printf(&lim, "------ %*.*s %*.*s",
    862   1.4       ryo 		    sample_event_width, sample_event_width, LINESTR,
    863   1.4       ryo 		    SYMBOL_LEN, SYMBOL_LEN, LINESTR);
    864   1.4       ryo 		for (n = 0; n < ncpu; n++) {
    865   1.4       ryo 			lim_printf(&lim, " %*.*s",
    866   1.4       ryo 			    sample_cpu_width[n], sample_cpu_width[n], LINESTR);
    867   1.4       ryo 		}
    868   1.4       ryo 		lim_newline(&lim);
    869   1.4       ryo 	} else {
    870   1.4       ryo 		printf("\n");
    871   1.1       ryo 	}
    872   1.1       ryo 
    873   1.4       ryo 	lim_printf(&lim, "Total  %*u %-32.32s",
    874   1.4       ryo 	    sample_event_width, sample_n_kern[opt_mode], "in-kernel");
    875   1.1       ryo 	for (n = 0; n < ncpu; n++) {
    876   1.4       ryo 		lim_printf(&lim, " %*u", sample_cpu_width[n],
    877   1.4       ryo 		    sample_n_kern_per_cpu[opt_mode][n]);
    878   1.1       ryo 	}
    879   1.1       ryo 
    880   1.1       ryo 	if (opt_userland) {
    881   1.4       ryo 		lim_newline(&lim);
    882   1.4       ryo 		lim_printf(&lim, "       %*u %-32.32s",
    883   1.4       ryo 		    sample_event_width, sample_n_user[opt_mode], "userland");
    884   1.1       ryo 		for (n = 0; n < ncpu; n++) {
    885   1.4       ryo 			lim_printf(&lim, " %*u", sample_cpu_width[n],
    886   1.4       ryo 			    sample_n_user_per_cpu[opt_mode][n]);
    887   1.1       ryo 		}
    888   1.1       ryo 	}
    889   1.1       ryo 
    890   1.4       ryo 	if (nontty)
    891   1.4       ryo 		printf("\n");
    892   1.4       ryo 	else
    893   1.4       ryo 		clr_to_eol();
    894   1.1       ryo }
    895   1.1       ryo 
    896   1.1       ryo __dead static void
    897   1.1       ryo tprof_top_usage(void)
    898   1.1       ryo {
    899   1.3       ryo 	fprintf(stderr, "%s top [-acu] [-e name[,scale] [-e ...]]"
    900   1.3       ryo 	    " [-i interval]\n", getprogname());
    901   1.1       ryo 	exit(EXIT_FAILURE);
    902   1.1       ryo }
    903   1.1       ryo 
    904   1.6       ryo __dead void
    905   1.1       ryo tprof_top(int argc, char **argv)
    906   1.1       ryo {
    907   1.1       ryo 	tprof_param_t params[TPROF_MAXCOUNTERS];
    908   1.1       ryo 	struct itimerval it;
    909   1.4       ryo 	ssize_t tprof_bufsize, len;
    910   1.1       ryo 	u_int i;
    911   1.1       ryo 	int ch, ret;
    912   1.7       ryo 	char *tprof_buf, *p, *errmsg;
    913   1.4       ryo 	bool noinput = false;
    914   1.1       ryo 
    915   1.1       ryo 	memset(params, 0, sizeof(params));
    916   1.1       ryo 	nevent = 0;
    917   1.1       ryo 
    918   1.4       ryo 	while ((ch = getopt(argc, argv, "ace:i:L:u")) != -1) {
    919   1.1       ryo 		switch (ch) {
    920   1.3       ryo 		case 'a':
    921   1.3       ryo 			opt_mode = SAMPLE_MODE_ACCUMULATIVE;
    922   1.3       ryo 			break;
    923   1.1       ryo 		case 'c':
    924   1.1       ryo 			opt_showcounter = 1;
    925   1.1       ryo 			break;
    926   1.1       ryo 		case 'e':
    927   1.7       ryo 			if (tprof_parse_event(&params[nevent], optarg,
    928   1.7       ryo 			    TPROF_PARSE_EVENT_F_ALLOWSCALE,
    929   1.7       ryo 			    &eventname[nevent], &errmsg) != 0) {
    930   1.7       ryo 				die_errc(EXIT_FAILURE, 0, "%s", errmsg);
    931   1.1       ryo 			}
    932   1.1       ryo 			nevent++;
    933   1.1       ryo 			if (nevent > __arraycount(params) ||
    934   1.1       ryo 			    nevent > ncounters)
    935   1.4       ryo 				die_errc(EXIT_FAILURE, 0,
    936   1.4       ryo 				    "Too many events. Only a maximum of %d "
    937   1.4       ryo 				    "counters can be used.", ncounters);
    938   1.1       ryo 			break;
    939   1.1       ryo 		case 'i':
    940   1.1       ryo 			top_interval = strtol(optarg, &p, 10);
    941   1.1       ryo 			if (*p != '\0' || top_interval <= 0)
    942   1.4       ryo 				die_errc(EXIT_FAILURE, 0,
    943   1.4       ryo 				    "Bad/invalid interval: %s", optarg);
    944   1.1       ryo 			break;
    945   1.1       ryo 		case 'u':
    946   1.1       ryo 			opt_userland = 1;
    947   1.1       ryo 			break;
    948   1.1       ryo 		default:
    949   1.1       ryo 			tprof_top_usage();
    950   1.1       ryo 		}
    951   1.1       ryo 	}
    952   1.1       ryo 	argc -= optind;
    953   1.1       ryo 	argv += optind;
    954   1.1       ryo 
    955   1.1       ryo 	if (argc != 0)
    956   1.1       ryo 		tprof_top_usage();
    957   1.1       ryo 
    958   1.1       ryo 	if (nevent == 0) {
    959   1.9   msaitoh 		const char *defaultevent = tprof_cycle_event_name();
    960   1.1       ryo 		if (defaultevent == NULL)
    961   1.4       ryo 			die_errc(EXIT_FAILURE, 0, "cpu not supported");
    962   1.1       ryo 
    963   1.1       ryo 		tprof_event_lookup(defaultevent, &params[nevent]);
    964   1.1       ryo 		eventname[nevent] = defaultevent;
    965   1.1       ryo 		nevent++;
    966   1.1       ryo 	}
    967   1.1       ryo 
    968   1.3       ryo 	sample_init();
    969   1.1       ryo 	show_counters_alloc();
    970   1.1       ryo 
    971   1.1       ryo 	for (i = 0; i < nevent; i++) {
    972   1.1       ryo 		params[i].p_counter = i;
    973   1.1       ryo 		params[i].p_flags |= TPROF_PARAM_KERN | TPROF_PARAM_PROFILE;
    974   1.1       ryo 		if (opt_userland)
    975   1.1       ryo 			params[i].p_flags |= TPROF_PARAM_USER;
    976   1.1       ryo 		ret = ioctl(devfd, TPROF_IOC_CONFIGURE_EVENT, &params[i]);
    977   1.1       ryo 		if (ret == -1)
    978   1.4       ryo 			die_errc(EXIT_FAILURE, errno,
    979   1.4       ryo 			    "TPROF_IOC_CONFIGURE_EVENT: %s", eventname[i]);
    980   1.1       ryo 	}
    981   1.1       ryo 
    982   1.1       ryo 	tprof_countermask_t mask = TPROF_COUNTERMASK_ALL;
    983   1.1       ryo 	ret = ioctl(devfd, TPROF_IOC_START, &mask);
    984   1.1       ryo 	if (ret == -1)
    985   1.4       ryo 		die_errc(EXIT_FAILURE, errno, "TPROF_IOC_START");
    986   1.1       ryo 
    987   1.1       ryo 	ksyms = ksymload(&nksyms);
    988   1.1       ryo 
    989   1.4       ryo 	signal(SIGALRM, sigalrm_handler);
    990   1.1       ryo 
    991   1.1       ryo 	it.it_interval.tv_sec = it.it_value.tv_sec = top_interval;
    992   1.1       ryo 	it.it_interval.tv_usec = it.it_value.tv_usec = 0;
    993   1.1       ryo 	setitimer(ITIMER_REAL, &it, NULL);
    994   1.1       ryo 
    995   1.3       ryo 	sample_reset(true);
    996   1.1       ryo 	printf("collecting samples...");
    997   1.1       ryo 	fflush(stdout);
    998   1.1       ryo 
    999   1.6       ryo 	tprof_bufsize = sizeof(tprof_sample_t) * 1024 * 32;
   1000   1.3       ryo 	tprof_buf = emalloc(tprof_bufsize);
   1001   1.1       ryo 	do {
   1002   1.4       ryo 		bool force_update = false;
   1003   1.4       ryo 
   1004   1.6       ryo 		while (sigalrm == 0 && !force_update) {
   1005   1.4       ryo 			fd_set r;
   1006   1.4       ryo 			int nfound;
   1007   1.4       ryo 			char c;
   1008   1.4       ryo 
   1009   1.4       ryo 			FD_ZERO(&r);
   1010   1.4       ryo 			if (!noinput)
   1011   1.4       ryo 				FD_SET(STDIN_FILENO, &r);
   1012   1.4       ryo 			FD_SET(devfd, &r);
   1013   1.4       ryo 			nfound = select(devfd + 1, &r, NULL, NULL, NULL);
   1014   1.4       ryo 			if (nfound == -1) {
   1015   1.4       ryo 				if (errno == EINTR)
   1016   1.4       ryo 					break;
   1017   1.4       ryo 				die_errc(EXIT_FAILURE, errno, "select");
   1018   1.4       ryo 			}
   1019   1.4       ryo 
   1020   1.4       ryo 			if (FD_ISSET(STDIN_FILENO, &r)) {
   1021   1.4       ryo 				len = read(STDIN_FILENO, &c, 1);
   1022   1.4       ryo 				if (len <= 0) {
   1023   1.4       ryo 					noinput = true;
   1024   1.4       ryo 					continue;
   1025   1.4       ryo 				}
   1026   1.4       ryo 				switch (c) {
   1027   1.4       ryo 				case 0x0c:	/* ^L */
   1028   1.4       ryo 					do_redraw = true;
   1029   1.4       ryo 					break;
   1030   1.4       ryo 				case 'a':
   1031   1.4       ryo 					/* toggle mode */
   1032   1.4       ryo 					opt_mode = (opt_mode + 1) %
   1033   1.4       ryo 					    SAMPLE_MODE_NUM;
   1034   1.6       ryo 					do_redraw = true;
   1035   1.6       ryo 					break;
   1036   1.6       ryo 				case 'c':
   1037   1.6       ryo 					/* toggle mode */
   1038   1.6       ryo 					opt_showcounter ^= 1;
   1039   1.6       ryo 					do_redraw = true;
   1040   1.4       ryo 					break;
   1041   1.4       ryo 				case 'q':
   1042   1.4       ryo 					goto done;
   1043   1.4       ryo 				case 'z':
   1044   1.4       ryo 					sample_reset(true);
   1045   1.4       ryo 					break;
   1046   1.4       ryo 				default:
   1047   1.6       ryo 					continue;
   1048   1.4       ryo 				}
   1049   1.4       ryo 				force_update = true;
   1050   1.4       ryo 			}
   1051   1.4       ryo 
   1052   1.4       ryo 			if (FD_ISSET(devfd, &r)) {
   1053   1.4       ryo 				len = read(devfd, tprof_buf, tprof_bufsize);
   1054   1.4       ryo 				if (len == -1 && errno != EINTR)
   1055   1.4       ryo 					die_errc(EXIT_FAILURE, errno, "read");
   1056   1.4       ryo 				if (len > 0) {
   1057   1.4       ryo 					tprof_sample_t *s =
   1058   1.4       ryo 					    (tprof_sample_t *)tprof_buf;
   1059   1.4       ryo 					while (s <
   1060   1.4       ryo 					    (tprof_sample_t *)(tprof_buf + len))
   1061   1.4       ryo 						sample_collect(s++);
   1062   1.4       ryo 				}
   1063   1.1       ryo 			}
   1064   1.1       ryo 		}
   1065   1.1       ryo 		sigalrm = 0;
   1066   1.1       ryo 
   1067   1.1       ryo 		/* update screen */
   1068   1.1       ryo 		sample_show();
   1069   1.1       ryo 		fflush(stdout);
   1070   1.4       ryo 		do_redraw = false;
   1071   1.4       ryo 		if (force_update)
   1072   1.4       ryo 			continue;
   1073   1.1       ryo 
   1074   1.3       ryo 		sample_reset(false);
   1075   1.4       ryo 
   1076   1.1       ryo 	} while (!nontty);
   1077   1.1       ryo 
   1078   1.4       ryo  done:
   1079   1.4       ryo 	die(0);
   1080   1.1       ryo }
   1081