diff options
author | Ingo Molnar <mingo@kernel.org> | 2013-11-04 15:14:04 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-11-04 15:14:04 -0500 |
commit | 87968f94fbea47df334502a0db645833ce8a848b (patch) | |
tree | a8acb87cf151aed23aa0f64d2f78567b6eaffc75 | |
parent | 2a3ede8cb2ddee5885518e4232aca13056f9a6e0 (diff) | |
parent | 6d862b8c14ba539c7c87ffc77f2e1d6dc9630c4d (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
* Add new COMM infrastructure, further improving histogram processing, from
Frédéric Weisbecker, one fix from Namhyung Kim.
* Enhance option parse error message, showing just the help lines of the
options affected, from Namhyung Kim.
* Fixup PERF_SAMPLE_TRANSACTION handling in sample synthesizing and
'perf test', from Adrian Hunter.
* Set up output options for in-stream attributes, from Adrian Hunter.
* Fix 32-bit cross build, from Adrian Hunter.
* Fix libunwind build and feature detection for 32-bit build, from Adrian Hunter.
* Always use perf_evsel__set_sample_bit to set sample_type, from Adrian Hunter.
perf evlist: Add a debug print if event buffer mmap fails
* Add missing data.h into LIB_H headers, fix from Jiri Olsa.
* libtraceevent updates from upstream trace-cmd repo, from Steven Rostedt.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
35 files changed, 722 insertions, 303 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index d1c2a6a4cd32..8f450adaa9c2 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -305,6 +305,11 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid) | |||
305 | return 0; | 305 | return 0; |
306 | } | 306 | } |
307 | 307 | ||
308 | void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock) | ||
309 | { | ||
310 | pevent->trace_clock = trace_clock; | ||
311 | } | ||
312 | |||
308 | struct func_map { | 313 | struct func_map { |
309 | unsigned long long addr; | 314 | unsigned long long addr; |
310 | char *func; | 315 | char *func; |
@@ -599,10 +604,11 @@ find_printk(struct pevent *pevent, unsigned long long addr) | |||
599 | * This registers a string by the address it was stored in the kernel. | 604 | * This registers a string by the address it was stored in the kernel. |
600 | * The @fmt passed in is duplicated. | 605 | * The @fmt passed in is duplicated. |
601 | */ | 606 | */ |
602 | int pevent_register_print_string(struct pevent *pevent, char *fmt, | 607 | int pevent_register_print_string(struct pevent *pevent, const char *fmt, |
603 | unsigned long long addr) | 608 | unsigned long long addr) |
604 | { | 609 | { |
605 | struct printk_list *item = malloc(sizeof(*item)); | 610 | struct printk_list *item = malloc(sizeof(*item)); |
611 | char *p; | ||
606 | 612 | ||
607 | if (!item) | 613 | if (!item) |
608 | return -1; | 614 | return -1; |
@@ -610,10 +616,21 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt, | |||
610 | item->next = pevent->printklist; | 616 | item->next = pevent->printklist; |
611 | item->addr = addr; | 617 | item->addr = addr; |
612 | 618 | ||
619 | /* Strip off quotes and '\n' from the end */ | ||
620 | if (fmt[0] == '"') | ||
621 | fmt++; | ||
613 | item->printk = strdup(fmt); | 622 | item->printk = strdup(fmt); |
614 | if (!item->printk) | 623 | if (!item->printk) |
615 | goto out_free; | 624 | goto out_free; |
616 | 625 | ||
626 | p = item->printk + strlen(item->printk) - 1; | ||
627 | if (*p == '"') | ||
628 | *p = 0; | ||
629 | |||
630 | p -= 2; | ||
631 | if (strcmp(p, "\\n") == 0) | ||
632 | *p = 0; | ||
633 | |||
617 | pevent->printklist = item; | 634 | pevent->printklist = item; |
618 | pevent->printk_count++; | 635 | pevent->printk_count++; |
619 | 636 | ||
@@ -3488,6 +3505,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3488 | struct pevent *pevent = event->pevent; | 3505 | struct pevent *pevent = event->pevent; |
3489 | struct print_flag_sym *flag; | 3506 | struct print_flag_sym *flag; |
3490 | struct format_field *field; | 3507 | struct format_field *field; |
3508 | struct printk_map *printk; | ||
3491 | unsigned long long val, fval; | 3509 | unsigned long long val, fval; |
3492 | unsigned long addr; | 3510 | unsigned long addr; |
3493 | char *str; | 3511 | char *str; |
@@ -3523,7 +3541,12 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3523 | if (!(field->flags & FIELD_IS_ARRAY) && | 3541 | if (!(field->flags & FIELD_IS_ARRAY) && |
3524 | field->size == pevent->long_size) { | 3542 | field->size == pevent->long_size) { |
3525 | addr = *(unsigned long *)(data + field->offset); | 3543 | addr = *(unsigned long *)(data + field->offset); |
3526 | trace_seq_printf(s, "%lx", addr); | 3544 | /* Check if it matches a print format */ |
3545 | printk = find_printk(pevent, addr); | ||
3546 | if (printk) | ||
3547 | trace_seq_puts(s, printk->printk); | ||
3548 | else | ||
3549 | trace_seq_printf(s, "%lx", addr); | ||
3527 | break; | 3550 | break; |
3528 | } | 3551 | } |
3529 | str = malloc(len + 1); | 3552 | str = malloc(len + 1); |
@@ -3565,15 +3588,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3565 | } | 3588 | } |
3566 | break; | 3589 | break; |
3567 | case PRINT_HEX: | 3590 | case PRINT_HEX: |
3568 | field = arg->hex.field->field.field; | 3591 | if (arg->hex.field->type == PRINT_DYNAMIC_ARRAY) { |
3569 | if (!field) { | 3592 | unsigned long offset; |
3570 | str = arg->hex.field->field.name; | 3593 | offset = pevent_read_number(pevent, |
3571 | field = pevent_find_any_field(event, str); | 3594 | data + arg->hex.field->dynarray.field->offset, |
3572 | if (!field) | 3595 | arg->hex.field->dynarray.field->size); |
3573 | goto out_warning_field; | 3596 | hex = data + (offset & 0xffff); |
3574 | arg->hex.field->field.field = field; | 3597 | } else { |
3598 | field = arg->hex.field->field.field; | ||
3599 | if (!field) { | ||
3600 | str = arg->hex.field->field.name; | ||
3601 | field = pevent_find_any_field(event, str); | ||
3602 | if (!field) | ||
3603 | goto out_warning_field; | ||
3604 | arg->hex.field->field.field = field; | ||
3605 | } | ||
3606 | hex = data + field->offset; | ||
3575 | } | 3607 | } |
3576 | hex = data + field->offset; | ||
3577 | len = eval_num_arg(data, size, event, arg->hex.size); | 3608 | len = eval_num_arg(data, size, event, arg->hex.size); |
3578 | for (i = 0; i < len; i++) { | 3609 | for (i = 0; i < len; i++) { |
3579 | if (i) | 3610 | if (i) |
@@ -3771,8 +3802,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc | |||
3771 | if (asprintf(&arg->atom.atom, "%lld", ip) < 0) | 3802 | if (asprintf(&arg->atom.atom, "%lld", ip) < 0) |
3772 | goto out_free; | 3803 | goto out_free; |
3773 | 3804 | ||
3774 | /* skip the first "%pf : " */ | 3805 | /* skip the first "%pf: " */ |
3775 | for (ptr = fmt + 6, bptr = data + field->offset; | 3806 | for (ptr = fmt + 5, bptr = data + field->offset; |
3776 | bptr < data + size && *ptr; ptr++) { | 3807 | bptr < data + size && *ptr; ptr++) { |
3777 | int ls = 0; | 3808 | int ls = 0; |
3778 | 3809 | ||
@@ -3882,7 +3913,6 @@ get_bprint_format(void *data, int size __maybe_unused, | |||
3882 | struct format_field *field; | 3913 | struct format_field *field; |
3883 | struct printk_map *printk; | 3914 | struct printk_map *printk; |
3884 | char *format; | 3915 | char *format; |
3885 | char *p; | ||
3886 | 3916 | ||
3887 | field = pevent->bprint_fmt_field; | 3917 | field = pevent->bprint_fmt_field; |
3888 | 3918 | ||
@@ -3899,25 +3929,13 @@ get_bprint_format(void *data, int size __maybe_unused, | |||
3899 | 3929 | ||
3900 | printk = find_printk(pevent, addr); | 3930 | printk = find_printk(pevent, addr); |
3901 | if (!printk) { | 3931 | if (!printk) { |
3902 | if (asprintf(&format, "%%pf : (NO FORMAT FOUND at %llx)\n", addr) < 0) | 3932 | if (asprintf(&format, "%%pf: (NO FORMAT FOUND at %llx)\n", addr) < 0) |
3903 | return NULL; | 3933 | return NULL; |
3904 | return format; | 3934 | return format; |
3905 | } | 3935 | } |
3906 | 3936 | ||
3907 | p = printk->printk; | 3937 | if (asprintf(&format, "%s: %s", "%pf", printk->printk) < 0) |
3908 | /* Remove any quotes. */ | ||
3909 | if (*p == '"') | ||
3910 | p++; | ||
3911 | if (asprintf(&format, "%s : %s", "%pf", p) < 0) | ||
3912 | return NULL; | 3938 | return NULL; |
3913 | /* remove ending quotes and new line since we will add one too */ | ||
3914 | p = format + strlen(format) - 1; | ||
3915 | if (*p == '"') | ||
3916 | *p = 0; | ||
3917 | |||
3918 | p -= 2; | ||
3919 | if (strcmp(p, "\\n") == 0) | ||
3920 | *p = 0; | ||
3921 | 3939 | ||
3922 | return format; | 3940 | return format; |
3923 | } | 3941 | } |
@@ -3963,7 +3981,7 @@ static int is_printable_array(char *p, unsigned int len) | |||
3963 | unsigned int i; | 3981 | unsigned int i; |
3964 | 3982 | ||
3965 | for (i = 0; i < len && p[i]; i++) | 3983 | for (i = 0; i < len && p[i]; i++) |
3966 | if (!isprint(p[i])) | 3984 | if (!isprint(p[i]) && !isspace(p[i])) |
3967 | return 0; | 3985 | return 0; |
3968 | return 1; | 3986 | return 1; |
3969 | } | 3987 | } |
@@ -4428,11 +4446,11 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event, | |||
4428 | { | 4446 | { |
4429 | int print_pretty = 1; | 4447 | int print_pretty = 1; |
4430 | 4448 | ||
4431 | if (event->pevent->print_raw) | 4449 | if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW)) |
4432 | print_event_fields(s, record->data, record->size, event); | 4450 | print_event_fields(s, record->data, record->size, event); |
4433 | else { | 4451 | else { |
4434 | 4452 | ||
4435 | if (event->handler) | 4453 | if (event->handler && !(event->flags & EVENT_FL_NOHANDLE)) |
4436 | print_pretty = event->handler(s, record, event, | 4454 | print_pretty = event->handler(s, record, event, |
4437 | event->context); | 4455 | event->context); |
4438 | 4456 | ||
@@ -4443,8 +4461,21 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event, | |||
4443 | trace_seq_terminate(s); | 4461 | trace_seq_terminate(s); |
4444 | } | 4462 | } |
4445 | 4463 | ||
4464 | static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock) | ||
4465 | { | ||
4466 | if (!use_trace_clock) | ||
4467 | return true; | ||
4468 | |||
4469 | if (!strcmp(trace_clock, "local") || !strcmp(trace_clock, "global") | ||
4470 | || !strcmp(trace_clock, "uptime") || !strcmp(trace_clock, "perf")) | ||
4471 | return true; | ||
4472 | |||
4473 | /* trace_clock is setting in tsc or counter mode */ | ||
4474 | return false; | ||
4475 | } | ||
4476 | |||
4446 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | 4477 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, |
4447 | struct pevent_record *record) | 4478 | struct pevent_record *record, bool use_trace_clock) |
4448 | { | 4479 | { |
4449 | static const char *spaces = " "; /* 20 spaces */ | 4480 | static const char *spaces = " "; /* 20 spaces */ |
4450 | struct event_format *event; | 4481 | struct event_format *event; |
@@ -4457,9 +4488,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | |||
4457 | int pid; | 4488 | int pid; |
4458 | int len; | 4489 | int len; |
4459 | int p; | 4490 | int p; |
4491 | bool use_usec_format; | ||
4460 | 4492 | ||
4461 | secs = record->ts / NSECS_PER_SEC; | 4493 | use_usec_format = is_timestamp_in_us(pevent->trace_clock, |
4462 | nsecs = record->ts - secs * NSECS_PER_SEC; | 4494 | use_trace_clock); |
4495 | if (use_usec_format) { | ||
4496 | secs = record->ts / NSECS_PER_SEC; | ||
4497 | nsecs = record->ts - secs * NSECS_PER_SEC; | ||
4498 | } | ||
4463 | 4499 | ||
4464 | if (record->size < 0) { | 4500 | if (record->size < 0) { |
4465 | do_warning("ug! negative record size %d", record->size); | 4501 | do_warning("ug! negative record size %d", record->size); |
@@ -4484,15 +4520,20 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | |||
4484 | } else | 4520 | } else |
4485 | trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu); | 4521 | trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu); |
4486 | 4522 | ||
4487 | if (pevent->flags & PEVENT_NSEC_OUTPUT) { | 4523 | if (use_usec_format) { |
4488 | usecs = nsecs; | 4524 | if (pevent->flags & PEVENT_NSEC_OUTPUT) { |
4489 | p = 9; | 4525 | usecs = nsecs; |
4490 | } else { | 4526 | p = 9; |
4491 | usecs = (nsecs + 500) / NSECS_PER_USEC; | 4527 | } else { |
4492 | p = 6; | 4528 | usecs = (nsecs + 500) / NSECS_PER_USEC; |
4493 | } | 4529 | p = 6; |
4530 | } | ||
4494 | 4531 | ||
4495 | trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name); | 4532 | trace_seq_printf(s, " %5lu.%0*lu: %s: ", |
4533 | secs, p, usecs, event->name); | ||
4534 | } else | ||
4535 | trace_seq_printf(s, " %12llu: %s: ", | ||
4536 | record->ts, event->name); | ||
4496 | 4537 | ||
4497 | /* Space out the event names evenly. */ | 4538 | /* Space out the event names evenly. */ |
4498 | len = strlen(event->name); | 4539 | len = strlen(event->name); |
@@ -5326,6 +5367,48 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, | |||
5326 | return -1; | 5367 | return -1; |
5327 | } | 5368 | } |
5328 | 5369 | ||
5370 | /** | ||
5371 | * pevent_print_func_field - print a field and a format for function pointers | ||
5372 | * @s: The seq to print to | ||
5373 | * @fmt: The printf format to print the field with. | ||
5374 | * @event: the event that the field is for | ||
5375 | * @name: The name of the field | ||
5376 | * @record: The record with the field name. | ||
5377 | * @err: print default error if failed. | ||
5378 | * | ||
5379 | * Returns: 0 on success, -1 field not found, or 1 if buffer is full. | ||
5380 | */ | ||
5381 | int pevent_print_func_field(struct trace_seq *s, const char *fmt, | ||
5382 | struct event_format *event, const char *name, | ||
5383 | struct pevent_record *record, int err) | ||
5384 | { | ||
5385 | struct format_field *field = pevent_find_field(event, name); | ||
5386 | struct pevent *pevent = event->pevent; | ||
5387 | unsigned long long val; | ||
5388 | struct func_map *func; | ||
5389 | char tmp[128]; | ||
5390 | |||
5391 | if (!field) | ||
5392 | goto failed; | ||
5393 | |||
5394 | if (pevent_read_number_field(field, record->data, &val)) | ||
5395 | goto failed; | ||
5396 | |||
5397 | func = find_func(pevent, val); | ||
5398 | |||
5399 | if (func) | ||
5400 | snprintf(tmp, 128, "%s/0x%llx", func->func, func->addr - val); | ||
5401 | else | ||
5402 | sprintf(tmp, "0x%08llx", val); | ||
5403 | |||
5404 | return trace_seq_printf(s, fmt, tmp); | ||
5405 | |||
5406 | failed: | ||
5407 | if (err) | ||
5408 | trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name); | ||
5409 | return -1; | ||
5410 | } | ||
5411 | |||
5329 | static void free_func_handle(struct pevent_function_handler *func) | 5412 | static void free_func_handle(struct pevent_function_handler *func) |
5330 | { | 5413 | { |
5331 | struct pevent_func_params *params; | 5414 | struct pevent_func_params *params; |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index c37b2026d04a..8d73d2594f65 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #ifndef _PARSE_EVENTS_H | 20 | #ifndef _PARSE_EVENTS_H |
21 | #define _PARSE_EVENTS_H | 21 | #define _PARSE_EVENTS_H |
22 | 22 | ||
23 | #include <stdbool.h> | ||
23 | #include <stdarg.h> | 24 | #include <stdarg.h> |
24 | #include <regex.h> | 25 | #include <regex.h> |
25 | 26 | ||
@@ -307,6 +308,8 @@ enum { | |||
307 | EVENT_FL_ISBPRINT = 0x04, | 308 | EVENT_FL_ISBPRINT = 0x04, |
308 | EVENT_FL_ISFUNCENT = 0x10, | 309 | EVENT_FL_ISFUNCENT = 0x10, |
309 | EVENT_FL_ISFUNCRET = 0x20, | 310 | EVENT_FL_ISFUNCRET = 0x20, |
311 | EVENT_FL_NOHANDLE = 0x40, | ||
312 | EVENT_FL_PRINTRAW = 0x80, | ||
310 | 313 | ||
311 | EVENT_FL_FAILED = 0x80000000 | 314 | EVENT_FL_FAILED = 0x80000000 |
312 | }; | 315 | }; |
@@ -450,6 +453,8 @@ struct pevent { | |||
450 | 453 | ||
451 | /* cache */ | 454 | /* cache */ |
452 | struct event_format *last_event; | 455 | struct event_format *last_event; |
456 | |||
457 | char *trace_clock; | ||
453 | }; | 458 | }; |
454 | 459 | ||
455 | static inline void pevent_set_flag(struct pevent *pevent, int flag) | 460 | static inline void pevent_set_flag(struct pevent *pevent, int flag) |
@@ -527,14 +532,15 @@ enum trace_flag_type { | |||
527 | }; | 532 | }; |
528 | 533 | ||
529 | int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); | 534 | int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); |
535 | void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock); | ||
530 | int pevent_register_function(struct pevent *pevent, char *name, | 536 | int pevent_register_function(struct pevent *pevent, char *name, |
531 | unsigned long long addr, char *mod); | 537 | unsigned long long addr, char *mod); |
532 | int pevent_register_print_string(struct pevent *pevent, char *fmt, | 538 | int pevent_register_print_string(struct pevent *pevent, const char *fmt, |
533 | unsigned long long addr); | 539 | unsigned long long addr); |
534 | int pevent_pid_is_registered(struct pevent *pevent, int pid); | 540 | int pevent_pid_is_registered(struct pevent *pevent, int pid); |
535 | 541 | ||
536 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | 542 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, |
537 | struct pevent_record *record); | 543 | struct pevent_record *record, bool use_trace_clock); |
538 | 544 | ||
539 | int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, | 545 | int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, |
540 | int long_size); | 546 | int long_size); |
@@ -563,6 +569,10 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, | |||
563 | struct event_format *event, const char *name, | 569 | struct event_format *event, const char *name, |
564 | struct pevent_record *record, int err); | 570 | struct pevent_record *record, int err); |
565 | 571 | ||
572 | int pevent_print_func_field(struct trace_seq *s, const char *fmt, | ||
573 | struct event_format *event, const char *name, | ||
574 | struct pevent_record *record, int err); | ||
575 | |||
566 | int pevent_register_event_handler(struct pevent *pevent, int id, | 576 | int pevent_register_event_handler(struct pevent *pevent, int id, |
567 | const char *sys_name, const char *event_name, | 577 | const char *sys_name, const char *event_name, |
568 | pevent_event_handler_func func, void *context); | 578 | pevent_event_handler_func func, void *context); |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 8a9ca3836043..5b8639025aae 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -273,6 +273,7 @@ LIB_H += util/color.h | |||
273 | LIB_H += util/values.h | 273 | LIB_H += util/values.h |
274 | LIB_H += util/sort.h | 274 | LIB_H += util/sort.h |
275 | LIB_H += util/hist.h | 275 | LIB_H += util/hist.h |
276 | LIB_H += util/comm.h | ||
276 | LIB_H += util/thread.h | 277 | LIB_H += util/thread.h |
277 | LIB_H += util/thread_map.h | 278 | LIB_H += util/thread_map.h |
278 | LIB_H += util/trace-event.h | 279 | LIB_H += util/trace-event.h |
@@ -295,6 +296,7 @@ LIB_H += ui/helpline.h | |||
295 | LIB_H += ui/progress.h | 296 | LIB_H += ui/progress.h |
296 | LIB_H += ui/util.h | 297 | LIB_H += ui/util.h |
297 | LIB_H += ui/ui.h | 298 | LIB_H += ui/ui.h |
299 | LIB_H += util/data.h | ||
298 | 300 | ||
299 | LIB_OBJS += $(OUTPUT)util/abspath.o | 301 | LIB_OBJS += $(OUTPUT)util/abspath.o |
300 | LIB_OBJS += $(OUTPUT)util/alias.o | 302 | LIB_OBJS += $(OUTPUT)util/alias.o |
@@ -340,6 +342,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o | |||
340 | LIB_OBJS += $(OUTPUT)util/map.o | 342 | LIB_OBJS += $(OUTPUT)util/map.o |
341 | LIB_OBJS += $(OUTPUT)util/pstack.o | 343 | LIB_OBJS += $(OUTPUT)util/pstack.o |
342 | LIB_OBJS += $(OUTPUT)util/session.o | 344 | LIB_OBJS += $(OUTPUT)util/session.o |
345 | LIB_OBJS += $(OUTPUT)util/comm.o | ||
343 | LIB_OBJS += $(OUTPUT)util/thread.o | 346 | LIB_OBJS += $(OUTPUT)util/thread.o |
344 | LIB_OBJS += $(OUTPUT)util/thread_map.o | 347 | LIB_OBJS += $(OUTPUT)util/thread_map.o |
345 | LIB_OBJS += $(OUTPUT)util/trace-event-parse.o | 348 | LIB_OBJS += $(OUTPUT)util/trace-event-parse.o |
@@ -708,7 +711,7 @@ $(LIB_FILE): $(LIB_OBJS) | |||
708 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) | 711 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) |
709 | 712 | ||
710 | $(LIBTRACEEVENT): $(TE_SOURCES) | 713 | $(LIBTRACEEVENT): $(TE_SOURCES) |
711 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libtraceevent.a | 714 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a |
712 | 715 | ||
713 | $(LIBTRACEEVENT)-clean: | 716 | $(LIBTRACEEVENT)-clean: |
714 | $(call QUIET_CLEAN, libtraceevent) | 717 | $(call QUIET_CLEAN, libtraceevent) |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 1126382659a9..a28970f7ddfb 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -315,7 +315,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
315 | return -1; | 315 | return -1; |
316 | } | 316 | } |
317 | 317 | ||
318 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); | 318 | dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); |
319 | 319 | ||
320 | if (evsel->handler.func != NULL) { | 320 | if (evsel->handler.func != NULL) { |
321 | tracepoint_handler f = evsel->handler.func; | 321 | tracepoint_handler f = evsel->handler.func; |
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 33c7253295b9..35f9aaa565cc 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
@@ -767,7 +767,7 @@ static void dump_threads(void) | |||
767 | while (node) { | 767 | while (node) { |
768 | st = container_of(node, struct thread_stat, rb); | 768 | st = container_of(node, struct thread_stat, rb); |
769 | t = perf_session__findnew(session, st->tid); | 769 | t = perf_session__findnew(session, st->tid); |
770 | pr_info("%10d: %s\n", st->tid, t->comm); | 770 | pr_info("%10d: %s\n", st->tid, thread__comm_str(t)); |
771 | node = rb_next(node); | 771 | node = rb_next(node); |
772 | }; | 772 | }; |
773 | } | 773 | } |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 98d3891392e2..25f83d5d66fd 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -905,13 +905,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
905 | input_name = "perf.data"; | 905 | input_name = "perf.data"; |
906 | } | 906 | } |
907 | 907 | ||
908 | if (strcmp(input_name, "-") != 0) | ||
909 | setup_browser(true); | ||
910 | else { | ||
911 | use_browser = 0; | ||
912 | perf_hpp__init(); | ||
913 | } | ||
914 | |||
915 | file.path = input_name; | 908 | file.path = input_name; |
916 | file.force = report.force; | 909 | file.force = report.force; |
917 | 910 | ||
@@ -954,8 +947,22 @@ repeat: | |||
954 | sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; | 947 | sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; |
955 | } | 948 | } |
956 | 949 | ||
957 | if (setup_sorting() < 0) | 950 | if (setup_sorting() < 0) { |
958 | usage_with_options(report_usage, options); | 951 | parse_options_usage(report_usage, options, "s", 1); |
952 | goto error; | ||
953 | } | ||
954 | |||
955 | if (parent_pattern != default_parent_pattern) { | ||
956 | if (sort_dimension__add("parent") < 0) | ||
957 | goto error; | ||
958 | } | ||
959 | |||
960 | if (strcmp(input_name, "-") != 0) | ||
961 | setup_browser(true); | ||
962 | else { | ||
963 | use_browser = 0; | ||
964 | perf_hpp__init(); | ||
965 | } | ||
959 | 966 | ||
960 | /* | 967 | /* |
961 | * Only in the TUI browser we are doing integrated annotation, | 968 | * Only in the TUI browser we are doing integrated annotation, |
@@ -986,11 +993,6 @@ repeat: | |||
986 | if (symbol__init() < 0) | 993 | if (symbol__init() < 0) |
987 | goto error; | 994 | goto error; |
988 | 995 | ||
989 | if (parent_pattern != default_parent_pattern) { | ||
990 | if (sort_dimension__add("parent") < 0) | ||
991 | goto error; | ||
992 | } | ||
993 | |||
994 | if (argc) { | 996 | if (argc) { |
995 | /* | 997 | /* |
996 | * Special case: if there's an argument left then assume that | 998 | * Special case: if there's an argument left then assume that |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index ddb5dc15be17..a81ab1828aa5 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -737,12 +737,12 @@ static int replay_fork_event(struct perf_sched *sched, | |||
737 | 737 | ||
738 | if (verbose) { | 738 | if (verbose) { |
739 | printf("fork event\n"); | 739 | printf("fork event\n"); |
740 | printf("... parent: %s/%d\n", parent->comm, parent->tid); | 740 | printf("... parent: %s/%d\n", thread__comm_str(parent), parent->tid); |
741 | printf("... child: %s/%d\n", child->comm, child->tid); | 741 | printf("... child: %s/%d\n", thread__comm_str(child), child->tid); |
742 | } | 742 | } |
743 | 743 | ||
744 | register_pid(sched, parent->tid, parent->comm); | 744 | register_pid(sched, parent->tid, thread__comm_str(parent)); |
745 | register_pid(sched, child->tid, child->comm); | 745 | register_pid(sched, child->tid, thread__comm_str(child)); |
746 | return 0; | 746 | return 0; |
747 | } | 747 | } |
748 | 748 | ||
@@ -1077,7 +1077,7 @@ static int latency_migrate_task_event(struct perf_sched *sched, | |||
1077 | if (!atoms) { | 1077 | if (!atoms) { |
1078 | if (thread_atoms_insert(sched, migrant)) | 1078 | if (thread_atoms_insert(sched, migrant)) |
1079 | return -1; | 1079 | return -1; |
1080 | register_pid(sched, migrant->tid, migrant->comm); | 1080 | register_pid(sched, migrant->tid, thread__comm_str(migrant)); |
1081 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); | 1081 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); |
1082 | if (!atoms) { | 1082 | if (!atoms) { |
1083 | pr_err("migration-event: Internal tree error"); | 1083 | pr_err("migration-event: Internal tree error"); |
@@ -1111,13 +1111,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ | |||
1111 | /* | 1111 | /* |
1112 | * Ignore idle threads: | 1112 | * Ignore idle threads: |
1113 | */ | 1113 | */ |
1114 | if (!strcmp(work_list->thread->comm, "swapper")) | 1114 | if (!strcmp(thread__comm_str(work_list->thread), "swapper")) |
1115 | return; | 1115 | return; |
1116 | 1116 | ||
1117 | sched->all_runtime += work_list->total_runtime; | 1117 | sched->all_runtime += work_list->total_runtime; |
1118 | sched->all_count += work_list->nb_atoms; | 1118 | sched->all_count += work_list->nb_atoms; |
1119 | 1119 | ||
1120 | ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid); | 1120 | ret = printf(" %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid); |
1121 | 1121 | ||
1122 | for (i = 0; i < 24 - ret; i++) | 1122 | for (i = 0; i < 24 - ret; i++) |
1123 | printf(" "); | 1123 | printf(" "); |
@@ -1334,7 +1334,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1334 | printf(" %12.6f secs ", (double)timestamp/1e9); | 1334 | printf(" %12.6f secs ", (double)timestamp/1e9); |
1335 | if (new_shortname) { | 1335 | if (new_shortname) { |
1336 | printf("%s => %s:%d\n", | 1336 | printf("%s => %s:%d\n", |
1337 | sched_in->shortname, sched_in->comm, sched_in->tid); | 1337 | sched_in->shortname, thread__comm_str(sched_in), sched_in->tid); |
1338 | } else { | 1338 | } else { |
1339 | printf("\n"); | 1339 | printf("\n"); |
1340 | } | 1340 | } |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 0ae88c2538a1..baf17989a216 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -229,6 +229,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
229 | return 0; | 229 | return 0; |
230 | } | 230 | } |
231 | 231 | ||
232 | static void set_print_ip_opts(struct perf_event_attr *attr) | ||
233 | { | ||
234 | unsigned int type = attr->type; | ||
235 | |||
236 | output[type].print_ip_opts = 0; | ||
237 | if (PRINT_FIELD(IP)) | ||
238 | output[type].print_ip_opts |= PRINT_IP_OPT_IP; | ||
239 | |||
240 | if (PRINT_FIELD(SYM)) | ||
241 | output[type].print_ip_opts |= PRINT_IP_OPT_SYM; | ||
242 | |||
243 | if (PRINT_FIELD(DSO)) | ||
244 | output[type].print_ip_opts |= PRINT_IP_OPT_DSO; | ||
245 | |||
246 | if (PRINT_FIELD(SYMOFFSET)) | ||
247 | output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; | ||
248 | } | ||
249 | |||
232 | /* | 250 | /* |
233 | * verify all user requested events exist and the samples | 251 | * verify all user requested events exist and the samples |
234 | * have the expected data | 252 | * have the expected data |
@@ -237,7 +255,6 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
237 | { | 255 | { |
238 | int j; | 256 | int j; |
239 | struct perf_evsel *evsel; | 257 | struct perf_evsel *evsel; |
240 | struct perf_event_attr *attr; | ||
241 | 258 | ||
242 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 259 | for (j = 0; j < PERF_TYPE_MAX; ++j) { |
243 | evsel = perf_session__find_first_evtype(session, j); | 260 | evsel = perf_session__find_first_evtype(session, j); |
@@ -260,20 +277,7 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
260 | if (evsel == NULL) | 277 | if (evsel == NULL) |
261 | continue; | 278 | continue; |
262 | 279 | ||
263 | attr = &evsel->attr; | 280 | set_print_ip_opts(&evsel->attr); |
264 | |||
265 | output[j].print_ip_opts = 0; | ||
266 | if (PRINT_FIELD(IP)) | ||
267 | output[j].print_ip_opts |= PRINT_IP_OPT_IP; | ||
268 | |||
269 | if (PRINT_FIELD(SYM)) | ||
270 | output[j].print_ip_opts |= PRINT_IP_OPT_SYM; | ||
271 | |||
272 | if (PRINT_FIELD(DSO)) | ||
273 | output[j].print_ip_opts |= PRINT_IP_OPT_DSO; | ||
274 | |||
275 | if (PRINT_FIELD(SYMOFFSET)) | ||
276 | output[j].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; | ||
277 | } | 281 | } |
278 | 282 | ||
279 | return 0; | 283 | return 0; |
@@ -291,11 +295,11 @@ static void print_sample_start(struct perf_sample *sample, | |||
291 | 295 | ||
292 | if (PRINT_FIELD(COMM)) { | 296 | if (PRINT_FIELD(COMM)) { |
293 | if (latency_format) | 297 | if (latency_format) |
294 | printf("%8.8s ", thread->comm); | 298 | printf("%8.8s ", thread__comm_str(thread)); |
295 | else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) | 299 | else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) |
296 | printf("%s ", thread->comm); | 300 | printf("%s ", thread__comm_str(thread)); |
297 | else | 301 | else |
298 | printf("%16s ", thread->comm); | 302 | printf("%16s ", thread__comm_str(thread)); |
299 | } | 303 | } |
300 | 304 | ||
301 | if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) | 305 | if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) |
@@ -547,6 +551,34 @@ struct perf_script { | |||
547 | struct perf_session *session; | 551 | struct perf_session *session; |
548 | }; | 552 | }; |
549 | 553 | ||
554 | static int process_attr(struct perf_tool *tool, union perf_event *event, | ||
555 | struct perf_evlist **pevlist) | ||
556 | { | ||
557 | struct perf_script *scr = container_of(tool, struct perf_script, tool); | ||
558 | struct perf_evlist *evlist; | ||
559 | struct perf_evsel *evsel, *pos; | ||
560 | int err; | ||
561 | |||
562 | err = perf_event__process_attr(tool, event, pevlist); | ||
563 | if (err) | ||
564 | return err; | ||
565 | |||
566 | evlist = *pevlist; | ||
567 | evsel = perf_evlist__last(*pevlist); | ||
568 | |||
569 | if (evsel->attr.type >= PERF_TYPE_MAX) | ||
570 | return 0; | ||
571 | |||
572 | list_for_each_entry(pos, &evlist->entries, node) { | ||
573 | if (pos->attr.type == evsel->attr.type && pos != evsel) | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | set_print_ip_opts(&evsel->attr); | ||
578 | |||
579 | return perf_evsel__check_attr(evsel, scr->session); | ||
580 | } | ||
581 | |||
550 | static void sig_handler(int sig __maybe_unused) | 582 | static void sig_handler(int sig __maybe_unused) |
551 | { | 583 | { |
552 | session_done = 1; | 584 | session_done = 1; |
@@ -1272,7 +1304,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1272 | .comm = perf_event__process_comm, | 1304 | .comm = perf_event__process_comm, |
1273 | .exit = perf_event__process_exit, | 1305 | .exit = perf_event__process_exit, |
1274 | .fork = perf_event__process_fork, | 1306 | .fork = perf_event__process_fork, |
1275 | .attr = perf_event__process_attr, | 1307 | .attr = process_attr, |
1276 | .tracing_data = perf_event__process_tracing_data, | 1308 | .tracing_data = perf_event__process_tracing_data, |
1277 | .build_id = perf_event__process_build_id, | 1309 | .build_id = perf_event__process_build_id, |
1278 | .ordered_samples = true, | 1310 | .ordered_samples = true, |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1a9c95d270aa..0fc1c941a73c 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -1596,7 +1596,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1596 | "perf stat [<options>] [<command>]", | 1596 | "perf stat [<options>] [<command>]", |
1597 | NULL | 1597 | NULL |
1598 | }; | 1598 | }; |
1599 | int status = -ENOMEM, run_idx; | 1599 | int status = -EINVAL, run_idx; |
1600 | const char *mode; | 1600 | const char *mode; |
1601 | 1601 | ||
1602 | setlocale(LC_ALL, ""); | 1602 | setlocale(LC_ALL, ""); |
@@ -1614,12 +1614,15 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1614 | 1614 | ||
1615 | if (output_name && output_fd) { | 1615 | if (output_name && output_fd) { |
1616 | fprintf(stderr, "cannot use both --output and --log-fd\n"); | 1616 | fprintf(stderr, "cannot use both --output and --log-fd\n"); |
1617 | usage_with_options(stat_usage, options); | 1617 | parse_options_usage(stat_usage, options, "o", 1); |
1618 | parse_options_usage(NULL, options, "log-fd", 0); | ||
1619 | goto out; | ||
1618 | } | 1620 | } |
1619 | 1621 | ||
1620 | if (output_fd < 0) { | 1622 | if (output_fd < 0) { |
1621 | fprintf(stderr, "argument to --log-fd must be a > 0\n"); | 1623 | fprintf(stderr, "argument to --log-fd must be a > 0\n"); |
1622 | usage_with_options(stat_usage, options); | 1624 | parse_options_usage(stat_usage, options, "log-fd", 0); |
1625 | goto out; | ||
1623 | } | 1626 | } |
1624 | 1627 | ||
1625 | if (!output) { | 1628 | if (!output) { |
@@ -1656,7 +1659,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1656 | /* User explicitly passed -B? */ | 1659 | /* User explicitly passed -B? */ |
1657 | if (big_num_opt == 1) { | 1660 | if (big_num_opt == 1) { |
1658 | fprintf(stderr, "-B option not supported with -x\n"); | 1661 | fprintf(stderr, "-B option not supported with -x\n"); |
1659 | usage_with_options(stat_usage, options); | 1662 | parse_options_usage(stat_usage, options, "B", 1); |
1663 | parse_options_usage(NULL, options, "x", 1); | ||
1664 | goto out; | ||
1660 | } else /* Nope, so disable big number formatting */ | 1665 | } else /* Nope, so disable big number formatting */ |
1661 | big_num = false; | 1666 | big_num = false; |
1662 | } else if (big_num_opt == 0) /* User passed --no-big-num */ | 1667 | } else if (big_num_opt == 0) /* User passed --no-big-num */ |
@@ -1666,7 +1671,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1666 | usage_with_options(stat_usage, options); | 1671 | usage_with_options(stat_usage, options); |
1667 | 1672 | ||
1668 | if (run_count < 0) { | 1673 | if (run_count < 0) { |
1669 | usage_with_options(stat_usage, options); | 1674 | pr_err("Run count must be a positive number\n"); |
1675 | parse_options_usage(stat_usage, options, "r", 1); | ||
1676 | goto out; | ||
1670 | } else if (run_count == 0) { | 1677 | } else if (run_count == 0) { |
1671 | forever = true; | 1678 | forever = true; |
1672 | run_count = 1; | 1679 | run_count = 1; |
@@ -1678,8 +1685,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1678 | fprintf(stderr, "both cgroup and no-aggregation " | 1685 | fprintf(stderr, "both cgroup and no-aggregation " |
1679 | "modes only available in system-wide mode\n"); | 1686 | "modes only available in system-wide mode\n"); |
1680 | 1687 | ||
1681 | usage_with_options(stat_usage, options); | 1688 | parse_options_usage(stat_usage, options, "G", 1); |
1682 | return -1; | 1689 | parse_options_usage(NULL, options, "A", 1); |
1690 | parse_options_usage(NULL, options, "a", 1); | ||
1691 | goto out; | ||
1683 | } | 1692 | } |
1684 | 1693 | ||
1685 | if (add_default_attributes()) | 1694 | if (add_default_attributes()) |
@@ -1688,25 +1697,28 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1688 | perf_target__validate(&target); | 1697 | perf_target__validate(&target); |
1689 | 1698 | ||
1690 | if (perf_evlist__create_maps(evsel_list, &target) < 0) { | 1699 | if (perf_evlist__create_maps(evsel_list, &target) < 0) { |
1691 | if (perf_target__has_task(&target)) | 1700 | if (perf_target__has_task(&target)) { |
1692 | pr_err("Problems finding threads of monitor\n"); | 1701 | pr_err("Problems finding threads of monitor\n"); |
1693 | if (perf_target__has_cpu(&target)) | 1702 | parse_options_usage(stat_usage, options, "p", 1); |
1703 | parse_options_usage(NULL, options, "t", 1); | ||
1704 | } else if (perf_target__has_cpu(&target)) { | ||
1694 | perror("failed to parse CPUs map"); | 1705 | perror("failed to parse CPUs map"); |
1695 | 1706 | parse_options_usage(stat_usage, options, "C", 1); | |
1696 | usage_with_options(stat_usage, options); | 1707 | parse_options_usage(NULL, options, "a", 1); |
1697 | return -1; | 1708 | } |
1709 | goto out; | ||
1698 | } | 1710 | } |
1699 | if (interval && interval < 100) { | 1711 | if (interval && interval < 100) { |
1700 | pr_err("print interval must be >= 100ms\n"); | 1712 | pr_err("print interval must be >= 100ms\n"); |
1701 | usage_with_options(stat_usage, options); | 1713 | parse_options_usage(stat_usage, options, "I", 1); |
1702 | return -1; | 1714 | goto out_free_maps; |
1703 | } | 1715 | } |
1704 | 1716 | ||
1705 | if (perf_evlist__alloc_stats(evsel_list, interval)) | 1717 | if (perf_evlist__alloc_stats(evsel_list, interval)) |
1706 | goto out_free_maps; | 1718 | goto out_free_maps; |
1707 | 1719 | ||
1708 | if (perf_stat_init_aggr_mode()) | 1720 | if (perf_stat_init_aggr_mode()) |
1709 | goto out; | 1721 | goto out_free_maps; |
1710 | 1722 | ||
1711 | /* | 1723 | /* |
1712 | * We dont want to block the signals - that would cause | 1724 | * We dont want to block the signals - that would cause |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a6ea956a533e..ca5ca37980fb 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -856,7 +856,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
856 | &sample, machine); | 856 | &sample, machine); |
857 | } else if (event->header.type < PERF_RECORD_MAX) { | 857 | } else if (event->header.type < PERF_RECORD_MAX) { |
858 | hists__inc_nr_events(&evsel->hists, event->header.type); | 858 | hists__inc_nr_events(&evsel->hists, event->header.type); |
859 | machine__process_event(machine, event); | 859 | machine__process_event(machine, event, &sample); |
860 | } else | 860 | } else |
861 | ++session->stats.nr_unknown_events; | 861 | ++session->stats.nr_unknown_events; |
862 | next_event: | 862 | next_event: |
@@ -1040,7 +1040,7 @@ parse_percent_limit(const struct option *opt, const char *arg, | |||
1040 | 1040 | ||
1041 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | 1041 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) |
1042 | { | 1042 | { |
1043 | int status; | 1043 | int status = -1; |
1044 | char errbuf[BUFSIZ]; | 1044 | char errbuf[BUFSIZ]; |
1045 | struct perf_top top = { | 1045 | struct perf_top top = { |
1046 | .count_filter = 5, | 1046 | .count_filter = 5, |
@@ -1159,8 +1159,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1159 | if (sort_order == default_sort_order) | 1159 | if (sort_order == default_sort_order) |
1160 | sort_order = "dso,symbol"; | 1160 | sort_order = "dso,symbol"; |
1161 | 1161 | ||
1162 | if (setup_sorting() < 0) | 1162 | if (setup_sorting() < 0) { |
1163 | usage_with_options(top_usage, options); | 1163 | parse_options_usage(top_usage, options, "s", 1); |
1164 | goto out_delete_evlist; | ||
1165 | } | ||
1164 | 1166 | ||
1165 | /* display thread wants entries to be collapsed in a different tree */ | 1167 | /* display thread wants entries to be collapsed in a different tree */ |
1166 | sort__need_collapse = 1; | 1168 | sort__need_collapse = 1; |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index dc3da654ff12..b3e57dc64546 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -1114,7 +1114,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre | |||
1114 | 1114 | ||
1115 | if (trace->multiple_threads) { | 1115 | if (trace->multiple_threads) { |
1116 | if (trace->show_comm) | 1116 | if (trace->show_comm) |
1117 | printed += fprintf(fp, "%.14s/", thread->comm); | 1117 | printed += fprintf(fp, "%.14s/", thread__comm_str(thread)); |
1118 | printed += fprintf(fp, "%d ", thread->tid); | 1118 | printed += fprintf(fp, "%d ", thread->tid); |
1119 | } | 1119 | } |
1120 | 1120 | ||
@@ -1122,7 +1122,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre | |||
1122 | } | 1122 | } |
1123 | 1123 | ||
1124 | static int trace__process_event(struct trace *trace, struct machine *machine, | 1124 | static int trace__process_event(struct trace *trace, struct machine *machine, |
1125 | union perf_event *event) | 1125 | union perf_event *event, struct perf_sample *sample) |
1126 | { | 1126 | { |
1127 | int ret = 0; | 1127 | int ret = 0; |
1128 | 1128 | ||
@@ -1130,9 +1130,9 @@ static int trace__process_event(struct trace *trace, struct machine *machine, | |||
1130 | case PERF_RECORD_LOST: | 1130 | case PERF_RECORD_LOST: |
1131 | color_fprintf(trace->output, PERF_COLOR_RED, | 1131 | color_fprintf(trace->output, PERF_COLOR_RED, |
1132 | "LOST %" PRIu64 " events!\n", event->lost.lost); | 1132 | "LOST %" PRIu64 " events!\n", event->lost.lost); |
1133 | ret = machine__process_lost_event(machine, event); | 1133 | ret = machine__process_lost_event(machine, event, sample); |
1134 | default: | 1134 | default: |
1135 | ret = machine__process_event(machine, event); | 1135 | ret = machine__process_event(machine, event, sample); |
1136 | break; | 1136 | break; |
1137 | } | 1137 | } |
1138 | 1138 | ||
@@ -1141,11 +1141,11 @@ static int trace__process_event(struct trace *trace, struct machine *machine, | |||
1141 | 1141 | ||
1142 | static int trace__tool_process(struct perf_tool *tool, | 1142 | static int trace__tool_process(struct perf_tool *tool, |
1143 | union perf_event *event, | 1143 | union perf_event *event, |
1144 | struct perf_sample *sample __maybe_unused, | 1144 | struct perf_sample *sample, |
1145 | struct machine *machine) | 1145 | struct machine *machine) |
1146 | { | 1146 | { |
1147 | struct trace *trace = container_of(tool, struct trace, tool); | 1147 | struct trace *trace = container_of(tool, struct trace, tool); |
1148 | return trace__process_event(trace, machine, event); | 1148 | return trace__process_event(trace, machine, event, sample); |
1149 | } | 1149 | } |
1150 | 1150 | ||
1151 | static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) | 1151 | static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) |
@@ -1751,7 +1751,7 @@ again: | |||
1751 | trace->base_time = sample.time; | 1751 | trace->base_time = sample.time; |
1752 | 1752 | ||
1753 | if (type != PERF_RECORD_SAMPLE) { | 1753 | if (type != PERF_RECORD_SAMPLE) { |
1754 | trace__process_event(trace, trace->host, event); | 1754 | trace__process_event(trace, trace->host, event, &sample); |
1755 | continue; | 1755 | continue; |
1756 | } | 1756 | } |
1757 | 1757 | ||
@@ -1986,7 +1986,7 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) | |||
1986 | else if (ratio > 5.0) | 1986 | else if (ratio > 5.0) |
1987 | color = PERF_COLOR_YELLOW; | 1987 | color = PERF_COLOR_YELLOW; |
1988 | 1988 | ||
1989 | printed += color_fprintf(fp, color, "%20s", thread->comm); | 1989 | printed += color_fprintf(fp, color, "%20s", thread__comm_str(thread)); |
1990 | printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); | 1990 | printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); |
1991 | printed += color_fprintf(fp, color, "%5.1f%%", ratio); | 1991 | printed += color_fprintf(fp, color, "%5.1f%%", ratio); |
1992 | printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); | 1992 | printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 543aa953bab1..ffb5f55c8fba 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -25,9 +25,11 @@ ifeq ($(ARCH),x86_64) | |||
25 | RAW_ARCH := x86_64 | 25 | RAW_ARCH := x86_64 |
26 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT | 26 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT |
27 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S | 27 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S |
28 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | ||
29 | else | ||
30 | LIBUNWIND_LIBS = -lunwind -lunwind-x86 | ||
28 | endif | 31 | endif |
29 | NO_PERF_REGS := 0 | 32 | NO_PERF_REGS := 0 |
30 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | ||
31 | endif | 33 | endif |
32 | 34 | ||
33 | ifeq ($(NO_PERF_REGS),0) | 35 | ifeq ($(NO_PERF_REGS),0) |
@@ -96,7 +98,7 @@ endif | |||
96 | 98 | ||
97 | feature_check = $(eval $(feature_check_code)) | 99 | feature_check = $(eval $(feature_check_code)) |
98 | define feature_check_code | 100 | define feature_check_code |
99 | feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) LDFLAGS=$(LDFLAGS) -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0) | 101 | feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) LIBUNWIND_LIBS="$(LIBUNWIND_LIBS)" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0) |
100 | endef | 102 | endef |
101 | 103 | ||
102 | feature_set = $(eval $(feature_set_code)) | 104 | feature_set = $(eval $(feature_set_code)) |
@@ -173,7 +175,7 @@ ifeq ($(feature-all), 1) | |||
173 | # | 175 | # |
174 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) | 176 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) |
175 | else | 177 | else |
176 | $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1) | 178 | $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1) |
177 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) | 179 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) |
178 | endif | 180 | endif |
179 | 181 | ||
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 452b67cc4d7b..d37d58d273fe 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile | |||
@@ -31,12 +31,12 @@ CC := $(CC) -MD | |||
31 | 31 | ||
32 | all: $(FILES) | 32 | all: $(FILES) |
33 | 33 | ||
34 | BUILD = $(CC) $(LDFLAGS) -o $(OUTPUT)$@ $@.c | 34 | BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c |
35 | 35 | ||
36 | ############################### | 36 | ############################### |
37 | 37 | ||
38 | test-all: | 38 | test-all: |
39 | $(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lunwind -lunwind-x86_64 -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl | 39 | $(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl |
40 | 40 | ||
41 | test-hello: | 41 | test-hello: |
42 | $(BUILD) | 42 | $(BUILD) |
@@ -72,7 +72,7 @@ test-libnuma: | |||
72 | $(BUILD) -lnuma | 72 | $(BUILD) -lnuma |
73 | 73 | ||
74 | test-libunwind: | 74 | test-libunwind: |
75 | $(BUILD) -lunwind -lunwind-x86_64 -lelf | 75 | $(BUILD) $(LIBUNWIND_LIBS) -lelf |
76 | 76 | ||
77 | test-libaudit: | 77 | test-libaudit: |
78 | $(BUILD) -laudit | 78 | $(BUILD) -laudit |
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index e3fedfa2906e..49ccc3b2995e 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
@@ -276,7 +276,7 @@ static int process_event(struct machine *machine, struct perf_evlist *evlist, | |||
276 | return process_sample_event(machine, evlist, event, state); | 276 | return process_sample_event(machine, evlist, event, state); |
277 | 277 | ||
278 | if (event->header.type < PERF_RECORD_MAX) | 278 | if (event->header.type < PERF_RECORD_MAX) |
279 | return machine__process_event(machine, event); | 279 | return machine__process_event(machine, event, NULL); |
280 | 280 | ||
281 | return 0; | 281 | return 0; |
282 | } | 282 | } |
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index b51abcb2c243..6c337e653540 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c | |||
@@ -93,7 +93,7 @@ static struct machine *setup_fake_machine(struct machines *machines) | |||
93 | if (thread == NULL) | 93 | if (thread == NULL) |
94 | goto out; | 94 | goto out; |
95 | 95 | ||
96 | thread__set_comm(thread, fake_threads[i].comm); | 96 | thread__set_comm(thread, fake_threads[i].comm, 0); |
97 | } | 97 | } |
98 | 98 | ||
99 | for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) { | 99 | for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) { |
@@ -110,7 +110,7 @@ static struct machine *setup_fake_machine(struct machines *machines) | |||
110 | strcpy(fake_mmap_event.mmap.filename, | 110 | strcpy(fake_mmap_event.mmap.filename, |
111 | fake_mmap_info[i].filename); | 111 | fake_mmap_info[i].filename); |
112 | 112 | ||
113 | machine__process_mmap_event(machine, &fake_mmap_event); | 113 | machine__process_mmap_event(machine, &fake_mmap_event, NULL); |
114 | } | 114 | } |
115 | 115 | ||
116 | for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) { | 116 | for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) { |
@@ -421,7 +421,7 @@ static void print_hists(struct hists *hists) | |||
421 | he = rb_entry(node, struct hist_entry, rb_node_in); | 421 | he = rb_entry(node, struct hist_entry, rb_node_in); |
422 | 422 | ||
423 | pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", | 423 | pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", |
424 | i, he->thread->comm, he->ms.map->dso->short_name, | 424 | i, thread__comm_str(he->thread), he->ms.map->dso->short_name, |
425 | he->ms.sym->name, he->stat.period); | 425 | he->ms.sym->name, he->stat.period); |
426 | 426 | ||
427 | i++; | 427 | i++; |
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 61c9da2eb3a9..1b677202638d 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c | |||
@@ -121,6 +121,9 @@ static bool samples_same(const struct perf_sample *s1, | |||
121 | if (type & PERF_SAMPLE_DATA_SRC) | 121 | if (type & PERF_SAMPLE_DATA_SRC) |
122 | COMP(data_src); | 122 | COMP(data_src); |
123 | 123 | ||
124 | if (type & PERF_SAMPLE_TRANSACTION) | ||
125 | COMP(transaction); | ||
126 | |||
124 | return true; | 127 | return true; |
125 | } | 128 | } |
126 | 129 | ||
@@ -165,6 +168,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format) | |||
165 | .cpu = 110, | 168 | .cpu = 110, |
166 | .raw_size = sizeof(raw_data), | 169 | .raw_size = sizeof(raw_data), |
167 | .data_src = 111, | 170 | .data_src = 111, |
171 | .transaction = 112, | ||
168 | .raw_data = (void *)raw_data, | 172 | .raw_data = (void *)raw_data, |
169 | .callchain = &callchain.callchain, | 173 | .callchain = &callchain.callchain, |
170 | .branch_stack = &branch_stack.branch_stack, | 174 | .branch_stack = &branch_stack.branch_stack, |
@@ -273,7 +277,8 @@ int test__sample_parsing(void) | |||
273 | 277 | ||
274 | /* | 278 | /* |
275 | * Fail the test if it has not been updated when new sample format bits | 279 | * Fail the test if it has not been updated when new sample format bits |
276 | * were added. | 280 | * were added. Please actually update the test rather than just change |
281 | * the condition below. | ||
277 | */ | 282 | */ |
278 | if (PERF_SAMPLE_MAX > PERF_SAMPLE_TRANSACTION << 1) { | 283 | if (PERF_SAMPLE_MAX > PERF_SAMPLE_TRANSACTION << 1) { |
279 | pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n"); | 284 | pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n"); |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 7ef36c360471..a91b6b219412 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1255,7 +1255,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, | |||
1255 | if (thread) | 1255 | if (thread) |
1256 | printed += scnprintf(bf + printed, size - printed, | 1256 | printed += scnprintf(bf + printed, size - printed, |
1257 | ", Thread: %s(%d)", | 1257 | ", Thread: %s(%d)", |
1258 | (thread->comm_set ? thread->comm : ""), | 1258 | (thread->comm_set ? thread__comm_str(thread) : ""), |
1259 | thread->tid); | 1259 | thread->tid); |
1260 | if (dso) | 1260 | if (dso) |
1261 | printed += scnprintf(bf + printed, size - printed, | 1261 | printed += scnprintf(bf + printed, size - printed, |
@@ -1578,7 +1578,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1578 | if (thread != NULL && | 1578 | if (thread != NULL && |
1579 | asprintf(&options[nr_options], "Zoom %s %s(%d) thread", | 1579 | asprintf(&options[nr_options], "Zoom %s %s(%d) thread", |
1580 | (browser->hists->thread_filter ? "out of" : "into"), | 1580 | (browser->hists->thread_filter ? "out of" : "into"), |
1581 | (thread->comm_set ? thread->comm : ""), | 1581 | (thread->comm_set ? thread__comm_str(thread) : ""), |
1582 | thread->tid) > 0) | 1582 | thread->tid) > 0) |
1583 | zoom_thread = nr_options++; | 1583 | zoom_thread = nr_options++; |
1584 | 1584 | ||
@@ -1598,7 +1598,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1598 | struct symbol *sym; | 1598 | struct symbol *sym; |
1599 | 1599 | ||
1600 | if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", | 1600 | if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", |
1601 | browser->he_selection->thread->comm) > 0) | 1601 | thread__comm_str(browser->he_selection->thread)) > 0) |
1602 | scripts_comm = nr_options++; | 1602 | scripts_comm = nr_options++; |
1603 | 1603 | ||
1604 | sym = browser->he_selection->ms.sym; | 1604 | sym = browser->he_selection->ms.sym; |
@@ -1701,7 +1701,7 @@ zoom_out_thread: | |||
1701 | sort_thread.elide = false; | 1701 | sort_thread.elide = false; |
1702 | } else { | 1702 | } else { |
1703 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", | 1703 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", |
1704 | thread->comm_set ? thread->comm : "", | 1704 | thread->comm_set ? thread__comm_str(thread) : "", |
1705 | thread->tid); | 1705 | thread->tid); |
1706 | browser->hists->thread_filter = thread; | 1706 | browser->hists->thread_filter = thread; |
1707 | sort_thread.elide = true; | 1707 | sort_thread.elide = true; |
@@ -1717,7 +1717,7 @@ do_scripts: | |||
1717 | memset(script_opt, 0, 64); | 1717 | memset(script_opt, 0, 64); |
1718 | 1718 | ||
1719 | if (choice == scripts_comm) | 1719 | if (choice == scripts_comm) |
1720 | sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm); | 1720 | sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread)); |
1721 | 1721 | ||
1722 | if (choice == scripts_symbol) | 1722 | if (choice == scripts_symbol) |
1723 | sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); | 1723 | sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); |
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c new file mode 100644 index 000000000000..ee0df0e24cdb --- /dev/null +++ b/tools/perf/util/comm.c | |||
@@ -0,0 +1,121 @@ | |||
1 | #include "comm.h" | ||
2 | #include "util.h" | ||
3 | #include <stdlib.h> | ||
4 | #include <stdio.h> | ||
5 | |||
6 | struct comm_str { | ||
7 | char *str; | ||
8 | struct rb_node rb_node; | ||
9 | int ref; | ||
10 | }; | ||
11 | |||
12 | /* Should perhaps be moved to struct machine */ | ||
13 | static struct rb_root comm_str_root; | ||
14 | |||
15 | static void comm_str__get(struct comm_str *cs) | ||
16 | { | ||
17 | cs->ref++; | ||
18 | } | ||
19 | |||
20 | static void comm_str__put(struct comm_str *cs) | ||
21 | { | ||
22 | if (!--cs->ref) { | ||
23 | rb_erase(&cs->rb_node, &comm_str_root); | ||
24 | free(cs->str); | ||
25 | free(cs); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | static struct comm_str *comm_str__alloc(const char *str) | ||
30 | { | ||
31 | struct comm_str *cs; | ||
32 | |||
33 | cs = zalloc(sizeof(*cs)); | ||
34 | if (!cs) | ||
35 | return NULL; | ||
36 | |||
37 | cs->str = strdup(str); | ||
38 | if (!cs->str) { | ||
39 | free(cs); | ||
40 | return NULL; | ||
41 | } | ||
42 | |||
43 | return cs; | ||
44 | } | ||
45 | |||
46 | static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root) | ||
47 | { | ||
48 | struct rb_node **p = &root->rb_node; | ||
49 | struct rb_node *parent = NULL; | ||
50 | struct comm_str *iter, *new; | ||
51 | int cmp; | ||
52 | |||
53 | while (*p != NULL) { | ||
54 | parent = *p; | ||
55 | iter = rb_entry(parent, struct comm_str, rb_node); | ||
56 | |||
57 | cmp = strcmp(str, iter->str); | ||
58 | if (!cmp) | ||
59 | return iter; | ||
60 | |||
61 | if (cmp < 0) | ||
62 | p = &(*p)->rb_left; | ||
63 | else | ||
64 | p = &(*p)->rb_right; | ||
65 | } | ||
66 | |||
67 | new = comm_str__alloc(str); | ||
68 | if (!new) | ||
69 | return NULL; | ||
70 | |||
71 | rb_link_node(&new->rb_node, parent, p); | ||
72 | rb_insert_color(&new->rb_node, root); | ||
73 | |||
74 | return new; | ||
75 | } | ||
76 | |||
77 | struct comm *comm__new(const char *str, u64 timestamp) | ||
78 | { | ||
79 | struct comm *comm = zalloc(sizeof(*comm)); | ||
80 | |||
81 | if (!comm) | ||
82 | return NULL; | ||
83 | |||
84 | comm->start = timestamp; | ||
85 | |||
86 | comm->comm_str = comm_str__findnew(str, &comm_str_root); | ||
87 | if (!comm->comm_str) { | ||
88 | free(comm); | ||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | comm_str__get(comm->comm_str); | ||
93 | |||
94 | return comm; | ||
95 | } | ||
96 | |||
97 | void comm__override(struct comm *comm, const char *str, u64 timestamp) | ||
98 | { | ||
99 | struct comm_str *old = comm->comm_str; | ||
100 | |||
101 | comm->comm_str = comm_str__findnew(str, &comm_str_root); | ||
102 | if (!comm->comm_str) { | ||
103 | comm->comm_str = old; | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | comm->start = timestamp; | ||
108 | comm_str__get(comm->comm_str); | ||
109 | comm_str__put(old); | ||
110 | } | ||
111 | |||
112 | void comm__free(struct comm *comm) | ||
113 | { | ||
114 | comm_str__put(comm->comm_str); | ||
115 | free(comm); | ||
116 | } | ||
117 | |||
118 | const char *comm__str(const struct comm *comm) | ||
119 | { | ||
120 | return comm->comm_str->str; | ||
121 | } | ||
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h new file mode 100644 index 000000000000..7a86e5656710 --- /dev/null +++ b/tools/perf/util/comm.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifndef __PERF_COMM_H | ||
2 | #define __PERF_COMM_H | ||
3 | |||
4 | #include "../perf.h" | ||
5 | #include <linux/rbtree.h> | ||
6 | #include <linux/list.h> | ||
7 | |||
8 | struct comm_str; | ||
9 | |||
10 | struct comm { | ||
11 | struct comm_str *comm_str; | ||
12 | u64 start; | ||
13 | struct list_head list; | ||
14 | }; | ||
15 | |||
16 | void comm__free(struct comm *comm); | ||
17 | struct comm *comm__new(const char *str, u64 timestamp); | ||
18 | const char *comm__str(const struct comm *comm); | ||
19 | void comm__override(struct comm *comm, const char *str, u64 timestamp); | ||
20 | |||
21 | #endif /* __PERF_COMM_H */ | ||
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 49096ea58a15..c26b3539187b 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -512,18 +512,18 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) | |||
512 | 512 | ||
513 | int perf_event__process_comm(struct perf_tool *tool __maybe_unused, | 513 | int perf_event__process_comm(struct perf_tool *tool __maybe_unused, |
514 | union perf_event *event, | 514 | union perf_event *event, |
515 | struct perf_sample *sample __maybe_unused, | 515 | struct perf_sample *sample, |
516 | struct machine *machine) | 516 | struct machine *machine) |
517 | { | 517 | { |
518 | return machine__process_comm_event(machine, event); | 518 | return machine__process_comm_event(machine, event, sample); |
519 | } | 519 | } |
520 | 520 | ||
521 | int perf_event__process_lost(struct perf_tool *tool __maybe_unused, | 521 | int perf_event__process_lost(struct perf_tool *tool __maybe_unused, |
522 | union perf_event *event, | 522 | union perf_event *event, |
523 | struct perf_sample *sample __maybe_unused, | 523 | struct perf_sample *sample, |
524 | struct machine *machine) | 524 | struct machine *machine) |
525 | { | 525 | { |
526 | return machine__process_lost_event(machine, event); | 526 | return machine__process_lost_event(machine, event, sample); |
527 | } | 527 | } |
528 | 528 | ||
529 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) | 529 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) |
@@ -546,18 +546,18 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) | |||
546 | 546 | ||
547 | int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, | 547 | int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, |
548 | union perf_event *event, | 548 | union perf_event *event, |
549 | struct perf_sample *sample __maybe_unused, | 549 | struct perf_sample *sample, |
550 | struct machine *machine) | 550 | struct machine *machine) |
551 | { | 551 | { |
552 | return machine__process_mmap_event(machine, event); | 552 | return machine__process_mmap_event(machine, event, sample); |
553 | } | 553 | } |
554 | 554 | ||
555 | int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, | 555 | int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, |
556 | union perf_event *event, | 556 | union perf_event *event, |
557 | struct perf_sample *sample __maybe_unused, | 557 | struct perf_sample *sample, |
558 | struct machine *machine) | 558 | struct machine *machine) |
559 | { | 559 | { |
560 | return machine__process_mmap2_event(machine, event); | 560 | return machine__process_mmap2_event(machine, event, sample); |
561 | } | 561 | } |
562 | 562 | ||
563 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) | 563 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) |
@@ -569,18 +569,18 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) | |||
569 | 569 | ||
570 | int perf_event__process_fork(struct perf_tool *tool __maybe_unused, | 570 | int perf_event__process_fork(struct perf_tool *tool __maybe_unused, |
571 | union perf_event *event, | 571 | union perf_event *event, |
572 | struct perf_sample *sample __maybe_unused, | 572 | struct perf_sample *sample, |
573 | struct machine *machine) | 573 | struct machine *machine) |
574 | { | 574 | { |
575 | return machine__process_fork_event(machine, event); | 575 | return machine__process_fork_event(machine, event, sample); |
576 | } | 576 | } |
577 | 577 | ||
578 | int perf_event__process_exit(struct perf_tool *tool __maybe_unused, | 578 | int perf_event__process_exit(struct perf_tool *tool __maybe_unused, |
579 | union perf_event *event, | 579 | union perf_event *event, |
580 | struct perf_sample *sample __maybe_unused, | 580 | struct perf_sample *sample, |
581 | struct machine *machine) | 581 | struct machine *machine) |
582 | { | 582 | { |
583 | return machine__process_exit_event(machine, event); | 583 | return machine__process_exit_event(machine, event, sample); |
584 | } | 584 | } |
585 | 585 | ||
586 | size_t perf_event__fprintf(union perf_event *event, FILE *fp) | 586 | size_t perf_event__fprintf(union perf_event *event, FILE *fp) |
@@ -611,10 +611,10 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) | |||
611 | 611 | ||
612 | int perf_event__process(struct perf_tool *tool __maybe_unused, | 612 | int perf_event__process(struct perf_tool *tool __maybe_unused, |
613 | union perf_event *event, | 613 | union perf_event *event, |
614 | struct perf_sample *sample __maybe_unused, | 614 | struct perf_sample *sample, |
615 | struct machine *machine) | 615 | struct machine *machine) |
616 | { | 616 | { |
617 | return machine__process_event(machine, event); | 617 | return machine__process_event(machine, event, sample); |
618 | } | 618 | } |
619 | 619 | ||
620 | void thread__find_addr_map(struct thread *self, | 620 | void thread__find_addr_map(struct thread *self, |
@@ -721,10 +721,10 @@ int perf_event__preprocess_sample(const union perf_event *event, | |||
721 | return -1; | 721 | return -1; |
722 | 722 | ||
723 | if (symbol_conf.comm_list && | 723 | if (symbol_conf.comm_list && |
724 | !strlist__has_entry(symbol_conf.comm_list, thread->comm)) | 724 | !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread))) |
725 | goto out_filtered; | 725 | goto out_filtered; |
726 | 726 | ||
727 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); | 727 | dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); |
728 | /* | 728 | /* |
729 | * Have we already created the kernel maps for this machine? | 729 | * Have we already created the kernel maps for this machine? |
730 | * | 730 | * |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 0582f67fbefc..1c173ccb0ef2 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -607,6 +607,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, | |||
607 | evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, | 607 | evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, |
608 | MAP_SHARED, fd, 0); | 608 | MAP_SHARED, fd, 0); |
609 | if (evlist->mmap[idx].base == MAP_FAILED) { | 609 | if (evlist->mmap[idx].base == MAP_FAILED) { |
610 | pr_debug2("failed to mmap perf event ring buffer, error %d\n", | ||
611 | errno); | ||
610 | evlist->mmap[idx].base = NULL; | 612 | evlist->mmap[idx].base = NULL; |
611 | return -1; | 613 | return -1; |
612 | } | 614 | } |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 3a334f001997..5280820ed389 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -663,7 +663,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
663 | } | 663 | } |
664 | 664 | ||
665 | if (opts->sample_address) | 665 | if (opts->sample_address) |
666 | attr->sample_type |= PERF_SAMPLE_DATA_SRC; | 666 | perf_evsel__set_sample_bit(evsel, DATA_SRC); |
667 | 667 | ||
668 | if (opts->no_delay) { | 668 | if (opts->no_delay) { |
669 | attr->watermark = 0; | 669 | attr->watermark = 0; |
@@ -675,13 +675,13 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
675 | } | 675 | } |
676 | 676 | ||
677 | if (opts->sample_weight) | 677 | if (opts->sample_weight) |
678 | attr->sample_type |= PERF_SAMPLE_WEIGHT; | 678 | perf_evsel__set_sample_bit(evsel, WEIGHT); |
679 | 679 | ||
680 | attr->mmap = track; | 680 | attr->mmap = track; |
681 | attr->comm = track; | 681 | attr->comm = track; |
682 | 682 | ||
683 | if (opts->sample_transaction) | 683 | if (opts->sample_transaction) |
684 | attr->sample_type |= PERF_SAMPLE_TRANSACTION; | 684 | perf_evsel__set_sample_bit(evsel, TRANSACTION); |
685 | 685 | ||
686 | /* | 686 | /* |
687 | * XXX see the function comment above | 687 | * XXX see the function comment above |
@@ -1051,6 +1051,8 @@ retry_open: | |||
1051 | group_fd, flags); | 1051 | group_fd, flags); |
1052 | if (FD(evsel, cpu, thread) < 0) { | 1052 | if (FD(evsel, cpu, thread) < 0) { |
1053 | err = -errno; | 1053 | err = -errno; |
1054 | pr_debug2("perf_event_open failed, error %d\n", | ||
1055 | err); | ||
1054 | goto try_fallback; | 1056 | goto try_fallback; |
1055 | } | 1057 | } |
1056 | set_rlimit = NO_CHANGE; | 1058 | set_rlimit = NO_CHANGE; |
@@ -1479,6 +1481,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
1479 | 1481 | ||
1480 | data->transaction = 0; | 1482 | data->transaction = 0; |
1481 | if (type & PERF_SAMPLE_TRANSACTION) { | 1483 | if (type & PERF_SAMPLE_TRANSACTION) { |
1484 | OVERFLOW_CHECK_u64(array); | ||
1482 | data->transaction = *array; | 1485 | data->transaction = *array; |
1483 | array++; | 1486 | array++; |
1484 | } | 1487 | } |
@@ -1575,6 +1578,9 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, | |||
1575 | if (type & PERF_SAMPLE_DATA_SRC) | 1578 | if (type & PERF_SAMPLE_DATA_SRC) |
1576 | result += sizeof(u64); | 1579 | result += sizeof(u64); |
1577 | 1580 | ||
1581 | if (type & PERF_SAMPLE_TRANSACTION) | ||
1582 | result += sizeof(u64); | ||
1583 | |||
1578 | return result; | 1584 | return result; |
1579 | } | 1585 | } |
1580 | 1586 | ||
@@ -1748,6 +1754,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | |||
1748 | array++; | 1754 | array++; |
1749 | } | 1755 | } |
1750 | 1756 | ||
1757 | if (type & PERF_SAMPLE_TRANSACTION) { | ||
1758 | *array = sample->transaction; | ||
1759 | array++; | ||
1760 | } | ||
1761 | |||
1751 | return 0; | 1762 | return 0; |
1752 | } | 1763 | } |
1753 | 1764 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 7e80253074b0..30793f98c8bb 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -416,6 +416,7 @@ struct hist_entry *__hists__add_mem_entry(struct hists *hists, | |||
416 | { | 416 | { |
417 | struct hist_entry entry = { | 417 | struct hist_entry entry = { |
418 | .thread = al->thread, | 418 | .thread = al->thread, |
419 | .comm = thread__comm(al->thread), | ||
419 | .ms = { | 420 | .ms = { |
420 | .map = al->map, | 421 | .map = al->map, |
421 | .sym = al->sym, | 422 | .sym = al->sym, |
@@ -446,6 +447,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *hists, | |||
446 | { | 447 | { |
447 | struct hist_entry entry = { | 448 | struct hist_entry entry = { |
448 | .thread = al->thread, | 449 | .thread = al->thread, |
450 | .comm = thread__comm(al->thread), | ||
449 | .ms = { | 451 | .ms = { |
450 | .map = bi->to.map, | 452 | .map = bi->to.map, |
451 | .sym = bi->to.sym, | 453 | .sym = bi->to.sym, |
@@ -475,6 +477,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, | |||
475 | { | 477 | { |
476 | struct hist_entry entry = { | 478 | struct hist_entry entry = { |
477 | .thread = al->thread, | 479 | .thread = al->thread, |
480 | .comm = thread__comm(al->thread), | ||
478 | .ms = { | 481 | .ms = { |
479 | .map = al->map, | 482 | .map = al->map, |
480 | .sym = al->sym, | 483 | .sym = al->sym, |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index ea93425cce95..ce034c183a7e 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -40,7 +40,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
40 | return -ENOMEM; | 40 | return -ENOMEM; |
41 | 41 | ||
42 | snprintf(comm, sizeof(comm), "[guest/%d]", pid); | 42 | snprintf(comm, sizeof(comm), "[guest/%d]", pid); |
43 | thread__set_comm(thread, comm); | 43 | thread__set_comm(thread, comm, 0); |
44 | } | 44 | } |
45 | 45 | ||
46 | return 0; | 46 | return 0; |
@@ -331,7 +331,8 @@ struct thread *machine__find_thread(struct machine *machine, pid_t tid) | |||
331 | return __machine__findnew_thread(machine, 0, tid, false); | 331 | return __machine__findnew_thread(machine, 0, tid, false); |
332 | } | 332 | } |
333 | 333 | ||
334 | int machine__process_comm_event(struct machine *machine, union perf_event *event) | 334 | int machine__process_comm_event(struct machine *machine, union perf_event *event, |
335 | struct perf_sample *sample) | ||
335 | { | 336 | { |
336 | struct thread *thread = machine__findnew_thread(machine, | 337 | struct thread *thread = machine__findnew_thread(machine, |
337 | event->comm.pid, | 338 | event->comm.pid, |
@@ -340,7 +341,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event | |||
340 | if (dump_trace) | 341 | if (dump_trace) |
341 | perf_event__fprintf_comm(event, stdout); | 342 | perf_event__fprintf_comm(event, stdout); |
342 | 343 | ||
343 | if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { | 344 | if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) { |
344 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); | 345 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); |
345 | return -1; | 346 | return -1; |
346 | } | 347 | } |
@@ -349,7 +350,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event | |||
349 | } | 350 | } |
350 | 351 | ||
351 | int machine__process_lost_event(struct machine *machine __maybe_unused, | 352 | int machine__process_lost_event(struct machine *machine __maybe_unused, |
352 | union perf_event *event) | 353 | union perf_event *event, struct perf_sample *sample __maybe_unused) |
353 | { | 354 | { |
354 | dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", | 355 | dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", |
355 | event->lost.id, event->lost.lost); | 356 | event->lost.id, event->lost.lost); |
@@ -984,7 +985,8 @@ out_problem: | |||
984 | } | 985 | } |
985 | 986 | ||
986 | int machine__process_mmap2_event(struct machine *machine, | 987 | int machine__process_mmap2_event(struct machine *machine, |
987 | union perf_event *event) | 988 | union perf_event *event, |
989 | struct perf_sample *sample __maybe_unused) | ||
988 | { | 990 | { |
989 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 991 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
990 | struct thread *thread; | 992 | struct thread *thread; |
@@ -1031,7 +1033,8 @@ out_problem: | |||
1031 | return 0; | 1033 | return 0; |
1032 | } | 1034 | } |
1033 | 1035 | ||
1034 | int machine__process_mmap_event(struct machine *machine, union perf_event *event) | 1036 | int machine__process_mmap_event(struct machine *machine, union perf_event *event, |
1037 | struct perf_sample *sample __maybe_unused) | ||
1035 | { | 1038 | { |
1036 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 1039 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
1037 | struct thread *thread; | 1040 | struct thread *thread; |
@@ -1088,7 +1091,8 @@ static void machine__remove_thread(struct machine *machine, struct thread *th) | |||
1088 | list_add_tail(&th->node, &machine->dead_threads); | 1091 | list_add_tail(&th->node, &machine->dead_threads); |
1089 | } | 1092 | } |
1090 | 1093 | ||
1091 | int machine__process_fork_event(struct machine *machine, union perf_event *event) | 1094 | int machine__process_fork_event(struct machine *machine, union perf_event *event, |
1095 | struct perf_sample *sample) | ||
1092 | { | 1096 | { |
1093 | struct thread *thread = machine__find_thread(machine, event->fork.tid); | 1097 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
1094 | struct thread *parent = machine__findnew_thread(machine, | 1098 | struct thread *parent = machine__findnew_thread(machine, |
@@ -1105,7 +1109,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1105 | perf_event__fprintf_task(event, stdout); | 1109 | perf_event__fprintf_task(event, stdout); |
1106 | 1110 | ||
1107 | if (thread == NULL || parent == NULL || | 1111 | if (thread == NULL || parent == NULL || |
1108 | thread__fork(thread, parent) < 0) { | 1112 | thread__fork(thread, parent, sample->time) < 0) { |
1109 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); | 1113 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); |
1110 | return -1; | 1114 | return -1; |
1111 | } | 1115 | } |
@@ -1113,8 +1117,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1113 | return 0; | 1117 | return 0; |
1114 | } | 1118 | } |
1115 | 1119 | ||
1116 | int machine__process_exit_event(struct machine *machine __maybe_unused, | 1120 | int machine__process_exit_event(struct machine *machine, union perf_event *event, |
1117 | union perf_event *event) | 1121 | struct perf_sample *sample __maybe_unused) |
1118 | { | 1122 | { |
1119 | struct thread *thread = machine__find_thread(machine, event->fork.tid); | 1123 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
1120 | 1124 | ||
@@ -1127,23 +1131,24 @@ int machine__process_exit_event(struct machine *machine __maybe_unused, | |||
1127 | return 0; | 1131 | return 0; |
1128 | } | 1132 | } |
1129 | 1133 | ||
1130 | int machine__process_event(struct machine *machine, union perf_event *event) | 1134 | int machine__process_event(struct machine *machine, union perf_event *event, |
1135 | struct perf_sample *sample) | ||
1131 | { | 1136 | { |
1132 | int ret; | 1137 | int ret; |
1133 | 1138 | ||
1134 | switch (event->header.type) { | 1139 | switch (event->header.type) { |
1135 | case PERF_RECORD_COMM: | 1140 | case PERF_RECORD_COMM: |
1136 | ret = machine__process_comm_event(machine, event); break; | 1141 | ret = machine__process_comm_event(machine, event, sample); break; |
1137 | case PERF_RECORD_MMAP: | 1142 | case PERF_RECORD_MMAP: |
1138 | ret = machine__process_mmap_event(machine, event); break; | 1143 | ret = machine__process_mmap_event(machine, event, sample); break; |
1139 | case PERF_RECORD_MMAP2: | 1144 | case PERF_RECORD_MMAP2: |
1140 | ret = machine__process_mmap2_event(machine, event); break; | 1145 | ret = machine__process_mmap2_event(machine, event, sample); break; |
1141 | case PERF_RECORD_FORK: | 1146 | case PERF_RECORD_FORK: |
1142 | ret = machine__process_fork_event(machine, event); break; | 1147 | ret = machine__process_fork_event(machine, event, sample); break; |
1143 | case PERF_RECORD_EXIT: | 1148 | case PERF_RECORD_EXIT: |
1144 | ret = machine__process_exit_event(machine, event); break; | 1149 | ret = machine__process_exit_event(machine, event, sample); break; |
1145 | case PERF_RECORD_LOST: | 1150 | case PERF_RECORD_LOST: |
1146 | ret = machine__process_lost_event(machine, event); break; | 1151 | ret = machine__process_lost_event(machine, event, sample); break; |
1147 | default: | 1152 | default: |
1148 | ret = -1; | 1153 | ret = -1; |
1149 | break; | 1154 | break; |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 4c1f5d567f54..2389ba81fafe 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -40,13 +40,20 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type) | |||
40 | 40 | ||
41 | struct thread *machine__find_thread(struct machine *machine, pid_t tid); | 41 | struct thread *machine__find_thread(struct machine *machine, pid_t tid); |
42 | 42 | ||
43 | int machine__process_comm_event(struct machine *machine, union perf_event *event); | 43 | int machine__process_comm_event(struct machine *machine, union perf_event *event, |
44 | int machine__process_exit_event(struct machine *machine, union perf_event *event); | 44 | struct perf_sample *sample); |
45 | int machine__process_fork_event(struct machine *machine, union perf_event *event); | 45 | int machine__process_exit_event(struct machine *machine, union perf_event *event, |
46 | int machine__process_lost_event(struct machine *machine, union perf_event *event); | 46 | struct perf_sample *sample); |
47 | int machine__process_mmap_event(struct machine *machine, union perf_event *event); | 47 | int machine__process_fork_event(struct machine *machine, union perf_event *event, |
48 | int machine__process_mmap2_event(struct machine *machine, union perf_event *event); | 48 | struct perf_sample *sample); |
49 | int machine__process_event(struct machine *machine, union perf_event *event); | 49 | int machine__process_lost_event(struct machine *machine, union perf_event *event, |
50 | struct perf_sample *sample); | ||
51 | int machine__process_mmap_event(struct machine *machine, union perf_event *event, | ||
52 | struct perf_sample *sample); | ||
53 | int machine__process_mmap2_event(struct machine *machine, union perf_event *event, | ||
54 | struct perf_sample *sample); | ||
55 | int machine__process_event(struct machine *machine, union perf_event *event, | ||
56 | struct perf_sample *sample); | ||
50 | 57 | ||
51 | typedef void (*machine__process_t)(struct machine *machine, void *data); | 58 | typedef void (*machine__process_t)(struct machine *machine, void *data); |
52 | 59 | ||
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 2bc9e70df7e2..31f404a032a9 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c | |||
@@ -339,10 +339,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, | |||
339 | if (arg[1] != '-') { | 339 | if (arg[1] != '-') { |
340 | ctx->opt = arg + 1; | 340 | ctx->opt = arg + 1; |
341 | if (internal_help && *ctx->opt == 'h') | 341 | if (internal_help && *ctx->opt == 'h') |
342 | return parse_options_usage(usagestr, options); | 342 | return usage_with_options_internal(usagestr, options, 0); |
343 | switch (parse_short_opt(ctx, options)) { | 343 | switch (parse_short_opt(ctx, options)) { |
344 | case -1: | 344 | case -1: |
345 | return parse_options_usage(usagestr, options); | 345 | return parse_options_usage(usagestr, options, arg + 1, 1); |
346 | case -2: | 346 | case -2: |
347 | goto unknown; | 347 | goto unknown; |
348 | default: | 348 | default: |
@@ -352,10 +352,11 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, | |||
352 | check_typos(arg + 1, options); | 352 | check_typos(arg + 1, options); |
353 | while (ctx->opt) { | 353 | while (ctx->opt) { |
354 | if (internal_help && *ctx->opt == 'h') | 354 | if (internal_help && *ctx->opt == 'h') |
355 | return parse_options_usage(usagestr, options); | 355 | return usage_with_options_internal(usagestr, options, 0); |
356 | arg = ctx->opt; | ||
356 | switch (parse_short_opt(ctx, options)) { | 357 | switch (parse_short_opt(ctx, options)) { |
357 | case -1: | 358 | case -1: |
358 | return parse_options_usage(usagestr, options); | 359 | return parse_options_usage(usagestr, options, arg, 1); |
359 | case -2: | 360 | case -2: |
360 | /* fake a short option thing to hide the fact that we may have | 361 | /* fake a short option thing to hide the fact that we may have |
361 | * started to parse aggregated stuff | 362 | * started to parse aggregated stuff |
@@ -383,12 +384,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, | |||
383 | if (internal_help && !strcmp(arg + 2, "help-all")) | 384 | if (internal_help && !strcmp(arg + 2, "help-all")) |
384 | return usage_with_options_internal(usagestr, options, 1); | 385 | return usage_with_options_internal(usagestr, options, 1); |
385 | if (internal_help && !strcmp(arg + 2, "help")) | 386 | if (internal_help && !strcmp(arg + 2, "help")) |
386 | return parse_options_usage(usagestr, options); | 387 | return usage_with_options_internal(usagestr, options, 0); |
387 | if (!strcmp(arg + 2, "list-opts")) | 388 | if (!strcmp(arg + 2, "list-opts")) |
388 | return PARSE_OPT_LIST; | 389 | return PARSE_OPT_LIST; |
389 | switch (parse_long_opt(ctx, arg + 2, options)) { | 390 | switch (parse_long_opt(ctx, arg + 2, options)) { |
390 | case -1: | 391 | case -1: |
391 | return parse_options_usage(usagestr, options); | 392 | return parse_options_usage(usagestr, options, arg + 2, 0); |
392 | case -2: | 393 | case -2: |
393 | goto unknown; | 394 | goto unknown; |
394 | default: | 395 | default: |
@@ -445,6 +446,89 @@ int parse_options(int argc, const char **argv, const struct option *options, | |||
445 | #define USAGE_OPTS_WIDTH 24 | 446 | #define USAGE_OPTS_WIDTH 24 |
446 | #define USAGE_GAP 2 | 447 | #define USAGE_GAP 2 |
447 | 448 | ||
449 | static void print_option_help(const struct option *opts, int full) | ||
450 | { | ||
451 | size_t pos; | ||
452 | int pad; | ||
453 | |||
454 | if (opts->type == OPTION_GROUP) { | ||
455 | fputc('\n', stderr); | ||
456 | if (*opts->help) | ||
457 | fprintf(stderr, "%s\n", opts->help); | ||
458 | return; | ||
459 | } | ||
460 | if (!full && (opts->flags & PARSE_OPT_HIDDEN)) | ||
461 | return; | ||
462 | |||
463 | pos = fprintf(stderr, " "); | ||
464 | if (opts->short_name) | ||
465 | pos += fprintf(stderr, "-%c", opts->short_name); | ||
466 | else | ||
467 | pos += fprintf(stderr, " "); | ||
468 | |||
469 | if (opts->long_name && opts->short_name) | ||
470 | pos += fprintf(stderr, ", "); | ||
471 | if (opts->long_name) | ||
472 | pos += fprintf(stderr, "--%s", opts->long_name); | ||
473 | |||
474 | switch (opts->type) { | ||
475 | case OPTION_ARGUMENT: | ||
476 | break; | ||
477 | case OPTION_LONG: | ||
478 | case OPTION_U64: | ||
479 | case OPTION_INTEGER: | ||
480 | case OPTION_UINTEGER: | ||
481 | if (opts->flags & PARSE_OPT_OPTARG) | ||
482 | if (opts->long_name) | ||
483 | pos += fprintf(stderr, "[=<n>]"); | ||
484 | else | ||
485 | pos += fprintf(stderr, "[<n>]"); | ||
486 | else | ||
487 | pos += fprintf(stderr, " <n>"); | ||
488 | break; | ||
489 | case OPTION_CALLBACK: | ||
490 | if (opts->flags & PARSE_OPT_NOARG) | ||
491 | break; | ||
492 | /* FALLTHROUGH */ | ||
493 | case OPTION_STRING: | ||
494 | if (opts->argh) { | ||
495 | if (opts->flags & PARSE_OPT_OPTARG) | ||
496 | if (opts->long_name) | ||
497 | pos += fprintf(stderr, "[=<%s>]", opts->argh); | ||
498 | else | ||
499 | pos += fprintf(stderr, "[<%s>]", opts->argh); | ||
500 | else | ||
501 | pos += fprintf(stderr, " <%s>", opts->argh); | ||
502 | } else { | ||
503 | if (opts->flags & PARSE_OPT_OPTARG) | ||
504 | if (opts->long_name) | ||
505 | pos += fprintf(stderr, "[=...]"); | ||
506 | else | ||
507 | pos += fprintf(stderr, "[...]"); | ||
508 | else | ||
509 | pos += fprintf(stderr, " ..."); | ||
510 | } | ||
511 | break; | ||
512 | default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */ | ||
513 | case OPTION_END: | ||
514 | case OPTION_GROUP: | ||
515 | case OPTION_BIT: | ||
516 | case OPTION_BOOLEAN: | ||
517 | case OPTION_INCR: | ||
518 | case OPTION_SET_UINT: | ||
519 | case OPTION_SET_PTR: | ||
520 | break; | ||
521 | } | ||
522 | |||
523 | if (pos <= USAGE_OPTS_WIDTH) | ||
524 | pad = USAGE_OPTS_WIDTH - pos; | ||
525 | else { | ||
526 | fputc('\n', stderr); | ||
527 | pad = USAGE_OPTS_WIDTH; | ||
528 | } | ||
529 | fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); | ||
530 | } | ||
531 | |||
448 | int usage_with_options_internal(const char * const *usagestr, | 532 | int usage_with_options_internal(const char * const *usagestr, |
449 | const struct option *opts, int full) | 533 | const struct option *opts, int full) |
450 | { | 534 | { |
@@ -464,87 +548,9 @@ int usage_with_options_internal(const char * const *usagestr, | |||
464 | if (opts->type != OPTION_GROUP) | 548 | if (opts->type != OPTION_GROUP) |
465 | fputc('\n', stderr); | 549 | fputc('\n', stderr); |
466 | 550 | ||
467 | for (; opts->type != OPTION_END; opts++) { | 551 | for ( ; opts->type != OPTION_END; opts++) |
468 | size_t pos; | 552 | print_option_help(opts, full); |
469 | int pad; | ||
470 | |||
471 | if (opts->type == OPTION_GROUP) { | ||
472 | fputc('\n', stderr); | ||
473 | if (*opts->help) | ||
474 | fprintf(stderr, "%s\n", opts->help); | ||
475 | continue; | ||
476 | } | ||
477 | if (!full && (opts->flags & PARSE_OPT_HIDDEN)) | ||
478 | continue; | ||
479 | |||
480 | pos = fprintf(stderr, " "); | ||
481 | if (opts->short_name) | ||
482 | pos += fprintf(stderr, "-%c", opts->short_name); | ||
483 | else | ||
484 | pos += fprintf(stderr, " "); | ||
485 | |||
486 | if (opts->long_name && opts->short_name) | ||
487 | pos += fprintf(stderr, ", "); | ||
488 | if (opts->long_name) | ||
489 | pos += fprintf(stderr, "--%s", opts->long_name); | ||
490 | |||
491 | switch (opts->type) { | ||
492 | case OPTION_ARGUMENT: | ||
493 | break; | ||
494 | case OPTION_LONG: | ||
495 | case OPTION_U64: | ||
496 | case OPTION_INTEGER: | ||
497 | case OPTION_UINTEGER: | ||
498 | if (opts->flags & PARSE_OPT_OPTARG) | ||
499 | if (opts->long_name) | ||
500 | pos += fprintf(stderr, "[=<n>]"); | ||
501 | else | ||
502 | pos += fprintf(stderr, "[<n>]"); | ||
503 | else | ||
504 | pos += fprintf(stderr, " <n>"); | ||
505 | break; | ||
506 | case OPTION_CALLBACK: | ||
507 | if (opts->flags & PARSE_OPT_NOARG) | ||
508 | break; | ||
509 | /* FALLTHROUGH */ | ||
510 | case OPTION_STRING: | ||
511 | if (opts->argh) { | ||
512 | if (opts->flags & PARSE_OPT_OPTARG) | ||
513 | if (opts->long_name) | ||
514 | pos += fprintf(stderr, "[=<%s>]", opts->argh); | ||
515 | else | ||
516 | pos += fprintf(stderr, "[<%s>]", opts->argh); | ||
517 | else | ||
518 | pos += fprintf(stderr, " <%s>", opts->argh); | ||
519 | } else { | ||
520 | if (opts->flags & PARSE_OPT_OPTARG) | ||
521 | if (opts->long_name) | ||
522 | pos += fprintf(stderr, "[=...]"); | ||
523 | else | ||
524 | pos += fprintf(stderr, "[...]"); | ||
525 | else | ||
526 | pos += fprintf(stderr, " ..."); | ||
527 | } | ||
528 | break; | ||
529 | default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */ | ||
530 | case OPTION_END: | ||
531 | case OPTION_GROUP: | ||
532 | case OPTION_BIT: | ||
533 | case OPTION_BOOLEAN: | ||
534 | case OPTION_INCR: | ||
535 | case OPTION_SET_UINT: | ||
536 | case OPTION_SET_PTR: | ||
537 | break; | ||
538 | } | ||
539 | 553 | ||
540 | if (pos <= USAGE_OPTS_WIDTH) | ||
541 | pad = USAGE_OPTS_WIDTH - pos; | ||
542 | else { | ||
543 | fputc('\n', stderr); | ||
544 | pad = USAGE_OPTS_WIDTH; | ||
545 | } | ||
546 | fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); | ||
547 | } | ||
548 | fputc('\n', stderr); | 554 | fputc('\n', stderr); |
549 | 555 | ||
550 | return PARSE_OPT_HELP; | 556 | return PARSE_OPT_HELP; |
@@ -559,9 +565,45 @@ void usage_with_options(const char * const *usagestr, | |||
559 | } | 565 | } |
560 | 566 | ||
561 | int parse_options_usage(const char * const *usagestr, | 567 | int parse_options_usage(const char * const *usagestr, |
562 | const struct option *opts) | 568 | const struct option *opts, |
569 | const char *optstr, bool short_opt) | ||
563 | { | 570 | { |
564 | return usage_with_options_internal(usagestr, opts, 0); | 571 | if (!usagestr) |
572 | goto opt; | ||
573 | |||
574 | fprintf(stderr, "\n usage: %s\n", *usagestr++); | ||
575 | while (*usagestr && **usagestr) | ||
576 | fprintf(stderr, " or: %s\n", *usagestr++); | ||
577 | while (*usagestr) { | ||
578 | fprintf(stderr, "%s%s\n", | ||
579 | **usagestr ? " " : "", | ||
580 | *usagestr); | ||
581 | usagestr++; | ||
582 | } | ||
583 | fputc('\n', stderr); | ||
584 | |||
585 | opt: | ||
586 | for ( ; opts->type != OPTION_END; opts++) { | ||
587 | if (short_opt) { | ||
588 | if (opts->short_name == *optstr) | ||
589 | break; | ||
590 | continue; | ||
591 | } | ||
592 | |||
593 | if (opts->long_name == NULL) | ||
594 | continue; | ||
595 | |||
596 | if (!prefixcmp(optstr, opts->long_name)) | ||
597 | break; | ||
598 | if (!prefixcmp(optstr, "no-") && | ||
599 | !prefixcmp(optstr + 3, opts->long_name)) | ||
600 | break; | ||
601 | } | ||
602 | |||
603 | if (opts->type != OPTION_END) | ||
604 | print_option_help(opts, 0); | ||
605 | |||
606 | return PARSE_OPT_HELP; | ||
565 | } | 607 | } |
566 | 608 | ||
567 | 609 | ||
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index 7bb5999940ca..b0241e28eaf7 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h | |||
@@ -158,7 +158,9 @@ struct parse_opt_ctx_t { | |||
158 | }; | 158 | }; |
159 | 159 | ||
160 | extern int parse_options_usage(const char * const *usagestr, | 160 | extern int parse_options_usage(const char * const *usagestr, |
161 | const struct option *opts); | 161 | const struct option *opts, |
162 | const char *optstr, | ||
163 | bool short_opt); | ||
162 | 164 | ||
163 | extern void parse_options_start(struct parse_opt_ctx_t *ctx, | 165 | extern void parse_options_start(struct parse_opt_ctx_t *ctx, |
164 | int argc, const char **argv, int flags); | 166 | int argc, const char **argv, int flags); |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index e41b0941e18f..2200dad4c3f4 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -583,7 +583,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | |||
583 | } | 583 | } |
584 | 584 | ||
585 | if (die_find_member(&type, field->name, die_mem) == NULL) { | 585 | if (die_find_member(&type, field->name, die_mem) == NULL) { |
586 | pr_warning("%s(tyep:%s) has no member %s.\n", varname, | 586 | pr_warning("%s(type:%s) has no member %s.\n", varname, |
587 | dwarf_diename(&type), field->name); | 587 | dwarf_diename(&type), field->name); |
588 | return -EINVAL; | 588 | return -EINVAL; |
589 | } | 589 | } |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index c0c9795c4f02..d5e5969f6fea 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -273,7 +273,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, | |||
273 | int cpu = sample->cpu; | 273 | int cpu = sample->cpu; |
274 | void *data = sample->raw_data; | 274 | void *data = sample->raw_data; |
275 | unsigned long long nsecs = sample->time; | 275 | unsigned long long nsecs = sample->time; |
276 | char *comm = thread->comm; | 276 | const char *comm = thread__comm_str(thread); |
277 | 277 | ||
278 | dSP; | 278 | dSP; |
279 | 279 | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 95d91a0b23af..53c20e7fd900 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -250,7 +250,7 @@ static void python_process_tracepoint(union perf_event *perf_event | |||
250 | int cpu = sample->cpu; | 250 | int cpu = sample->cpu; |
251 | void *data = sample->raw_data; | 251 | void *data = sample->raw_data; |
252 | unsigned long long nsecs = sample->time; | 252 | unsigned long long nsecs = sample->time; |
253 | char *comm = thread->comm; | 253 | const char *comm = thread__comm_str(thread); |
254 | 254 | ||
255 | t = PyTuple_New(MAX_FIELDS); | 255 | t = PyTuple_New(MAX_FIELDS); |
256 | if (!t) | 256 | if (!t) |
@@ -389,7 +389,7 @@ static void python_process_general_event(union perf_event *perf_event | |||
389 | pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( | 389 | pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( |
390 | (const char *)sample->raw_data, sample->raw_size)); | 390 | (const char *)sample->raw_data, sample->raw_size)); |
391 | pydict_set_item_string_decref(dict, "comm", | 391 | pydict_set_item_string_decref(dict, "comm", |
392 | PyString_FromString(thread->comm)); | 392 | PyString_FromString(thread__comm_str(thread))); |
393 | if (al->map) { | 393 | if (al->map) { |
394 | pydict_set_item_string_decref(dict, "dso", | 394 | pydict_set_item_string_decref(dict, "dso", |
395 | PyString_FromString(al->map->dso->name)); | 395 | PyString_FromString(al->map->dso->name)); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4ba7b548e055..3c1b30103d54 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1100,7 +1100,7 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se | |||
1100 | { | 1100 | { |
1101 | struct thread *thread = perf_session__findnew(self, 0); | 1101 | struct thread *thread = perf_session__findnew(self, 0); |
1102 | 1102 | ||
1103 | if (thread == NULL || thread__set_comm(thread, "swapper")) { | 1103 | if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { |
1104 | pr_err("problem inserting idle task.\n"); | 1104 | pr_err("problem inserting idle task.\n"); |
1105 | thread = NULL; | 1105 | thread = NULL; |
1106 | } | 1106 | } |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 19b4aa279d1e..3c1b75c8b9a6 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include "sort.h" | 1 | #include "sort.h" |
2 | #include "hist.h" | 2 | #include "hist.h" |
3 | #include "comm.h" | ||
3 | #include "symbol.h" | 4 | #include "symbol.h" |
4 | 5 | ||
5 | regex_t parent_regex; | 6 | regex_t parent_regex; |
@@ -42,7 +43,7 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) | |||
42 | return n; | 43 | return n; |
43 | } | 44 | } |
44 | 45 | ||
45 | static int64_t cmp_null(void *l, void *r) | 46 | static int64_t cmp_null(const void *l, const void *r) |
46 | { | 47 | { |
47 | if (!l && !r) | 48 | if (!l && !r) |
48 | return 0; | 49 | return 0; |
@@ -63,8 +64,9 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) | |||
63 | static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, | 64 | static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, |
64 | size_t size, unsigned int width) | 65 | size_t size, unsigned int width) |
65 | { | 66 | { |
67 | const char *comm = thread__comm_str(he->thread); | ||
66 | return repsep_snprintf(bf, size, "%*s:%5d", width - 6, | 68 | return repsep_snprintf(bf, size, "%*s:%5d", width - 6, |
67 | he->thread->comm ?: "", he->thread->tid); | 69 | comm ?: "", he->thread->tid); |
68 | } | 70 | } |
69 | 71 | ||
70 | struct sort_entry sort_thread = { | 72 | struct sort_entry sort_thread = { |
@@ -79,25 +81,21 @@ struct sort_entry sort_thread = { | |||
79 | static int64_t | 81 | static int64_t |
80 | sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) | 82 | sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) |
81 | { | 83 | { |
82 | return right->thread->tid - left->thread->tid; | 84 | /* Compare the addr that should be unique among comm */ |
85 | return comm__str(right->comm) - comm__str(left->comm); | ||
83 | } | 86 | } |
84 | 87 | ||
85 | static int64_t | 88 | static int64_t |
86 | sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) | 89 | sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) |
87 | { | 90 | { |
88 | char *comm_l = left->thread->comm; | 91 | /* Compare the addr that should be unique among comm */ |
89 | char *comm_r = right->thread->comm; | 92 | return comm__str(right->comm) - comm__str(left->comm); |
90 | |||
91 | if (!comm_l || !comm_r) | ||
92 | return cmp_null(comm_l, comm_r); | ||
93 | |||
94 | return strcmp(comm_l, comm_r); | ||
95 | } | 93 | } |
96 | 94 | ||
97 | static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, | 95 | static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, |
98 | size_t size, unsigned int width) | 96 | size_t size, unsigned int width) |
99 | { | 97 | { |
100 | return repsep_snprintf(bf, size, "%*s", width, he->thread->comm); | 98 | return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm)); |
101 | } | 99 | } |
102 | 100 | ||
103 | struct sort_entry sort_comm = { | 101 | struct sort_entry sort_comm = { |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index bf4333694d3a..f4e16f359d64 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -84,6 +84,7 @@ struct hist_entry { | |||
84 | struct he_stat stat; | 84 | struct he_stat stat; |
85 | struct map_symbol ms; | 85 | struct map_symbol ms; |
86 | struct thread *thread; | 86 | struct thread *thread; |
87 | struct comm *comm; | ||
87 | u64 ip; | 88 | u64 ip; |
88 | u64 transaction; | 89 | u64 transaction; |
89 | s32 cpu; | 90 | s32 cpu; |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 80d19a086072..cd8e2f592719 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -6,9 +6,12 @@ | |||
6 | #include "thread.h" | 6 | #include "thread.h" |
7 | #include "util.h" | 7 | #include "util.h" |
8 | #include "debug.h" | 8 | #include "debug.h" |
9 | #include "comm.h" | ||
9 | 10 | ||
10 | struct thread *thread__new(pid_t pid, pid_t tid) | 11 | struct thread *thread__new(pid_t pid, pid_t tid) |
11 | { | 12 | { |
13 | char *comm_str; | ||
14 | struct comm *comm; | ||
12 | struct thread *thread = zalloc(sizeof(*thread)); | 15 | struct thread *thread = zalloc(sizeof(*thread)); |
13 | 16 | ||
14 | if (thread != NULL) { | 17 | if (thread != NULL) { |
@@ -16,41 +19,88 @@ struct thread *thread__new(pid_t pid, pid_t tid) | |||
16 | thread->pid_ = pid; | 19 | thread->pid_ = pid; |
17 | thread->tid = tid; | 20 | thread->tid = tid; |
18 | thread->ppid = -1; | 21 | thread->ppid = -1; |
19 | thread->comm = malloc(32); | 22 | INIT_LIST_HEAD(&thread->comm_list); |
20 | if (thread->comm) | 23 | |
21 | snprintf(thread->comm, 32, ":%d", thread->tid); | 24 | comm_str = malloc(32); |
25 | if (!comm_str) | ||
26 | goto err_thread; | ||
27 | |||
28 | snprintf(comm_str, 32, ":%d", tid); | ||
29 | comm = comm__new(comm_str, 0); | ||
30 | free(comm_str); | ||
31 | if (!comm) | ||
32 | goto err_thread; | ||
33 | |||
34 | list_add(&comm->list, &thread->comm_list); | ||
22 | } | 35 | } |
23 | 36 | ||
24 | return thread; | 37 | return thread; |
38 | |||
39 | err_thread: | ||
40 | free(thread); | ||
41 | return NULL; | ||
25 | } | 42 | } |
26 | 43 | ||
27 | void thread__delete(struct thread *thread) | 44 | void thread__delete(struct thread *thread) |
28 | { | 45 | { |
46 | struct comm *comm, *tmp; | ||
47 | |||
29 | map_groups__exit(&thread->mg); | 48 | map_groups__exit(&thread->mg); |
30 | free(thread->comm); | 49 | list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { |
50 | list_del(&comm->list); | ||
51 | comm__free(comm); | ||
52 | } | ||
53 | |||
31 | free(thread); | 54 | free(thread); |
32 | } | 55 | } |
33 | 56 | ||
34 | int thread__set_comm(struct thread *thread, const char *comm) | 57 | struct comm *thread__comm(const struct thread *thread) |
35 | { | 58 | { |
36 | int err; | 59 | if (list_empty(&thread->comm_list)) |
60 | return NULL; | ||
37 | 61 | ||
38 | if (thread->comm) | 62 | return list_first_entry(&thread->comm_list, struct comm, list); |
39 | free(thread->comm); | 63 | } |
40 | thread->comm = strdup(comm); | 64 | |
41 | err = thread->comm == NULL ? -ENOMEM : 0; | 65 | /* CHECKME: time should always be 0 if event aren't ordered */ |
42 | if (!err) { | 66 | int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) |
43 | thread->comm_set = true; | 67 | { |
68 | struct comm *new, *curr = thread__comm(thread); | ||
69 | |||
70 | /* Override latest entry if it had no specific time coverage */ | ||
71 | if (!curr->start) { | ||
72 | comm__override(curr, str, timestamp); | ||
73 | return 0; | ||
44 | } | 74 | } |
45 | return err; | 75 | |
76 | new = comm__new(str, timestamp); | ||
77 | if (!new) | ||
78 | return -ENOMEM; | ||
79 | |||
80 | list_add(&new->list, &thread->comm_list); | ||
81 | thread->comm_set = true; | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | const char *thread__comm_str(const struct thread *thread) | ||
87 | { | ||
88 | const struct comm *comm = thread__comm(thread); | ||
89 | |||
90 | if (!comm) | ||
91 | return NULL; | ||
92 | |||
93 | return comm__str(comm); | ||
46 | } | 94 | } |
47 | 95 | ||
96 | /* CHECKME: it should probably better return the max comm len from its comm list */ | ||
48 | int thread__comm_len(struct thread *thread) | 97 | int thread__comm_len(struct thread *thread) |
49 | { | 98 | { |
50 | if (!thread->comm_len) { | 99 | if (!thread->comm_len) { |
51 | if (!thread->comm) | 100 | const char *comm = thread__comm_str(thread); |
101 | if (!comm) | ||
52 | return 0; | 102 | return 0; |
53 | thread->comm_len = strlen(thread->comm); | 103 | thread->comm_len = strlen(comm); |
54 | } | 104 | } |
55 | 105 | ||
56 | return thread->comm_len; | 106 | return thread->comm_len; |
@@ -58,7 +108,7 @@ int thread__comm_len(struct thread *thread) | |||
58 | 108 | ||
59 | size_t thread__fprintf(struct thread *thread, FILE *fp) | 109 | size_t thread__fprintf(struct thread *thread, FILE *fp) |
60 | { | 110 | { |
61 | return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) + | 111 | return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + |
62 | map_groups__fprintf(&thread->mg, verbose, fp); | 112 | map_groups__fprintf(&thread->mg, verbose, fp); |
63 | } | 113 | } |
64 | 114 | ||
@@ -68,16 +118,17 @@ void thread__insert_map(struct thread *thread, struct map *map) | |||
68 | map_groups__insert(&thread->mg, map); | 118 | map_groups__insert(&thread->mg, map); |
69 | } | 119 | } |
70 | 120 | ||
71 | int thread__fork(struct thread *thread, struct thread *parent) | 121 | int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) |
72 | { | 122 | { |
73 | int i; | 123 | int i, err; |
74 | 124 | ||
75 | if (parent->comm_set) { | 125 | if (parent->comm_set) { |
76 | if (thread->comm) | 126 | const char *comm = thread__comm_str(parent); |
77 | free(thread->comm); | 127 | if (!comm) |
78 | thread->comm = strdup(parent->comm); | ||
79 | if (!thread->comm) | ||
80 | return -ENOMEM; | 128 | return -ENOMEM; |
129 | err = thread__set_comm(thread, comm, timestamp); | ||
130 | if (!err) | ||
131 | return err; | ||
81 | thread->comm_set = true; | 132 | thread->comm_set = true; |
82 | } | 133 | } |
83 | 134 | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 4ebbb40d46d4..373c055989ed 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __PERF_THREAD_H | 2 | #define __PERF_THREAD_H |
3 | 3 | ||
4 | #include <linux/rbtree.h> | 4 | #include <linux/rbtree.h> |
5 | #include <linux/list.h> | ||
5 | #include <unistd.h> | 6 | #include <unistd.h> |
6 | #include <sys/types.h> | 7 | #include <sys/types.h> |
7 | #include "symbol.h" | 8 | #include "symbol.h" |
@@ -18,13 +19,14 @@ struct thread { | |||
18 | char shortname[3]; | 19 | char shortname[3]; |
19 | bool comm_set; | 20 | bool comm_set; |
20 | bool dead; /* if set thread has exited */ | 21 | bool dead; /* if set thread has exited */ |
21 | char *comm; | 22 | struct list_head comm_list; |
22 | int comm_len; | 23 | int comm_len; |
23 | 24 | ||
24 | void *priv; | 25 | void *priv; |
25 | }; | 26 | }; |
26 | 27 | ||
27 | struct machine; | 28 | struct machine; |
29 | struct comm; | ||
28 | 30 | ||
29 | struct thread *thread__new(pid_t pid, pid_t tid); | 31 | struct thread *thread__new(pid_t pid, pid_t tid); |
30 | void thread__delete(struct thread *self); | 32 | void thread__delete(struct thread *self); |
@@ -33,10 +35,12 @@ static inline void thread__exited(struct thread *thread) | |||
33 | thread->dead = true; | 35 | thread->dead = true; |
34 | } | 36 | } |
35 | 37 | ||
36 | int thread__set_comm(struct thread *self, const char *comm); | 38 | int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp); |
37 | int thread__comm_len(struct thread *self); | 39 | int thread__comm_len(struct thread *self); |
40 | struct comm *thread__comm(const struct thread *thread); | ||
41 | const char *thread__comm_str(const struct thread *thread); | ||
38 | void thread__insert_map(struct thread *self, struct map *map); | 42 | void thread__insert_map(struct thread *self, struct map *map); |
39 | int thread__fork(struct thread *self, struct thread *parent); | 43 | int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); |
40 | size_t thread__fprintf(struct thread *thread, FILE *fp); | 44 | size_t thread__fprintf(struct thread *thread, FILE *fp); |
41 | 45 | ||
42 | static inline struct map *thread__find_map(struct thread *self, | 46 | static inline struct map *thread__find_map(struct thread *self, |