Module Name: src Committed By: ryo Date: Fri Dec 9 01:55:46 UTC 2022
Modified Files: src/usr.sbin/tprof: tprof.8 tprof_top.c Log Message: add accumulative mode. "tprof top -a" To generate a diff of this commit: cvs rdiff -u -r1.19 -r1.20 src/usr.sbin/tprof/tprof.8 cvs rdiff -u -r1.2 -r1.3 src/usr.sbin/tprof/tprof_top.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/tprof/tprof.8 diff -u src/usr.sbin/tprof/tprof.8:1.19 src/usr.sbin/tprof/tprof.8:1.20 --- src/usr.sbin/tprof/tprof.8:1.19 Thu Dec 1 00:43:27 2022 +++ src/usr.sbin/tprof/tprof.8 Fri Dec 9 01:55:46 2022 @@ -1,4 +1,4 @@ -.\" $NetBSD: tprof.8,v 1.19 2022/12/01 00:43:27 ryo Exp $ +.\" $NetBSD: tprof.8,v 1.20 2022/12/09 01:55:46 ryo Exp $ .\" .\" Copyright (c)2011 YAMAMOTO Takashi, .\" All rights reserved. @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 1, 2022 +.Dd December 9, 2022 .Dt TPROF 8 .Os .Sh NAME @@ -137,8 +137,7 @@ Per symbol. .Op Fl e Ar ... .Oc .Op Fl i Ar interval -.Op Fl c -.Op Fl u +.Op Fl acu .Xc Displays profiling results in real-time. .Ar name @@ -158,6 +157,10 @@ is specified, profiling is performed eve .Bl -tag -width XXintervalX -offset indent .It Fl i Ar interval set the update interval in seconds. The default value is 1. +.It Fl a +Starts in accumulation mode. The display is updated every +.Ar interval +second, but the values are accumulative. .It Fl c show the delta of the event counters. .It Fl u @@ -226,7 +229,9 @@ utility was written by .An YAMAMOTO Takashi . It was revamped by .An Maxime Villard -in 2018. +in 2018, and by +.An Ryo Shimizu +in 2022. .Sh CAVEATS The contents and representation of recorded samples are undocumented and will likely be changed for future releases of Index: src/usr.sbin/tprof/tprof_top.c diff -u src/usr.sbin/tprof/tprof_top.c:1.2 src/usr.sbin/tprof/tprof_top.c:1.3 --- src/usr.sbin/tprof/tprof_top.c:1.2 Thu Dec 1 03:32:24 2022 +++ src/usr.sbin/tprof/tprof_top.c Fri Dec 9 01:55:46 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: tprof_top.c,v 1.2 2022/12/01 03:32:24 ryo Exp $ */ +/* $NetBSD: tprof_top.c,v 1.3 2022/12/09 01:55:46 ryo Exp $ */ /*- * Copyright (c) 2022 Ryo Shimizu <r...@nerv.org> @@ -28,7 +28,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: tprof_top.c,v 1.2 2022/12/01 03:32:24 ryo Exp $"); +__RCSID("$NetBSD: tprof_top.c,v 1.3 2022/12/09 01:55:46 ryo Exp $"); #endif /* not lint */ #include <sys/param.h> @@ -37,7 +37,6 @@ __RCSID("$NetBSD: tprof_top.c,v 1.2 2022 #include <sys/ioctl.h> #include <sys/time.h> -#include <assert.h> #include <err.h> #include <errno.h> #include <fcntl.h> @@ -54,14 +53,79 @@ __RCSID("$NetBSD: tprof_top.c,v 1.2 2022 #include "tprof.h" #include "ksyms.h" -static struct sym **ksyms; -static size_t nksyms; -static sig_atomic_t sigalrm; +#define SAMPLE_MODE_ACCUMULATIVE 0 +#define SAMPLE_MODE_INSTANTANEOUS 1 +#define SAMPLE_MODE_NUM 2 + +struct sample_elm { + struct rb_node node; + uint64_t addr; + const char *name; + uint32_t flags; +#define SAMPLE_ELM_FLAGS_USER 0x00000001 + uint32_t num[SAMPLE_MODE_NUM]; + uint32_t num_cpu[]; /* [SAMPLE_MODE_NUM][ncpu] */ +#define SAMPLE_ELM_NUM_CPU(e, k) \ + ((e)->num_cpu + (k) * ncpu) +}; + +struct ptrarray { + void **pa_ptrs; + size_t pa_allocnum; + size_t pa_inuse; +}; + +static int opt_mode = SAMPLE_MODE_INSTANTANEOUS; +static int opt_userland = 0; +static int opt_showcounter = 0; + +/* for display */ static struct winsize win; +static int nontty; static long top_interval = 1; + +/* for profiling and counting samples */ +static sig_atomic_t sigalrm; +static struct sym **ksyms; +static size_t nksyms; static u_int nevent; static const char *eventname[TPROF_MAXCOUNTERS]; -static int nontty; +static size_t sizeof_sample_elm; +static rb_tree_t rb_tree_sample; +struct ptrarray sample_list[SAMPLE_MODE_NUM]; +static u_int sample_n_kern[SAMPLE_MODE_NUM]; +static u_int sample_n_user[SAMPLE_MODE_NUM]; +static uint32_t *sample_n_kern_per_cpu[SAMPLE_MODE_NUM]; /* [ncpu] */ +static uint32_t *sample_n_user_per_cpu[SAMPLE_MODE_NUM]; /* [ncpu] */ +static uint64_t *sample_n_per_event[SAMPLE_MODE_NUM]; /* [nevent] */ +static uint64_t *sample_n_per_event_cpu[SAMPLE_MODE_NUM]; /* [ncpu] */ + +/* raw event counter */ +static uint64_t *counters; /* counters[2][ncpu][nevent] */ +static u_int counters_i; + +static const char * +cycle_event_name(void) +{ + const char *cycleevent; + + switch (tprof_info.ti_ident) { + case TPROF_IDENT_INTEL_GENERIC: + cycleevent = "unhalted-core-cycles"; + break; + case TPROF_IDENT_AMD_GENERIC: + cycleevent = "LsNotHaltedCyc"; + break; + case TPROF_IDENT_ARMV8_GENERIC: + case TPROF_IDENT_ARMV7_GENERIC: + cycleevent = "CPU_CYCLES"; + break; + default: + cycleevent = NULL; + break; + } + return cycleevent; +} /* XXX: use terminfo or curses */ static void @@ -108,31 +172,37 @@ sigalrm_handler(int signo) sigalrm = 1; } -struct sample_elm { - struct rb_node node; - uint64_t addr; - const char *name; - uint32_t flags; -#define SAMPLE_ELM_FLAGS_USER 0x00000001 - uint32_t num; - uint32_t numcpu[]; -}; +static void +ptrarray_push(struct ptrarray *ptrarray, void *ptr) +{ + int error; -static size_t sizeof_sample_elm; -static rb_tree_t rb_tree_sample; -static char *samplebuf; -static u_int sample_nused; -static u_int sample_kern_nsample; -static u_int sample_user_nsample; -static u_int sample_max = 1024 * 512; /* XXX */ -static uint32_t *sample_nsample_kern_per_cpu; -static uint32_t *sample_nsample_user_per_cpu; -static uint64_t *sample_nsample_per_event; -static uint64_t *sample_nsample_per_event_cpu; -static uint64_t collect_overflow; + if (ptrarray->pa_inuse >= ptrarray->pa_allocnum) { + /* increase buffer */ + ptrarray->pa_allocnum += 1024; + error = reallocarr(&ptrarray->pa_ptrs, ptrarray->pa_allocnum, + sizeof(*ptrarray->pa_ptrs)); + if (error != 0) + errc(EXIT_FAILURE, error, "rellocarr failed"); + } + ptrarray->pa_ptrs[ptrarray->pa_inuse++] = ptr; +} -static int opt_userland = 0; -static int opt_showcounter = 0; +static void +ptrarray_iterate(struct ptrarray *ptrarray, void (*ifunc)(void *)) +{ + size_t i; + + for (i = 0; i < ptrarray->pa_inuse; i++) { + (*ifunc)(ptrarray->pa_ptrs[i]); + } +} + +static void +ptrarray_clear(struct ptrarray *ptrarray) +{ + ptrarray->pa_inuse = 0; +} static int sample_compare_key(void *ctx, const void *n1, const void *keyp) @@ -154,70 +224,111 @@ static const rb_tree_ops_t sample_ops = .rbto_compare_key = sample_compare_key }; +static u_int +n_align(u_int n, u_int align) +{ + return (n + align - 1) / align * align; +} + static void sample_init(void) { - sizeof_sample_elm = sizeof(struct sample_elm) + sizeof(uint32_t) * ncpu; + const struct sample_elm *e; + int mode; + + u_int size = sizeof(struct sample_elm) + + sizeof(e->num_cpu[0]) * SAMPLE_MODE_NUM * ncpu; + sizeof_sample_elm = n_align(size, __alignof(struct sample_elm)); + + for (mode = 0; mode < SAMPLE_MODE_NUM; mode++) { + sample_n_kern_per_cpu[mode] = ecalloc(1, + sizeof(typeof(*sample_n_kern_per_cpu[mode])) * ncpu); + sample_n_user_per_cpu[mode] = ecalloc(1, + sizeof(typeof(*sample_n_user_per_cpu[mode])) * ncpu); + sample_n_per_event[mode] = ecalloc(1, + sizeof(typeof(*sample_n_per_event[mode])) * nevent); + sample_n_per_event_cpu[mode] = ecalloc(1, + sizeof(typeof(*sample_n_per_event_cpu[mode])) * + nevent * ncpu); + } } static void -sample_reset(void) +sample_clear_instantaneous(void *arg) { - if (samplebuf == NULL) { - samplebuf = emalloc(sizeof_sample_elm * sample_max); - sample_nsample_kern_per_cpu = emalloc(sizeof(uint32_t) * ncpu); - sample_nsample_user_per_cpu = emalloc(sizeof(uint32_t) * ncpu); - sample_nsample_per_event = emalloc(sizeof(uint64_t) * nevent); - sample_nsample_per_event_cpu = - emalloc(sizeof(uint64_t) * nevent * ncpu); - } - sample_nused = 0; - sample_kern_nsample = 0; - sample_user_nsample = 0; - memset(sample_nsample_kern_per_cpu, 0, sizeof(uint32_t) * ncpu); - memset(sample_nsample_user_per_cpu, 0, sizeof(uint32_t) * ncpu); - memset(sample_nsample_per_event, 0, sizeof(uint64_t) * nevent); - memset(sample_nsample_per_event_cpu, 0, - sizeof(uint64_t) * nevent * ncpu); + struct sample_elm *e = (void *)arg; - rb_tree_init(&rb_tree_sample, &sample_ops); + e->num[SAMPLE_MODE_INSTANTANEOUS] = 0; + memset(SAMPLE_ELM_NUM_CPU(e, SAMPLE_MODE_INSTANTANEOUS), + 0, sizeof(e->num_cpu[0]) * ncpu); } -static struct sample_elm * -sample_alloc(void) +static void +sample_reset(bool reset_accumulative) { - struct sample_elm *e; + int mode; - if (sample_nused >= sample_max) { - errx(EXIT_FAILURE, "sample buffer overflow"); - return NULL; + for (mode = 0; mode < SAMPLE_MODE_NUM; mode++) { + if (mode == SAMPLE_MODE_ACCUMULATIVE && !reset_accumulative) + continue; + + sample_n_kern[mode] = 0; + sample_n_user[mode] = 0; + memset(sample_n_kern_per_cpu[mode], 0, + sizeof(typeof(*sample_n_kern_per_cpu[mode])) * ncpu); + memset(sample_n_user_per_cpu[mode], 0, + sizeof(typeof(*sample_n_user_per_cpu[mode])) * ncpu); + memset(sample_n_per_event[mode], 0, + sizeof(typeof(*sample_n_per_event[mode])) * nevent); + memset(sample_n_per_event_cpu[mode], 0, + sizeof(typeof(*sample_n_per_event_cpu[mode])) * + nevent * ncpu); } - e = (struct sample_elm *)(samplebuf + sizeof_sample_elm * - sample_nused++); - memset(e, 0, sizeof_sample_elm); - return e; + if (reset_accumulative) { + rb_tree_init(&rb_tree_sample, &sample_ops); + ptrarray_iterate(&sample_list[SAMPLE_MODE_ACCUMULATIVE], free); + ptrarray_clear(&sample_list[SAMPLE_MODE_ACCUMULATIVE]); + ptrarray_clear(&sample_list[SAMPLE_MODE_INSTANTANEOUS]); + } else { + ptrarray_iterate(&sample_list[SAMPLE_MODE_INSTANTANEOUS], + sample_clear_instantaneous); + ptrarray_clear(&sample_list[SAMPLE_MODE_INSTANTANEOUS]); + } } -static void -sample_takeback(struct sample_elm *e) +static int __unused +sample_sortfunc_accumulative(const void *a, const void *b) { - assert(sample_nused > 0); - sample_nused--; + struct sample_elm * const *ea = a; + struct sample_elm * const *eb = b; + return (*eb)->num[SAMPLE_MODE_ACCUMULATIVE] - + (*ea)->num[SAMPLE_MODE_ACCUMULATIVE]; } static int -sample_sortfunc(const void *a, const void *b) +sample_sortfunc_instantaneous(const void *a, const void *b) { - const struct sample_elm *ea = a; - const struct sample_elm *eb = b; - return eb->num - ea->num; + struct sample_elm * const *ea = a; + struct sample_elm * const *eb = b; + return (*eb)->num[SAMPLE_MODE_INSTANTANEOUS] - + (*ea)->num[SAMPLE_MODE_INSTANTANEOUS]; } static void -sample_sort(void) +sample_sort_accumulative(void) { - qsort(samplebuf, sample_nused, sizeof_sample_elm, sample_sortfunc); + qsort(sample_list[SAMPLE_MODE_ACCUMULATIVE].pa_ptrs, + sample_list[SAMPLE_MODE_ACCUMULATIVE].pa_inuse, + sizeof(struct sample_elm *), sample_sortfunc_accumulative); +} + +static void +sample_sort_instantaneous(void) +{ + qsort(sample_list[SAMPLE_MODE_INSTANTANEOUS].pa_ptrs, + sample_list[SAMPLE_MODE_INSTANTANEOUS].pa_inuse, + sizeof(struct sample_elm *), sample_sortfunc_instantaneous); } static void @@ -229,16 +340,24 @@ sample_collect(tprof_sample_t *s) uint64_t addr, offset; uint32_t flags = 0; uint32_t eventid, cpuid; + int mode; eventid = __SHIFTOUT(s->s_flags, TPROF_SAMPLE_COUNTER_MASK); cpuid = s->s_cpuid; - sample_nsample_per_event[eventid]++; - sample_nsample_per_event_cpu[nevent * cpuid + eventid]++; + if (eventid >= nevent) /* unknown event from tprof? */ + return; + + for (mode = 0; mode < SAMPLE_MODE_NUM; mode++) { + sample_n_per_event[mode][eventid]++; + sample_n_per_event_cpu[mode][nevent * cpuid + eventid]++; + } if ((s->s_flags & TPROF_SAMPLE_INKERNEL) == 0) { - sample_user_nsample++; - sample_nsample_user_per_cpu[cpuid]++; + sample_n_user[SAMPLE_MODE_ACCUMULATIVE]++; + sample_n_user[SAMPLE_MODE_INSTANTANEOUS]++; + sample_n_user_per_cpu[SAMPLE_MODE_ACCUMULATIVE][cpuid]++; + sample_n_user_per_cpu[SAMPLE_MODE_INSTANTANEOUS][cpuid]++; name = NULL; addr = s->s_pid; /* XXX */ @@ -247,8 +366,10 @@ sample_collect(tprof_sample_t *s) if (!opt_userland) return; } else { - sample_kern_nsample++; - sample_nsample_kern_per_cpu[cpuid]++; + sample_n_kern[SAMPLE_MODE_ACCUMULATIVE]++; + sample_n_kern[SAMPLE_MODE_INSTANTANEOUS]++; + sample_n_kern_per_cpu[SAMPLE_MODE_ACCUMULATIVE][cpuid]++; + sample_n_kern_per_cpu[SAMPLE_MODE_INSTANTANEOUS][cpuid]++; name = ksymlookup(s->s_pc, &offset, &symid); if (name != NULL) { @@ -258,24 +379,31 @@ sample_collect(tprof_sample_t *s) } } - e = sample_alloc(); - if (e == NULL) { - fprintf(stderr, "cannot allocate sample\n"); - collect_overflow++; - return; - } - + e = ecalloc(1, sizeof_sample_elm); e->addr = addr; e->name = name; e->flags = flags; - e->num = 1; - e->numcpu[cpuid] = 1; + e->num[SAMPLE_MODE_ACCUMULATIVE] = 1; + e->num[SAMPLE_MODE_INSTANTANEOUS] = 1; + SAMPLE_ELM_NUM_CPU(e, SAMPLE_MODE_ACCUMULATIVE)[cpuid] = 1; + SAMPLE_ELM_NUM_CPU(e, SAMPLE_MODE_INSTANTANEOUS)[cpuid] = 1; o = rb_tree_insert_node(&rb_tree_sample, e); - if (o != e) { + if (o == e) { + /* new symbol. add to list for sort */ + ptrarray_push(&sample_list[SAMPLE_MODE_ACCUMULATIVE], o); + ptrarray_push(&sample_list[SAMPLE_MODE_INSTANTANEOUS], o); + } else { /* already exists */ - sample_takeback(e); - o->num++; - o->numcpu[cpuid]++; + free(e); + + o->num[SAMPLE_MODE_ACCUMULATIVE]++; + if (o->num[SAMPLE_MODE_INSTANTANEOUS]++ == 0) { + /* new instantaneous symbols. add to list for sort */ + ptrarray_push(&sample_list[SAMPLE_MODE_INSTANTANEOUS], + o); + } + SAMPLE_ELM_NUM_CPU(o, SAMPLE_MODE_ACCUMULATIVE)[cpuid]++; + SAMPLE_ELM_NUM_CPU(o, SAMPLE_MODE_INSTANTANEOUS)[cpuid]++; } } @@ -317,16 +445,11 @@ show_timestamp(void) printf("%-8.8s", &(ctime((time_t *)&tv.tv_sec)[11])); } - -static uint64_t *counters; /* counters[2][ncpu][nevent] */ -static u_int counters_i; - static void show_counters_alloc(void) { - size_t sz = 2 * ncpu * nevent * sizeof(uint64_t); - counters = emalloc(sz); - memset(counters, 0, sz); + size_t sz = 2 * ncpu * nevent * sizeof(*counters); + counters = ecalloc(1, sz); } static void @@ -377,22 +500,22 @@ show_count_per_event(void) u_int i, nsample_total; int n; - nsample_total = sample_kern_nsample + sample_user_nsample; + nsample_total = sample_n_kern[opt_mode] + sample_n_user[opt_mode]; for (i = 0; i < nevent; i++) { - if (sample_nsample_per_event[i] >= nsample_total) { - printf("%5.1f%%", sample_nsample_per_event[i] * + if (sample_n_per_event[opt_mode][i] >= nsample_total) { + printf("%5.1f%%", sample_n_per_event[opt_mode][i] * 100.00 / nsample_total); } else { - printf("%5.2f%%", sample_nsample_per_event[i] * + printf("%5.2f%%", sample_n_per_event[opt_mode][i] * 100.00 / nsample_total); } - printf("%8"PRIu64" ", sample_nsample_per_event[i]); + printf("%8"PRIu64" ", sample_n_per_event[opt_mode][i]); printf("%-32.32s", eventname[i]); for (n = 0; n < ncpu; n++) { printf("%6"PRIu64, - sample_nsample_per_event_cpu[nevent * n + i]); + sample_n_per_event_cpu[opt_mode][nevent * n + i]); } printf("\n"); } @@ -404,6 +527,7 @@ sample_show(void) static u_int nshow; struct sample_elm *e; + struct ptrarray *samples; u_int nsample_total; int i, n, ndisp; char namebuf[32]; @@ -413,12 +537,18 @@ sample_show(void) margin_lines += 3 + nevent; /* show_counter_per_event() */ + if (opt_mode == SAMPLE_MODE_INSTANTANEOUS) + sample_sort_instantaneous(); + else + sample_sort_accumulative(); + samples = &sample_list[opt_mode]; + if (opt_showcounter) margin_lines += 2 + nevent; if (opt_userland) margin_lines += 1; - ndisp = sample_nused; + ndisp = samples->pa_inuse; if (!nontty && ndisp > (win.ws_row - margin_lines)) ndisp = win.ws_row - margin_lines; @@ -427,6 +557,9 @@ sample_show(void) cls_eos(); + if (opt_mode == SAMPLE_MODE_ACCUMULATIVE) + printf("[Accumulative mode] "); + show_tprof_stat(); cls_eol(); @@ -477,22 +610,22 @@ sample_show(void) printf("\n"); for (i = 0; i < ndisp; i++) { - e = (struct sample_elm *)(samplebuf + sizeof_sample_elm * i); + e = (struct sample_elm *)samples->pa_ptrs[i]; name = e->name; if (name == NULL) { if (e->flags & SAMPLE_ELM_FLAGS_USER) { - snprintf(namebuf, sizeof(namebuf), "<PID:%"PRIu64">", - e->addr); + snprintf(namebuf, sizeof(namebuf), + "<PID:%"PRIu64">", e->addr); } else { - snprintf(namebuf, sizeof(namebuf), "0x%016"PRIx64, - e->addr); + snprintf(namebuf, sizeof(namebuf), + "0x%016"PRIx64, e->addr); } name = namebuf; } - nsample_total = sample_kern_nsample; + nsample_total = sample_n_kern[opt_mode]; if (opt_userland) - nsample_total += sample_user_nsample; + nsample_total += sample_n_user[opt_mode]; /* * even when only kernel mode events are configured, * interrupts may still occur in the user mode state. @@ -500,25 +633,29 @@ sample_show(void) if (nsample_total == 0) nsample_total = 1; - if (e->num >= nsample_total) { - printf("%5.1f%%", e->num * 100.00 / nsample_total); + if (e->num[opt_mode] >= nsample_total) { + printf("%5.1f%%", + e->num[opt_mode] * 100.00 / nsample_total); } else { - printf("%5.2f%%", e->num * 100.00 / nsample_total); + printf("%5.2f%%", + e->num[opt_mode] * 100.00 / nsample_total); } - printf("%8u %-32.32s", e->num, name); + printf("%8u %-32.32s", e->num[opt_mode], name); for (n = 0; n < ncpu; n++) { - if (e->numcpu[n] == 0) + if (SAMPLE_ELM_NUM_CPU(e, opt_mode)[n] == 0) { printf(" ."); - else - printf("%6u", e->numcpu[n]); + } else { + printf("%6u", + SAMPLE_ELM_NUM_CPU(e, opt_mode)[n]); + } } printf("\n"); } - if ((u_int)ndisp != sample_nused) { - printf(" : : (more %u symbols omitted)\n", - sample_nused - ndisp); + if ((u_int)ndisp != samples->pa_inuse) { + printf(" : : (more %zu symbols omitted)\n", + samples->pa_inuse - ndisp); } else { for (i = ndisp; i <= win.ws_row - margin_lines; i++) { printf("~"); @@ -534,16 +671,17 @@ sample_show(void) } printf("\n"); - printf("Total %8u %-32.32s", sample_kern_nsample, "in-kernel"); + printf("Total %8u %-32.32s", sample_n_kern[opt_mode], "in-kernel"); for (n = 0; n < ncpu; n++) { - printf("%6u", sample_nsample_kern_per_cpu[n]); + printf("%6u", sample_n_kern_per_cpu[opt_mode][n]); } if (opt_userland) { printf("\n"); - printf(" %8u %-32.32s", sample_user_nsample, "userland"); + printf(" %8u %-32.32s", + sample_n_user[opt_mode], "userland"); for (n = 0; n < ncpu; n++) { - printf("%6u", sample_nsample_user_per_cpu[n]); + printf("%6u", sample_n_user_per_cpu[opt_mode][n]); } } @@ -553,8 +691,8 @@ sample_show(void) __dead static void tprof_top_usage(void) { - fprintf(stderr, "%s top [-e name[,scale] [-e ...]]" - " [-i interval] [-c] [-u]\n", getprogname()); + fprintf(stderr, "%s top [-acu] [-e name[,scale] [-e ...]]" + " [-i interval]\n", getprogname()); exit(EXIT_FAILURE); } @@ -591,16 +729,19 @@ tprof_top(int argc, char **argv) tprof_param_t params[TPROF_MAXCOUNTERS]; struct sigaction sa; struct itimerval it; - ssize_t bufsize; + ssize_t tprof_bufsize; u_int i; int ch, ret; - char *buf, *tokens[2], *p; + char *tprof_buf, *tokens[2], *p; memset(params, 0, sizeof(params)); nevent = 0; - while ((ch = getopt(argc, argv, "ce:i:u")) != -1) { + while ((ch = getopt(argc, argv, "ace:i:u")) != -1) { switch (ch) { + case 'a': + opt_mode = SAMPLE_MODE_ACCUMULATIVE; + break; case 'c': opt_showcounter = 1; break; @@ -610,8 +751,11 @@ tprof_top(int argc, char **argv) tokens[1] = strtok(NULL, ","); tprof_event_lookup(tokens[0], ¶ms[nevent]); if (tokens[1] != NULL) { - if (parse_event_scale(¶ms[nevent], tokens[1]) != 0) - errx(EXIT_FAILURE, "invalid scale: %s", tokens[1]); + if (parse_event_scale(¶ms[nevent], + tokens[1]) != 0) { + errx(EXIT_FAILURE, "invalid scale: %s", + tokens[1]); + } } eventname[nevent] = tokens[0]; nevent++; @@ -640,29 +784,8 @@ tprof_top(int argc, char **argv) if (argc != 0) tprof_top_usage(); - bufsize = sizeof(tprof_sample_t) * 8192; - buf = emalloc(bufsize); - - sample_init(); - if (nevent == 0) { - const char *defaultevent; - - switch (tprof_info.ti_ident) { - case TPROF_IDENT_INTEL_GENERIC: - defaultevent = "unhalted-core-cycles"; - break; - case TPROF_IDENT_AMD_GENERIC: - defaultevent = "LsNotHaltedCyc"; - break; - case TPROF_IDENT_ARMV8_GENERIC: - case TPROF_IDENT_ARMV7_GENERIC: - defaultevent = "CPU_CYCLES"; - break; - default: - defaultevent = NULL; - break; - } + const char *defaultevent = cycle_event_name(); if (defaultevent == NULL) errx(EXIT_FAILURE, "cpu not supported"); @@ -671,6 +794,7 @@ tprof_top(int argc, char **argv) nevent++; } + sample_init(); show_counters_alloc(); for (i = 0; i < nevent; i++) { @@ -707,32 +831,31 @@ tprof_top(int argc, char **argv) it.it_interval.tv_usec = it.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &it, NULL); - sample_reset(); + sample_reset(true); printf("collecting samples..."); fflush(stdout); + tprof_bufsize = sizeof(tprof_sample_t) * 8192; + tprof_buf = emalloc(tprof_bufsize); do { /* continue to accumulate tprof_sample until alarm arrives */ while (sigalrm == 0) { - ssize_t len = read(devfd, buf, bufsize); + ssize_t len = read(devfd, tprof_buf, tprof_bufsize); if (len == -1 && errno != EINTR) err(EXIT_FAILURE, "read"); if (len > 0) { - tprof_sample_t *s = (tprof_sample_t *)buf; - while (s < (tprof_sample_t *)(buf + len)) { - sample_collect(s); - s++; - } + tprof_sample_t *s = (tprof_sample_t *)tprof_buf; + while (s < (tprof_sample_t *)(tprof_buf + len)) + sample_collect(s++); } } sigalrm = 0; /* update screen */ - sample_sort(); sample_show(); fflush(stdout); - sample_reset(); + sample_reset(false); } while (!nontty); printf("\n");