diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
| -rw-r--r-- | tools/perf/builtin-report.c | 719 |
1 files changed, 136 insertions, 583 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8b2ec882e6e0..cdf9a8d27bb9 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -17,19 +17,18 @@ | |||
| 17 | #include "util/string.h" | 17 | #include "util/string.h" |
| 18 | #include "util/callchain.h" | 18 | #include "util/callchain.h" |
| 19 | #include "util/strlist.h" | 19 | #include "util/strlist.h" |
| 20 | #include "util/values.h" | ||
| 20 | 21 | ||
| 21 | #include "perf.h" | 22 | #include "perf.h" |
| 23 | #include "util/debug.h" | ||
| 22 | #include "util/header.h" | 24 | #include "util/header.h" |
| 23 | 25 | ||
| 24 | #include "util/parse-options.h" | 26 | #include "util/parse-options.h" |
| 25 | #include "util/parse-events.h" | 27 | #include "util/parse-events.h" |
| 26 | 28 | ||
| 27 | #define SHOW_KERNEL 1 | 29 | #include "util/thread.h" |
| 28 | #define SHOW_USER 2 | ||
| 29 | #define SHOW_HV 4 | ||
| 30 | 30 | ||
| 31 | static char const *input_name = "perf.data"; | 31 | static char const *input_name = "perf.data"; |
| 32 | static char *vmlinux = NULL; | ||
| 33 | 32 | ||
| 34 | static char default_sort_order[] = "comm,dso,symbol"; | 33 | static char default_sort_order[] = "comm,dso,symbol"; |
| 35 | static char *sort_order = default_sort_order; | 34 | static char *sort_order = default_sort_order; |
| @@ -42,18 +41,15 @@ static int force; | |||
| 42 | static int input; | 41 | static int input; |
| 43 | static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; | 42 | static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; |
| 44 | 43 | ||
| 45 | static int dump_trace = 0; | ||
| 46 | #define dprintf(x...) do { if (dump_trace) printf(x); } while (0) | ||
| 47 | #define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0) | ||
| 48 | |||
| 49 | static int verbose; | ||
| 50 | #define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0) | ||
| 51 | |||
| 52 | static int modules; | ||
| 53 | |||
| 54 | static int full_paths; | 44 | static int full_paths; |
| 55 | static int show_nr_samples; | 45 | static int show_nr_samples; |
| 56 | 46 | ||
| 47 | static int show_threads; | ||
| 48 | static struct perf_read_values show_threads_values; | ||
| 49 | |||
| 50 | static char default_pretty_printing_style[] = "normal"; | ||
| 51 | static char *pretty_printing_style = default_pretty_printing_style; | ||
| 52 | |||
| 57 | static unsigned long page_size; | 53 | static unsigned long page_size; |
| 58 | static unsigned long mmap_window = 32; | 54 | static unsigned long mmap_window = 32; |
| 59 | 55 | ||
| @@ -67,6 +63,15 @@ static char callchain_default_opt[] = "fractal,0.5"; | |||
| 67 | 63 | ||
| 68 | static int callchain; | 64 | static int callchain; |
| 69 | 65 | ||
| 66 | static char __cwd[PATH_MAX]; | ||
| 67 | static char *cwd = __cwd; | ||
| 68 | static int cwdlen; | ||
| 69 | |||
| 70 | static struct rb_root threads; | ||
| 71 | static struct thread *last_match; | ||
| 72 | |||
| 73 | static struct perf_header *header; | ||
| 74 | |||
| 70 | static | 75 | static |
| 71 | struct callchain_param callchain_param = { | 76 | struct callchain_param callchain_param = { |
| 72 | .mode = CHAIN_GRAPH_REL, | 77 | .mode = CHAIN_GRAPH_REL, |
| @@ -75,59 +80,6 @@ struct callchain_param callchain_param = { | |||
| 75 | 80 | ||
| 76 | static u64 sample_type; | 81 | static u64 sample_type; |
| 77 | 82 | ||
| 78 | struct ip_event { | ||
| 79 | struct perf_event_header header; | ||
| 80 | u64 ip; | ||
| 81 | u32 pid, tid; | ||
| 82 | unsigned char __more_data[]; | ||
| 83 | }; | ||
| 84 | |||
| 85 | struct mmap_event { | ||
| 86 | struct perf_event_header header; | ||
| 87 | u32 pid, tid; | ||
| 88 | u64 start; | ||
| 89 | u64 len; | ||
| 90 | u64 pgoff; | ||
| 91 | char filename[PATH_MAX]; | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct comm_event { | ||
| 95 | struct perf_event_header header; | ||
| 96 | u32 pid, tid; | ||
| 97 | char comm[16]; | ||
| 98 | }; | ||
| 99 | |||
| 100 | struct fork_event { | ||
| 101 | struct perf_event_header header; | ||
| 102 | u32 pid, ppid; | ||
| 103 | u32 tid, ptid; | ||
| 104 | }; | ||
| 105 | |||
| 106 | struct lost_event { | ||
| 107 | struct perf_event_header header; | ||
| 108 | u64 id; | ||
| 109 | u64 lost; | ||
| 110 | }; | ||
| 111 | |||
| 112 | struct read_event { | ||
| 113 | struct perf_event_header header; | ||
| 114 | u32 pid,tid; | ||
| 115 | u64 value; | ||
| 116 | u64 time_enabled; | ||
| 117 | u64 time_running; | ||
| 118 | u64 id; | ||
| 119 | }; | ||
| 120 | |||
| 121 | typedef union event_union { | ||
| 122 | struct perf_event_header header; | ||
| 123 | struct ip_event ip; | ||
| 124 | struct mmap_event mmap; | ||
| 125 | struct comm_event comm; | ||
| 126 | struct fork_event fork; | ||
| 127 | struct lost_event lost; | ||
| 128 | struct read_event read; | ||
| 129 | } event_t; | ||
| 130 | |||
| 131 | static int repsep_fprintf(FILE *fp, const char *fmt, ...) | 83 | static int repsep_fprintf(FILE *fp, const char *fmt, ...) |
| 132 | { | 84 | { |
| 133 | int n; | 85 | int n; |
| @@ -141,6 +93,7 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...) | |||
| 141 | n = vasprintf(&bf, fmt, ap); | 93 | n = vasprintf(&bf, fmt, ap); |
| 142 | if (n > 0) { | 94 | if (n > 0) { |
| 143 | char *sep = bf; | 95 | char *sep = bf; |
| 96 | |||
| 144 | while (1) { | 97 | while (1) { |
| 145 | sep = strchr(sep, *field_sep); | 98 | sep = strchr(sep, *field_sep); |
| 146 | if (sep == NULL) | 99 | if (sep == NULL) |
| @@ -155,396 +108,10 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...) | |||
| 155 | return n; | 108 | return n; |
| 156 | } | 109 | } |
| 157 | 110 | ||
| 158 | static LIST_HEAD(dsos); | ||
| 159 | static struct dso *kernel_dso; | ||
| 160 | static struct dso *vdso; | ||
| 161 | static struct dso *hypervisor_dso; | ||
| 162 | |||
| 163 | static void dsos__add(struct dso *dso) | ||
| 164 | { | ||
| 165 | list_add_tail(&dso->node, &dsos); | ||
| 166 | } | ||
| 167 | |||
| 168 | static struct dso *dsos__find(const char *name) | ||
| 169 | { | ||
| 170 | struct dso *pos; | ||
| 171 | |||
| 172 | list_for_each_entry(pos, &dsos, node) | ||
| 173 | if (strcmp(pos->name, name) == 0) | ||
| 174 | return pos; | ||
| 175 | return NULL; | ||
| 176 | } | ||
| 177 | |||
| 178 | static struct dso *dsos__findnew(const char *name) | ||
| 179 | { | ||
| 180 | struct dso *dso = dsos__find(name); | ||
| 181 | int nr; | ||
| 182 | |||
| 183 | if (dso) | ||
| 184 | return dso; | ||
| 185 | |||
| 186 | dso = dso__new(name, 0); | ||
| 187 | if (!dso) | ||
| 188 | goto out_delete_dso; | ||
| 189 | |||
| 190 | nr = dso__load(dso, NULL, verbose); | ||
| 191 | if (nr < 0) { | ||
| 192 | eprintf("Failed to open: %s\n", name); | ||
| 193 | goto out_delete_dso; | ||
| 194 | } | ||
| 195 | if (!nr) | ||
| 196 | eprintf("No symbols found in: %s, maybe install a debug package?\n", name); | ||
| 197 | |||
| 198 | dsos__add(dso); | ||
| 199 | |||
| 200 | return dso; | ||
| 201 | |||
| 202 | out_delete_dso: | ||
| 203 | dso__delete(dso); | ||
| 204 | return NULL; | ||
| 205 | } | ||
| 206 | |||
| 207 | static void dsos__fprintf(FILE *fp) | ||
| 208 | { | ||
| 209 | struct dso *pos; | ||
| 210 | |||
| 211 | list_for_each_entry(pos, &dsos, node) | ||
| 212 | dso__fprintf(pos, fp); | ||
| 213 | } | ||
| 214 | |||
| 215 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) | ||
| 216 | { | ||
| 217 | return dso__find_symbol(dso, ip); | ||
| 218 | } | ||
| 219 | |||
| 220 | static int load_kernel(void) | ||
| 221 | { | ||
| 222 | int err; | ||
| 223 | |||
| 224 | kernel_dso = dso__new("[kernel]", 0); | ||
| 225 | if (!kernel_dso) | ||
| 226 | return -1; | ||
| 227 | |||
| 228 | err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules); | ||
| 229 | if (err <= 0) { | ||
| 230 | dso__delete(kernel_dso); | ||
| 231 | kernel_dso = NULL; | ||
| 232 | } else | ||
| 233 | dsos__add(kernel_dso); | ||
| 234 | |||
| 235 | vdso = dso__new("[vdso]", 0); | ||
| 236 | if (!vdso) | ||
| 237 | return -1; | ||
| 238 | |||
| 239 | vdso->find_symbol = vdso__find_symbol; | ||
| 240 | |||
| 241 | dsos__add(vdso); | ||
| 242 | |||
| 243 | hypervisor_dso = dso__new("[hypervisor]", 0); | ||
| 244 | if (!hypervisor_dso) | ||
| 245 | return -1; | ||
| 246 | dsos__add(hypervisor_dso); | ||
| 247 | |||
| 248 | return err; | ||
| 249 | } | ||
| 250 | |||
| 251 | static char __cwd[PATH_MAX]; | ||
| 252 | static char *cwd = __cwd; | ||
| 253 | static int cwdlen; | ||
| 254 | |||
| 255 | static int strcommon(const char *pathname) | ||
| 256 | { | ||
| 257 | int n = 0; | ||
| 258 | |||
| 259 | while (n < cwdlen && pathname[n] == cwd[n]) | ||
| 260 | ++n; | ||
| 261 | |||
| 262 | return n; | ||
| 263 | } | ||
| 264 | |||
| 265 | struct map { | ||
| 266 | struct list_head node; | ||
| 267 | u64 start; | ||
| 268 | u64 end; | ||
| 269 | u64 pgoff; | ||
| 270 | u64 (*map_ip)(struct map *, u64); | ||
| 271 | struct dso *dso; | ||
| 272 | }; | ||
| 273 | |||
| 274 | static u64 map__map_ip(struct map *map, u64 ip) | ||
| 275 | { | ||
| 276 | return ip - map->start + map->pgoff; | ||
| 277 | } | ||
| 278 | |||
| 279 | static u64 vdso__map_ip(struct map *map __used, u64 ip) | ||
| 280 | { | ||
| 281 | return ip; | ||
| 282 | } | ||
| 283 | |||
| 284 | static inline int is_anon_memory(const char *filename) | ||
| 285 | { | ||
| 286 | return strcmp(filename, "//anon") == 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static struct map *map__new(struct mmap_event *event) | ||
| 290 | { | ||
| 291 | struct map *self = malloc(sizeof(*self)); | ||
| 292 | |||
| 293 | if (self != NULL) { | ||
| 294 | const char *filename = event->filename; | ||
| 295 | char newfilename[PATH_MAX]; | ||
| 296 | int anon; | ||
| 297 | |||
| 298 | if (cwd) { | ||
| 299 | int n = strcommon(filename); | ||
| 300 | |||
| 301 | if (n == cwdlen) { | ||
| 302 | snprintf(newfilename, sizeof(newfilename), | ||
| 303 | ".%s", filename + n); | ||
| 304 | filename = newfilename; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | anon = is_anon_memory(filename); | ||
| 309 | |||
| 310 | if (anon) { | ||
| 311 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid); | ||
| 312 | filename = newfilename; | ||
| 313 | } | ||
| 314 | |||
| 315 | self->start = event->start; | ||
| 316 | self->end = event->start + event->len; | ||
| 317 | self->pgoff = event->pgoff; | ||
| 318 | |||
| 319 | self->dso = dsos__findnew(filename); | ||
| 320 | if (self->dso == NULL) | ||
| 321 | goto out_delete; | ||
| 322 | |||
| 323 | if (self->dso == vdso || anon) | ||
| 324 | self->map_ip = vdso__map_ip; | ||
| 325 | else | ||
| 326 | self->map_ip = map__map_ip; | ||
| 327 | } | ||
| 328 | return self; | ||
| 329 | out_delete: | ||
| 330 | free(self); | ||
| 331 | return NULL; | ||
| 332 | } | ||
| 333 | |||
| 334 | static struct map *map__clone(struct map *self) | ||
| 335 | { | ||
| 336 | struct map *map = malloc(sizeof(*self)); | ||
| 337 | |||
| 338 | if (!map) | ||
| 339 | return NULL; | ||
| 340 | |||
| 341 | memcpy(map, self, sizeof(*self)); | ||
| 342 | |||
| 343 | return map; | ||
| 344 | } | ||
| 345 | |||
| 346 | static int map__overlap(struct map *l, struct map *r) | ||
| 347 | { | ||
| 348 | if (l->start > r->start) { | ||
| 349 | struct map *t = l; | ||
| 350 | l = r; | ||
| 351 | r = t; | ||
| 352 | } | ||
| 353 | |||
| 354 | if (l->end > r->start) | ||
| 355 | return 1; | ||
| 356 | |||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | static size_t map__fprintf(struct map *self, FILE *fp) | ||
| 361 | { | ||
| 362 | return fprintf(fp, " %Lx-%Lx %Lx %s\n", | ||
| 363 | self->start, self->end, self->pgoff, self->dso->name); | ||
| 364 | } | ||
| 365 | |||
| 366 | |||
| 367 | struct thread { | ||
| 368 | struct rb_node rb_node; | ||
| 369 | struct list_head maps; | ||
| 370 | pid_t pid; | ||
| 371 | char *comm; | ||
| 372 | }; | ||
| 373 | |||
| 374 | static struct thread *thread__new(pid_t pid) | ||
| 375 | { | ||
| 376 | struct thread *self = malloc(sizeof(*self)); | ||
| 377 | |||
| 378 | if (self != NULL) { | ||
| 379 | self->pid = pid; | ||
| 380 | self->comm = malloc(32); | ||
| 381 | if (self->comm) | ||
| 382 | snprintf(self->comm, 32, ":%d", self->pid); | ||
| 383 | INIT_LIST_HEAD(&self->maps); | ||
| 384 | } | ||
| 385 | |||
| 386 | return self; | ||
| 387 | } | ||
| 388 | |||
| 389 | static unsigned int dsos__col_width, | 111 | static unsigned int dsos__col_width, |
| 390 | comms__col_width, | 112 | comms__col_width, |
| 391 | threads__col_width; | 113 | threads__col_width; |
| 392 | 114 | ||
| 393 | static int thread__set_comm(struct thread *self, const char *comm) | ||
| 394 | { | ||
| 395 | if (self->comm) | ||
| 396 | free(self->comm); | ||
| 397 | self->comm = strdup(comm); | ||
| 398 | if (!self->comm) | ||
| 399 | return -ENOMEM; | ||
| 400 | |||
| 401 | if (!col_width_list_str && !field_sep && | ||
| 402 | (!comm_list || strlist__has_entry(comm_list, comm))) { | ||
| 403 | unsigned int slen = strlen(comm); | ||
| 404 | if (slen > comms__col_width) { | ||
| 405 | comms__col_width = slen; | ||
| 406 | threads__col_width = slen + 6; | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | return 0; | ||
| 411 | } | ||
| 412 | |||
| 413 | static size_t thread__fprintf(struct thread *self, FILE *fp) | ||
| 414 | { | ||
| 415 | struct map *pos; | ||
| 416 | size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); | ||
| 417 | |||
| 418 | list_for_each_entry(pos, &self->maps, node) | ||
| 419 | ret += map__fprintf(pos, fp); | ||
| 420 | |||
| 421 | return ret; | ||
| 422 | } | ||
| 423 | |||
| 424 | |||
| 425 | static struct rb_root threads; | ||
| 426 | static struct thread *last_match; | ||
| 427 | |||
| 428 | static struct thread *threads__findnew(pid_t pid) | ||
| 429 | { | ||
| 430 | struct rb_node **p = &threads.rb_node; | ||
| 431 | struct rb_node *parent = NULL; | ||
| 432 | struct thread *th; | ||
| 433 | |||
| 434 | /* | ||
| 435 | * Font-end cache - PID lookups come in blocks, | ||
| 436 | * so most of the time we dont have to look up | ||
| 437 | * the full rbtree: | ||
| 438 | */ | ||
| 439 | if (last_match && last_match->pid == pid) | ||
| 440 | return last_match; | ||
| 441 | |||
| 442 | while (*p != NULL) { | ||
| 443 | parent = *p; | ||
| 444 | th = rb_entry(parent, struct thread, rb_node); | ||
| 445 | |||
| 446 | if (th->pid == pid) { | ||
| 447 | last_match = th; | ||
| 448 | return th; | ||
| 449 | } | ||
| 450 | |||
| 451 | if (pid < th->pid) | ||
| 452 | p = &(*p)->rb_left; | ||
| 453 | else | ||
| 454 | p = &(*p)->rb_right; | ||
| 455 | } | ||
| 456 | |||
| 457 | th = thread__new(pid); | ||
| 458 | if (th != NULL) { | ||
| 459 | rb_link_node(&th->rb_node, parent, p); | ||
| 460 | rb_insert_color(&th->rb_node, &threads); | ||
| 461 | last_match = th; | ||
| 462 | } | ||
| 463 | |||
| 464 | return th; | ||
| 465 | } | ||
| 466 | |||
| 467 | static void thread__insert_map(struct thread *self, struct map *map) | ||
| 468 | { | ||
| 469 | struct map *pos, *tmp; | ||
| 470 | |||
| 471 | list_for_each_entry_safe(pos, tmp, &self->maps, node) { | ||
| 472 | if (map__overlap(pos, map)) { | ||
| 473 | if (verbose >= 2) { | ||
| 474 | printf("overlapping maps:\n"); | ||
| 475 | map__fprintf(map, stdout); | ||
| 476 | map__fprintf(pos, stdout); | ||
| 477 | } | ||
| 478 | |||
| 479 | if (map->start <= pos->start && map->end > pos->start) | ||
| 480 | pos->start = map->end; | ||
| 481 | |||
| 482 | if (map->end >= pos->end && map->start < pos->end) | ||
| 483 | pos->end = map->start; | ||
| 484 | |||
| 485 | if (verbose >= 2) { | ||
| 486 | printf("after collision:\n"); | ||
| 487 | map__fprintf(pos, stdout); | ||
| 488 | } | ||
| 489 | |||
| 490 | if (pos->start >= pos->end) { | ||
| 491 | list_del_init(&pos->node); | ||
| 492 | free(pos); | ||
| 493 | } | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | list_add_tail(&map->node, &self->maps); | ||
| 498 | } | ||
| 499 | |||
| 500 | static int thread__fork(struct thread *self, struct thread *parent) | ||
| 501 | { | ||
| 502 | struct map *map; | ||
| 503 | |||
| 504 | if (self->comm) | ||
| 505 | free(self->comm); | ||
| 506 | self->comm = strdup(parent->comm); | ||
| 507 | if (!self->comm) | ||
| 508 | return -ENOMEM; | ||
| 509 | |||
| 510 | list_for_each_entry(map, &parent->maps, node) { | ||
| 511 | struct map *new = map__clone(map); | ||
| 512 | if (!new) | ||
| 513 | return -ENOMEM; | ||
| 514 | thread__insert_map(self, new); | ||
| 515 | } | ||
| 516 | |||
| 517 | return 0; | ||
| 518 | } | ||
| 519 | |||
| 520 | static struct map *thread__find_map(struct thread *self, u64 ip) | ||
| 521 | { | ||
| 522 | struct map *pos; | ||
| 523 | |||
| 524 | if (self == NULL) | ||
| 525 | return NULL; | ||
| 526 | |||
| 527 | list_for_each_entry(pos, &self->maps, node) | ||
| 528 | if (ip >= pos->start && ip <= pos->end) | ||
| 529 | return pos; | ||
| 530 | |||
| 531 | return NULL; | ||
| 532 | } | ||
| 533 | |||
| 534 | static size_t threads__fprintf(FILE *fp) | ||
| 535 | { | ||
| 536 | size_t ret = 0; | ||
| 537 | struct rb_node *nd; | ||
| 538 | |||
| 539 | for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { | ||
| 540 | struct thread *pos = rb_entry(nd, struct thread, rb_node); | ||
| 541 | |||
| 542 | ret += thread__fprintf(pos, fp); | ||
| 543 | } | ||
| 544 | |||
| 545 | return ret; | ||
| 546 | } | ||
| 547 | |||
| 548 | /* | 115 | /* |
| 549 | * histogram, sorted on item, collects counts | 116 | * histogram, sorted on item, collects counts |
| 550 | */ | 117 | */ |
| @@ -574,7 +141,7 @@ struct hist_entry { | |||
| 574 | struct sort_entry { | 141 | struct sort_entry { |
| 575 | struct list_head list; | 142 | struct list_head list; |
| 576 | 143 | ||
| 577 | char *header; | 144 | const char *header; |
| 578 | 145 | ||
| 579 | int64_t (*cmp)(struct hist_entry *, struct hist_entry *); | 146 | int64_t (*cmp)(struct hist_entry *, struct hist_entry *); |
| 580 | int64_t (*collapse)(struct hist_entry *, struct hist_entry *); | 147 | int64_t (*collapse)(struct hist_entry *, struct hist_entry *); |
| @@ -758,7 +325,7 @@ static int sort__need_collapse = 0; | |||
| 758 | static int sort__has_parent = 0; | 325 | static int sort__has_parent = 0; |
| 759 | 326 | ||
| 760 | struct sort_dimension { | 327 | struct sort_dimension { |
| 761 | char *name; | 328 | const char *name; |
| 762 | struct sort_entry *entry; | 329 | struct sort_entry *entry; |
| 763 | int taken; | 330 | int taken; |
| 764 | }; | 331 | }; |
| @@ -773,7 +340,7 @@ static struct sort_dimension sort_dimensions[] = { | |||
| 773 | 340 | ||
| 774 | static LIST_HEAD(hist_entry__sort_list); | 341 | static LIST_HEAD(hist_entry__sort_list); |
| 775 | 342 | ||
| 776 | static int sort_dimension__add(char *tok) | 343 | static int sort_dimension__add(const char *tok) |
| 777 | { | 344 | { |
| 778 | unsigned int i; | 345 | unsigned int i; |
| 779 | 346 | ||
| @@ -1032,6 +599,7 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, | |||
| 1032 | case CHAIN_GRAPH_REL: | 599 | case CHAIN_GRAPH_REL: |
| 1033 | ret += callchain__fprintf_graph(fp, chain, | 600 | ret += callchain__fprintf_graph(fp, chain, |
| 1034 | total_samples, 1, 1); | 601 | total_samples, 1, 1); |
| 602 | case CHAIN_NONE: | ||
| 1035 | default: | 603 | default: |
| 1036 | break; | 604 | break; |
| 1037 | } | 605 | } |
| @@ -1098,6 +666,34 @@ static void dso__calc_col_width(struct dso *self) | |||
| 1098 | self->slen_calculated = 1; | 666 | self->slen_calculated = 1; |
| 1099 | } | 667 | } |
| 1100 | 668 | ||
| 669 | static void thread__comm_adjust(struct thread *self) | ||
| 670 | { | ||
| 671 | char *comm = self->comm; | ||
| 672 | |||
| 673 | if (!col_width_list_str && !field_sep && | ||
| 674 | (!comm_list || strlist__has_entry(comm_list, comm))) { | ||
| 675 | unsigned int slen = strlen(comm); | ||
| 676 | |||
| 677 | if (slen > comms__col_width) { | ||
| 678 | comms__col_width = slen; | ||
| 679 | threads__col_width = slen + 6; | ||
| 680 | } | ||
| 681 | } | ||
| 682 | } | ||
| 683 | |||
| 684 | static int thread__set_comm_adjust(struct thread *self, const char *comm) | ||
| 685 | { | ||
| 686 | int ret = thread__set_comm(self, comm); | ||
| 687 | |||
| 688 | if (ret) | ||
| 689 | return ret; | ||
| 690 | |||
| 691 | thread__comm_adjust(self); | ||
| 692 | |||
| 693 | return 0; | ||
| 694 | } | ||
| 695 | |||
| 696 | |||
| 1101 | static struct symbol * | 697 | static struct symbol * |
| 1102 | resolve_symbol(struct thread *thread, struct map **mapp, | 698 | resolve_symbol(struct thread *thread, struct map **mapp, |
| 1103 | struct dso **dsop, u64 *ipp) | 699 | struct dso **dsop, u64 *ipp) |
| @@ -1141,8 +737,8 @@ got_map: | |||
| 1141 | if ((long long)ip < 0) | 737 | if ((long long)ip < 0) |
| 1142 | dso = kernel_dso; | 738 | dso = kernel_dso; |
| 1143 | } | 739 | } |
| 1144 | dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); | 740 | dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); |
| 1145 | dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip); | 741 | dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); |
| 1146 | *ipp = ip; | 742 | *ipp = ip; |
| 1147 | 743 | ||
| 1148 | if (dsop) | 744 | if (dsop) |
| @@ -1398,6 +994,9 @@ static size_t output__fprintf(FILE *fp, u64 total_samples) | |||
| 1398 | size_t ret = 0; | 994 | size_t ret = 0; |
| 1399 | unsigned int width; | 995 | unsigned int width; |
| 1400 | char *col_width = col_width_list_str; | 996 | char *col_width = col_width_list_str; |
| 997 | int raw_printing_style; | ||
| 998 | |||
| 999 | raw_printing_style = !strcmp(pretty_printing_style, "raw"); | ||
| 1401 | 1000 | ||
| 1402 | init_rem_hits(); | 1001 | init_rem_hits(); |
| 1403 | 1002 | ||
| @@ -1474,18 +1073,11 @@ print_entries: | |||
| 1474 | 1073 | ||
| 1475 | free(rem_sq_bracket); | 1074 | free(rem_sq_bracket); |
| 1476 | 1075 | ||
| 1477 | return ret; | 1076 | if (show_threads) |
| 1478 | } | 1077 | perf_read_values_display(fp, &show_threads_values, |
| 1078 | raw_printing_style); | ||
| 1479 | 1079 | ||
| 1480 | static void register_idle_thread(void) | 1080 | return ret; |
| 1481 | { | ||
| 1482 | struct thread *thread = threads__findnew(0); | ||
| 1483 | |||
| 1484 | if (thread == NULL || | ||
| 1485 | thread__set_comm(thread, "[idle]")) { | ||
| 1486 | fprintf(stderr, "problem inserting idle task.\n"); | ||
| 1487 | exit(-1); | ||
| 1488 | } | ||
| 1489 | } | 1081 | } |
| 1490 | 1082 | ||
| 1491 | static unsigned long total = 0, | 1083 | static unsigned long total = 0, |
| @@ -1514,7 +1106,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1514 | char level; | 1106 | char level; |
| 1515 | int show = 0; | 1107 | int show = 0; |
| 1516 | struct dso *dso = NULL; | 1108 | struct dso *dso = NULL; |
| 1517 | struct thread *thread = threads__findnew(event->ip.pid); | 1109 | struct thread *thread; |
| 1518 | u64 ip = event->ip.ip; | 1110 | u64 ip = event->ip.ip; |
| 1519 | u64 period = 1; | 1111 | u64 period = 1; |
| 1520 | struct map *map = NULL; | 1112 | struct map *map = NULL; |
| @@ -1522,12 +1114,14 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1522 | struct ip_callchain *chain = NULL; | 1114 | struct ip_callchain *chain = NULL; |
| 1523 | int cpumode; | 1115 | int cpumode; |
| 1524 | 1116 | ||
| 1117 | thread = threads__findnew(event->ip.pid, &threads, &last_match); | ||
| 1118 | |||
| 1525 | if (sample_type & PERF_SAMPLE_PERIOD) { | 1119 | if (sample_type & PERF_SAMPLE_PERIOD) { |
| 1526 | period = *(u64 *)more_data; | 1120 | period = *(u64 *)more_data; |
| 1527 | more_data += sizeof(u64); | 1121 | more_data += sizeof(u64); |
| 1528 | } | 1122 | } |
| 1529 | 1123 | ||
| 1530 | dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", | 1124 | dump_printf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", |
| 1531 | (void *)(offset + head), | 1125 | (void *)(offset + head), |
| 1532 | (void *)(long)(event->header.size), | 1126 | (void *)(long)(event->header.size), |
| 1533 | event->header.misc, | 1127 | event->header.misc, |
| @@ -1540,7 +1134,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1540 | 1134 | ||
| 1541 | chain = (void *)more_data; | 1135 | chain = (void *)more_data; |
| 1542 | 1136 | ||
| 1543 | dprintf("... chain: nr:%Lu\n", chain->nr); | 1137 | dump_printf("... chain: nr:%Lu\n", chain->nr); |
| 1544 | 1138 | ||
| 1545 | if (validate_chain(chain, event) < 0) { | 1139 | if (validate_chain(chain, event) < 0) { |
| 1546 | eprintf("call-chain problem with event, skipping it.\n"); | 1140 | eprintf("call-chain problem with event, skipping it.\n"); |
| @@ -1549,11 +1143,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1549 | 1143 | ||
| 1550 | if (dump_trace) { | 1144 | if (dump_trace) { |
| 1551 | for (i = 0; i < chain->nr; i++) | 1145 | for (i = 0; i < chain->nr; i++) |
| 1552 | dprintf("..... %2d: %016Lx\n", i, chain->ips[i]); | 1146 | dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); |
| 1553 | } | 1147 | } |
| 1554 | } | 1148 | } |
| 1555 | 1149 | ||
| 1556 | dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 1150 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
| 1557 | 1151 | ||
| 1558 | if (thread == NULL) { | 1152 | if (thread == NULL) { |
| 1559 | eprintf("problem processing %d event, skipping it.\n", | 1153 | eprintf("problem processing %d event, skipping it.\n", |
| @@ -1572,7 +1166,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1572 | 1166 | ||
| 1573 | dso = kernel_dso; | 1167 | dso = kernel_dso; |
| 1574 | 1168 | ||
| 1575 | dprintf(" ...... dso: %s\n", dso->name); | 1169 | dump_printf(" ...... dso: %s\n", dso->name); |
| 1576 | 1170 | ||
| 1577 | } else if (cpumode == PERF_EVENT_MISC_USER) { | 1171 | } else if (cpumode == PERF_EVENT_MISC_USER) { |
| 1578 | 1172 | ||
| @@ -1585,7 +1179,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1585 | 1179 | ||
| 1586 | dso = hypervisor_dso; | 1180 | dso = hypervisor_dso; |
| 1587 | 1181 | ||
| 1588 | dprintf(" ...... dso: [hypervisor]\n"); | 1182 | dump_printf(" ...... dso: [hypervisor]\n"); |
| 1589 | } | 1183 | } |
| 1590 | 1184 | ||
| 1591 | if (show & show_mask) { | 1185 | if (show & show_mask) { |
| @@ -1611,10 +1205,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1611 | static int | 1205 | static int |
| 1612 | process_mmap_event(event_t *event, unsigned long offset, unsigned long head) | 1206 | process_mmap_event(event_t *event, unsigned long offset, unsigned long head) |
| 1613 | { | 1207 | { |
| 1614 | struct thread *thread = threads__findnew(event->mmap.pid); | 1208 | struct thread *thread; |
| 1615 | struct map *map = map__new(&event->mmap); | 1209 | struct map *map = map__new(&event->mmap, cwd, cwdlen); |
| 1616 | 1210 | ||
| 1617 | dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", | 1211 | thread = threads__findnew(event->mmap.pid, &threads, &last_match); |
| 1212 | |||
| 1213 | dump_printf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", | ||
| 1618 | (void *)(offset + head), | 1214 | (void *)(offset + head), |
| 1619 | (void *)(long)(event->header.size), | 1215 | (void *)(long)(event->header.size), |
| 1620 | event->mmap.pid, | 1216 | event->mmap.pid, |
| @@ -1625,7 +1221,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1625 | event->mmap.filename); | 1221 | event->mmap.filename); |
| 1626 | 1222 | ||
| 1627 | if (thread == NULL || map == NULL) { | 1223 | if (thread == NULL || map == NULL) { |
| 1628 | dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); | 1224 | dump_printf("problem processing PERF_EVENT_MMAP, skipping event.\n"); |
| 1629 | return 0; | 1225 | return 0; |
| 1630 | } | 1226 | } |
| 1631 | 1227 | ||
| @@ -1638,16 +1234,18 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1638 | static int | 1234 | static int |
| 1639 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) | 1235 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) |
| 1640 | { | 1236 | { |
| 1641 | struct thread *thread = threads__findnew(event->comm.pid); | 1237 | struct thread *thread; |
| 1238 | |||
| 1239 | thread = threads__findnew(event->comm.pid, &threads, &last_match); | ||
| 1642 | 1240 | ||
| 1643 | dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", | 1241 | dump_printf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", |
| 1644 | (void *)(offset + head), | 1242 | (void *)(offset + head), |
| 1645 | (void *)(long)(event->header.size), | 1243 | (void *)(long)(event->header.size), |
| 1646 | event->comm.comm, event->comm.pid); | 1244 | event->comm.comm, event->comm.pid); |
| 1647 | 1245 | ||
| 1648 | if (thread == NULL || | 1246 | if (thread == NULL || |
| 1649 | thread__set_comm(thread, event->comm.comm)) { | 1247 | thread__set_comm_adjust(thread, event->comm.comm)) { |
| 1650 | dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); | 1248 | dump_printf("problem processing PERF_EVENT_COMM, skipping event.\n"); |
| 1651 | return -1; | 1249 | return -1; |
| 1652 | } | 1250 | } |
| 1653 | total_comm++; | 1251 | total_comm++; |
| @@ -1658,10 +1256,13 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1658 | static int | 1256 | static int |
| 1659 | process_task_event(event_t *event, unsigned long offset, unsigned long head) | 1257 | process_task_event(event_t *event, unsigned long offset, unsigned long head) |
| 1660 | { | 1258 | { |
| 1661 | struct thread *thread = threads__findnew(event->fork.pid); | 1259 | struct thread *thread; |
| 1662 | struct thread *parent = threads__findnew(event->fork.ppid); | 1260 | struct thread *parent; |
| 1663 | 1261 | ||
| 1664 | dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", | 1262 | thread = threads__findnew(event->fork.pid, &threads, &last_match); |
| 1263 | parent = threads__findnew(event->fork.ppid, &threads, &last_match); | ||
| 1264 | |||
| 1265 | dump_printf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", | ||
| 1665 | (void *)(offset + head), | 1266 | (void *)(offset + head), |
| 1666 | (void *)(long)(event->header.size), | 1267 | (void *)(long)(event->header.size), |
| 1667 | event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT", | 1268 | event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT", |
| @@ -1679,7 +1280,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1679 | return 0; | 1280 | return 0; |
| 1680 | 1281 | ||
| 1681 | if (!thread || !parent || thread__fork(thread, parent)) { | 1282 | if (!thread || !parent || thread__fork(thread, parent)) { |
| 1682 | dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); | 1283 | dump_printf("problem processing PERF_EVENT_FORK, skipping event.\n"); |
| 1683 | return -1; | 1284 | return -1; |
| 1684 | } | 1285 | } |
| 1685 | total_fork++; | 1286 | total_fork++; |
| @@ -1690,7 +1291,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1690 | static int | 1291 | static int |
| 1691 | process_lost_event(event_t *event, unsigned long offset, unsigned long head) | 1292 | process_lost_event(event_t *event, unsigned long offset, unsigned long head) |
| 1692 | { | 1293 | { |
| 1693 | dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", | 1294 | dump_printf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", |
| 1694 | (void *)(offset + head), | 1295 | (void *)(offset + head), |
| 1695 | (void *)(long)(event->header.size), | 1296 | (void *)(long)(event->header.size), |
| 1696 | event->lost.id, | 1297 | event->lost.id, |
| @@ -1701,67 +1302,24 @@ process_lost_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1701 | return 0; | 1302 | return 0; |
| 1702 | } | 1303 | } |
| 1703 | 1304 | ||
| 1704 | static void trace_event(event_t *event) | 1305 | static int |
| 1705 | { | 1306 | process_read_event(event_t *event, unsigned long offset, unsigned long head) |
| 1706 | unsigned char *raw_event = (void *)event; | ||
| 1707 | char *color = PERF_COLOR_BLUE; | ||
| 1708 | int i, j; | ||
| 1709 | |||
| 1710 | if (!dump_trace) | ||
| 1711 | return; | ||
| 1712 | |||
| 1713 | dprintf("."); | ||
| 1714 | cdprintf("\n. ... raw event: size %d bytes\n", event->header.size); | ||
| 1715 | |||
| 1716 | for (i = 0; i < event->header.size; i++) { | ||
| 1717 | if ((i & 15) == 0) { | ||
| 1718 | dprintf("."); | ||
| 1719 | cdprintf(" %04x: ", i); | ||
| 1720 | } | ||
| 1721 | |||
| 1722 | cdprintf(" %02x", raw_event[i]); | ||
| 1723 | |||
| 1724 | if (((i & 15) == 15) || i == event->header.size-1) { | ||
| 1725 | cdprintf(" "); | ||
| 1726 | for (j = 0; j < 15-(i & 15); j++) | ||
| 1727 | cdprintf(" "); | ||
| 1728 | for (j = 0; j < (i & 15); j++) { | ||
| 1729 | if (isprint(raw_event[i-15+j])) | ||
| 1730 | cdprintf("%c", raw_event[i-15+j]); | ||
| 1731 | else | ||
| 1732 | cdprintf("."); | ||
| 1733 | } | ||
| 1734 | cdprintf("\n"); | ||
| 1735 | } | ||
| 1736 | } | ||
| 1737 | dprintf(".\n"); | ||
| 1738 | } | ||
| 1739 | |||
| 1740 | static struct perf_header *header; | ||
| 1741 | |||
| 1742 | static struct perf_counter_attr *perf_header__find_attr(u64 id) | ||
| 1743 | { | 1307 | { |
| 1744 | int i; | 1308 | struct perf_counter_attr *attr; |
| 1745 | 1309 | ||
| 1746 | for (i = 0; i < header->attrs; i++) { | 1310 | attr = perf_header__find_attr(event->read.id, header); |
| 1747 | struct perf_header_attr *attr = header->attr[i]; | ||
| 1748 | int j; | ||
| 1749 | 1311 | ||
| 1750 | for (j = 0; j < attr->ids; j++) { | 1312 | if (show_threads) { |
| 1751 | if (attr->id[j] == id) | 1313 | const char *name = attr ? __event_name(attr->type, attr->config) |
| 1752 | return &attr->attr; | 1314 | : "unknown"; |
| 1753 | } | 1315 | perf_read_values_add_value(&show_threads_values, |
| 1316 | event->read.pid, event->read.tid, | ||
| 1317 | event->read.id, | ||
| 1318 | name, | ||
| 1319 | event->read.value); | ||
| 1754 | } | 1320 | } |
| 1755 | 1321 | ||
| 1756 | return NULL; | 1322 | dump_printf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n", |
| 1757 | } | ||
| 1758 | |||
| 1759 | static int | ||
| 1760 | process_read_event(event_t *event, unsigned long offset, unsigned long head) | ||
| 1761 | { | ||
| 1762 | struct perf_counter_attr *attr = perf_header__find_attr(event->read.id); | ||
| 1763 | |||
| 1764 | dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n", | ||
| 1765 | (void *)(offset + head), | 1323 | (void *)(offset + head), |
| 1766 | (void *)(long)(event->header.size), | 1324 | (void *)(long)(event->header.size), |
| 1767 | event->read.pid, | 1325 | event->read.pid, |
| @@ -1813,34 +1371,22 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1813 | return 0; | 1371 | return 0; |
| 1814 | } | 1372 | } |
| 1815 | 1373 | ||
| 1816 | static u64 perf_header__sample_type(void) | ||
| 1817 | { | ||
| 1818 | u64 sample_type = 0; | ||
| 1819 | int i; | ||
| 1820 | |||
| 1821 | for (i = 0; i < header->attrs; i++) { | ||
| 1822 | struct perf_header_attr *attr = header->attr[i]; | ||
| 1823 | |||
| 1824 | if (!sample_type) | ||
| 1825 | sample_type = attr->attr.sample_type; | ||
| 1826 | else if (sample_type != attr->attr.sample_type) | ||
| 1827 | die("non matching sample_type"); | ||
| 1828 | } | ||
| 1829 | |||
| 1830 | return sample_type; | ||
| 1831 | } | ||
| 1832 | |||
| 1833 | static int __cmd_report(void) | 1374 | static int __cmd_report(void) |
| 1834 | { | 1375 | { |
| 1835 | int ret, rc = EXIT_FAILURE; | 1376 | int ret, rc = EXIT_FAILURE; |
| 1836 | unsigned long offset = 0; | 1377 | unsigned long offset = 0; |
| 1837 | unsigned long head, shift; | 1378 | unsigned long head, shift; |
| 1838 | struct stat stat; | 1379 | struct stat input_stat; |
| 1380 | struct thread *idle; | ||
| 1839 | event_t *event; | 1381 | event_t *event; |
| 1840 | uint32_t size; | 1382 | uint32_t size; |
| 1841 | char *buf; | 1383 | char *buf; |
| 1842 | 1384 | ||
| 1843 | register_idle_thread(); | 1385 | idle = register_idle_thread(&threads, &last_match); |
| 1386 | thread__comm_adjust(idle); | ||
| 1387 | |||
| 1388 | if (show_threads) | ||
| 1389 | perf_read_values_init(&show_threads_values); | ||
| 1844 | 1390 | ||
| 1845 | input = open(input_name, O_RDONLY); | 1391 | input = open(input_name, O_RDONLY); |
| 1846 | if (input < 0) { | 1392 | if (input < 0) { |
| @@ -1851,18 +1397,18 @@ static int __cmd_report(void) | |||
| 1851 | exit(-1); | 1397 | exit(-1); |
| 1852 | } | 1398 | } |
| 1853 | 1399 | ||
| 1854 | ret = fstat(input, &stat); | 1400 | ret = fstat(input, &input_stat); |
| 1855 | if (ret < 0) { | 1401 | if (ret < 0) { |
| 1856 | perror("failed to stat file"); | 1402 | perror("failed to stat file"); |
| 1857 | exit(-1); | 1403 | exit(-1); |
| 1858 | } | 1404 | } |
| 1859 | 1405 | ||
| 1860 | if (!force && (stat.st_uid != geteuid())) { | 1406 | if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { |
| 1861 | fprintf(stderr, "file: %s not owned by current user\n", input_name); | 1407 | fprintf(stderr, "file: %s not owned by current user or root\n", input_name); |
| 1862 | exit(-1); | 1408 | exit(-1); |
| 1863 | } | 1409 | } |
| 1864 | 1410 | ||
| 1865 | if (!stat.st_size) { | 1411 | if (!input_stat.st_size) { |
| 1866 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | 1412 | fprintf(stderr, "zero-sized file, nothing to do!\n"); |
| 1867 | exit(0); | 1413 | exit(0); |
| 1868 | } | 1414 | } |
| @@ -1870,7 +1416,7 @@ static int __cmd_report(void) | |||
| 1870 | header = perf_header__read(input); | 1416 | header = perf_header__read(input); |
| 1871 | head = header->data_offset; | 1417 | head = header->data_offset; |
| 1872 | 1418 | ||
| 1873 | sample_type = perf_header__sample_type(); | 1419 | sample_type = perf_header__sample_type(header); |
| 1874 | 1420 | ||
| 1875 | if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) { | 1421 | if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) { |
| 1876 | if (sort__has_parent) { | 1422 | if (sort__has_parent) { |
| @@ -1880,7 +1426,7 @@ static int __cmd_report(void) | |||
| 1880 | exit(-1); | 1426 | exit(-1); |
| 1881 | } | 1427 | } |
| 1882 | if (callchain) { | 1428 | if (callchain) { |
| 1883 | fprintf(stderr, "selected -c but no callchain data." | 1429 | fprintf(stderr, "selected -g but no callchain data." |
| 1884 | " Did you call perf record without" | 1430 | " Did you call perf record without" |
| 1885 | " -g?\n"); | 1431 | " -g?\n"); |
| 1886 | exit(-1); | 1432 | exit(-1); |
| @@ -1930,12 +1476,12 @@ more: | |||
| 1930 | size = 8; | 1476 | size = 8; |
| 1931 | 1477 | ||
| 1932 | if (head + event->header.size >= page_size * mmap_window) { | 1478 | if (head + event->header.size >= page_size * mmap_window) { |
| 1933 | int ret; | 1479 | int munmap_ret; |
| 1934 | 1480 | ||
| 1935 | shift = page_size * (head / page_size); | 1481 | shift = page_size * (head / page_size); |
| 1936 | 1482 | ||
| 1937 | ret = munmap(buf, page_size * mmap_window); | 1483 | munmap_ret = munmap(buf, page_size * mmap_window); |
| 1938 | assert(ret == 0); | 1484 | assert(munmap_ret == 0); |
| 1939 | 1485 | ||
| 1940 | offset += shift; | 1486 | offset += shift; |
| 1941 | head -= shift; | 1487 | head -= shift; |
| @@ -1944,14 +1490,14 @@ more: | |||
| 1944 | 1490 | ||
| 1945 | size = event->header.size; | 1491 | size = event->header.size; |
| 1946 | 1492 | ||
| 1947 | dprintf("\n%p [%p]: event: %d\n", | 1493 | dump_printf("\n%p [%p]: event: %d\n", |
| 1948 | (void *)(offset + head), | 1494 | (void *)(offset + head), |
| 1949 | (void *)(long)event->header.size, | 1495 | (void *)(long)event->header.size, |
| 1950 | event->header.type); | 1496 | event->header.type); |
| 1951 | 1497 | ||
| 1952 | if (!size || process_event(event, offset, head) < 0) { | 1498 | if (!size || process_event(event, offset, head) < 0) { |
| 1953 | 1499 | ||
| 1954 | dprintf("%p [%p]: skipping unknown header type: %d\n", | 1500 | dump_printf("%p [%p]: skipping unknown header type: %d\n", |
| 1955 | (void *)(offset + head), | 1501 | (void *)(offset + head), |
| 1956 | (void *)(long)(event->header.size), | 1502 | (void *)(long)(event->header.size), |
| 1957 | event->header.type); | 1503 | event->header.type); |
| @@ -1974,25 +1520,25 @@ more: | |||
| 1974 | if (offset + head >= header->data_offset + header->data_size) | 1520 | if (offset + head >= header->data_offset + header->data_size) |
| 1975 | goto done; | 1521 | goto done; |
| 1976 | 1522 | ||
| 1977 | if (offset + head < (unsigned long)stat.st_size) | 1523 | if (offset + head < (unsigned long)input_stat.st_size) |
| 1978 | goto more; | 1524 | goto more; |
| 1979 | 1525 | ||
| 1980 | done: | 1526 | done: |
| 1981 | rc = EXIT_SUCCESS; | 1527 | rc = EXIT_SUCCESS; |
| 1982 | close(input); | 1528 | close(input); |
| 1983 | 1529 | ||
| 1984 | dprintf(" IP events: %10ld\n", total); | 1530 | dump_printf(" IP events: %10ld\n", total); |
| 1985 | dprintf(" mmap events: %10ld\n", total_mmap); | 1531 | dump_printf(" mmap events: %10ld\n", total_mmap); |
| 1986 | dprintf(" comm events: %10ld\n", total_comm); | 1532 | dump_printf(" comm events: %10ld\n", total_comm); |
| 1987 | dprintf(" fork events: %10ld\n", total_fork); | 1533 | dump_printf(" fork events: %10ld\n", total_fork); |
| 1988 | dprintf(" lost events: %10ld\n", total_lost); | 1534 | dump_printf(" lost events: %10ld\n", total_lost); |
| 1989 | dprintf(" unknown events: %10ld\n", total_unknown); | 1535 | dump_printf(" unknown events: %10ld\n", total_unknown); |
| 1990 | 1536 | ||
| 1991 | if (dump_trace) | 1537 | if (dump_trace) |
| 1992 | return 0; | 1538 | return 0; |
| 1993 | 1539 | ||
| 1994 | if (verbose >= 3) | 1540 | if (verbose >= 3) |
| 1995 | threads__fprintf(stdout); | 1541 | threads__fprintf(stdout, &threads); |
| 1996 | 1542 | ||
| 1997 | if (verbose >= 2) | 1543 | if (verbose >= 2) |
| 1998 | dsos__fprintf(stdout); | 1544 | dsos__fprintf(stdout); |
| @@ -2001,6 +1547,9 @@ done: | |||
| 2001 | output__resort(total); | 1547 | output__resort(total); |
| 2002 | output__fprintf(stdout, total); | 1548 | output__fprintf(stdout, total); |
| 2003 | 1549 | ||
| 1550 | if (show_threads) | ||
| 1551 | perf_read_values_destroy(&show_threads_values); | ||
| 1552 | |||
| 2004 | return rc; | 1553 | return rc; |
| 2005 | } | 1554 | } |
| 2006 | 1555 | ||
| @@ -2069,12 +1618,16 @@ static const struct option options[] = { | |||
| 2069 | "be more verbose (show symbol address, etc)"), | 1618 | "be more verbose (show symbol address, etc)"), |
| 2070 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1619 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
| 2071 | "dump raw trace in ASCII"), | 1620 | "dump raw trace in ASCII"), |
| 2072 | OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), | 1621 | OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), |
| 2073 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | 1622 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), |
| 2074 | OPT_BOOLEAN('m', "modules", &modules, | 1623 | OPT_BOOLEAN('m', "modules", &modules, |
| 2075 | "load module symbols - WARNING: use only with -k and LIVE kernel"), | 1624 | "load module symbols - WARNING: use only with -k and LIVE kernel"), |
| 2076 | OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, | 1625 | OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, |
| 2077 | "Show a column with the number of samples"), | 1626 | "Show a column with the number of samples"), |
| 1627 | OPT_BOOLEAN('T', "threads", &show_threads, | ||
| 1628 | "Show per-thread event counters"), | ||
| 1629 | OPT_STRING(0, "pretty", &pretty_printing_style, "key", | ||
| 1630 | "pretty printing style key: normal raw"), | ||
| 2078 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | 1631 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", |
| 2079 | "sort by key(s): pid, comm, dso, symbol, parent"), | 1632 | "sort by key(s): pid, comm, dso, symbol, parent"), |
| 2080 | OPT_BOOLEAN('P', "full-paths", &full_paths, | 1633 | OPT_BOOLEAN('P', "full-paths", &full_paths, |
