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(¶ms[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, ¶ms[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, ¶ms[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