aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/lib/traceevent/event-parse.c165
-rw-r--r--tools/lib/traceevent/event-parse.h14
-rw-r--r--tools/perf/Makefile.perf5
-rw-r--r--tools/perf/builtin-kmem.c2
-rw-r--r--tools/perf/builtin-lock.c2
-rw-r--r--tools/perf/builtin-report.c30
-rw-r--r--tools/perf/builtin-sched.c16
-rw-r--r--tools/perf/builtin-script.c70
-rw-r--r--tools/perf/builtin-stat.c42
-rw-r--r--tools/perf/builtin-top.c10
-rw-r--r--tools/perf/builtin-trace.c16
-rw-r--r--tools/perf/config/Makefile8
-rw-r--r--tools/perf/config/feature-checks/Makefile6
-rw-r--r--tools/perf/tests/code-reading.c2
-rw-r--r--tools/perf/tests/hists_link.c6
-rw-r--r--tools/perf/tests/sample-parsing.c7
-rw-r--r--tools/perf/ui/browsers/hists.c10
-rw-r--r--tools/perf/util/comm.c121
-rw-r--r--tools/perf/util/comm.h21
-rw-r--r--tools/perf/util/event.c32
-rw-r--r--tools/perf/util/evlist.c2
-rw-r--r--tools/perf/util/evsel.c17
-rw-r--r--tools/perf/util/hist.c3
-rw-r--r--tools/perf/util/machine.c39
-rw-r--r--tools/perf/util/machine.h21
-rw-r--r--tools/perf/util/parse-options.c218
-rw-r--r--tools/perf/util/parse-options.h4
-rw-r--r--tools/perf/util/probe-finder.c2
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c2
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c4
-rw-r--r--tools/perf/util/session.c2
-rw-r--r--tools/perf/util/sort.c20
-rw-r--r--tools/perf/util/sort.h1
-rw-r--r--tools/perf/util/thread.c95
-rw-r--r--tools/perf/util/thread.h10
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
308void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock)
309{
310 pevent->trace_clock = trace_clock;
311}
312
308struct func_map { 313struct 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 */
602int pevent_register_print_string(struct pevent *pevent, char *fmt, 607int 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
4464static 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
4446void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 4477void 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 */
5381int 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
5329static void free_func_handle(struct pevent_function_handler *func) 5412static 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
455static inline void pevent_set_flag(struct pevent *pevent, int flag) 460static inline void pevent_set_flag(struct pevent *pevent, int flag)
@@ -527,14 +532,15 @@ enum trace_flag_type {
527}; 532};
528 533
529int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); 534int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
535void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock);
530int pevent_register_function(struct pevent *pevent, char *name, 536int pevent_register_function(struct pevent *pevent, char *name,
531 unsigned long long addr, char *mod); 537 unsigned long long addr, char *mod);
532int pevent_register_print_string(struct pevent *pevent, char *fmt, 538int pevent_register_print_string(struct pevent *pevent, const char *fmt,
533 unsigned long long addr); 539 unsigned long long addr);
534int pevent_pid_is_registered(struct pevent *pevent, int pid); 540int pevent_pid_is_registered(struct pevent *pevent, int pid);
535 541
536void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 542void 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
539int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, 545int 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
572int 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
566int pevent_register_event_handler(struct pevent *pevent, int id, 576int 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
273LIB_H += util/values.h 273LIB_H += util/values.h
274LIB_H += util/sort.h 274LIB_H += util/sort.h
275LIB_H += util/hist.h 275LIB_H += util/hist.h
276LIB_H += util/comm.h
276LIB_H += util/thread.h 277LIB_H += util/thread.h
277LIB_H += util/thread_map.h 278LIB_H += util/thread_map.h
278LIB_H += util/trace-event.h 279LIB_H += util/trace-event.h
@@ -295,6 +296,7 @@ LIB_H += ui/helpline.h
295LIB_H += ui/progress.h 296LIB_H += ui/progress.h
296LIB_H += ui/util.h 297LIB_H += ui/util.h
297LIB_H += ui/ui.h 298LIB_H += ui/ui.h
299LIB_H += util/data.h
298 300
299LIB_OBJS += $(OUTPUT)util/abspath.o 301LIB_OBJS += $(OUTPUT)util/abspath.o
300LIB_OBJS += $(OUTPUT)util/alias.o 302LIB_OBJS += $(OUTPUT)util/alias.o
@@ -340,6 +342,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o
340LIB_OBJS += $(OUTPUT)util/map.o 342LIB_OBJS += $(OUTPUT)util/map.o
341LIB_OBJS += $(OUTPUT)util/pstack.o 343LIB_OBJS += $(OUTPUT)util/pstack.o
342LIB_OBJS += $(OUTPUT)util/session.o 344LIB_OBJS += $(OUTPUT)util/session.o
345LIB_OBJS += $(OUTPUT)util/comm.o
343LIB_OBJS += $(OUTPUT)util/thread.o 346LIB_OBJS += $(OUTPUT)util/thread.o
344LIB_OBJS += $(OUTPUT)util/thread_map.o 347LIB_OBJS += $(OUTPUT)util/thread_map.o
345LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 348LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
@@ -708,7 +711,7 @@ $(LIB_FILE): $(LIB_OBJS)
708TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) 711TE_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
232static 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
554static 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
550static void sig_handler(int sig __maybe_unused) 582static 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;
862next_event: 862next_event:
@@ -1040,7 +1040,7 @@ parse_percent_limit(const struct option *opt, const char *arg,
1040 1040
1041int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 1041int 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
1124static int trace__process_event(struct trace *trace, struct machine *machine, 1124static 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
1142static int trace__tool_process(struct perf_tool *tool, 1142static 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
1151static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) 1151static 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
31endif 33endif
32 34
33ifeq ($(NO_PERF_REGS),0) 35ifeq ($(NO_PERF_REGS),0)
@@ -96,7 +98,7 @@ endif
96 98
97feature_check = $(eval $(feature_check_code)) 99feature_check = $(eval $(feature_check_code))
98define feature_check_code 100define 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)
100endef 102endef
101 103
102feature_set = $(eval $(feature_set_code)) 104feature_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)))
175else 177else
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)))
178endif 180endif
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
32all: $(FILES) 32all: $(FILES)
33 33
34BUILD = $(CC) $(LDFLAGS) -o $(OUTPUT)$@ $@.c 34BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
35 35
36############################### 36###############################
37 37
38test-all: 38test-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
41test-hello: 41test-hello:
42 $(BUILD) 42 $(BUILD)
@@ -72,7 +72,7 @@ test-libnuma:
72 $(BUILD) -lnuma 72 $(BUILD) -lnuma
73 73
74test-libunwind: 74test-libunwind:
75 $(BUILD) -lunwind -lunwind-x86_64 -lelf 75 $(BUILD) $(LIBUNWIND_LIBS) -lelf
76 76
77test-libaudit: 77test-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
6struct comm_str {
7 char *str;
8 struct rb_node rb_node;
9 int ref;
10};
11
12/* Should perhaps be moved to struct machine */
13static struct rb_root comm_str_root;
14
15static void comm_str__get(struct comm_str *cs)
16{
17 cs->ref++;
18}
19
20static 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
29static 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
46static 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
77struct 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
97void 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
112void comm__free(struct comm *comm)
113{
114 comm_str__put(comm->comm_str);
115 free(comm);
116}
117
118const 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
8struct comm_str;
9
10struct comm {
11 struct comm_str *comm_str;
12 u64 start;
13 struct list_head list;
14};
15
16void comm__free(struct comm *comm);
17struct comm *comm__new(const char *str, u64 timestamp);
18const char *comm__str(const struct comm *comm);
19void 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
513int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 513int 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
521int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 521int 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
529size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 529size_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
547int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 547int 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
555int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, 555int 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
563size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 563size_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
570int perf_event__process_fork(struct perf_tool *tool __maybe_unused, 570int 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
578int perf_event__process_exit(struct perf_tool *tool __maybe_unused, 578int 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
586size_t perf_event__fprintf(union perf_event *event, FILE *fp) 586size_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
612int perf_event__process(struct perf_tool *tool __maybe_unused, 612int 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
620void thread__find_addr_map(struct thread *self, 620void 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
334int machine__process_comm_event(struct machine *machine, union perf_event *event) 334int 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
351int machine__process_lost_event(struct machine *machine __maybe_unused, 352int 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
986int machine__process_mmap2_event(struct machine *machine, 987int 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
1034int machine__process_mmap_event(struct machine *machine, union perf_event *event) 1036int 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
1091int machine__process_fork_event(struct machine *machine, union perf_event *event) 1094int 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
1116int machine__process_exit_event(struct machine *machine __maybe_unused, 1120int 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
1130int machine__process_event(struct machine *machine, union perf_event *event) 1134int 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
41struct thread *machine__find_thread(struct machine *machine, pid_t tid); 41struct thread *machine__find_thread(struct machine *machine, pid_t tid);
42 42
43int machine__process_comm_event(struct machine *machine, union perf_event *event); 43int machine__process_comm_event(struct machine *machine, union perf_event *event,
44int machine__process_exit_event(struct machine *machine, union perf_event *event); 44 struct perf_sample *sample);
45int machine__process_fork_event(struct machine *machine, union perf_event *event); 45int machine__process_exit_event(struct machine *machine, union perf_event *event,
46int machine__process_lost_event(struct machine *machine, union perf_event *event); 46 struct perf_sample *sample);
47int machine__process_mmap_event(struct machine *machine, union perf_event *event); 47int machine__process_fork_event(struct machine *machine, union perf_event *event,
48int machine__process_mmap2_event(struct machine *machine, union perf_event *event); 48 struct perf_sample *sample);
49int machine__process_event(struct machine *machine, union perf_event *event); 49int machine__process_lost_event(struct machine *machine, union perf_event *event,
50 struct perf_sample *sample);
51int machine__process_mmap_event(struct machine *machine, union perf_event *event,
52 struct perf_sample *sample);
53int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
54 struct perf_sample *sample);
55int machine__process_event(struct machine *machine, union perf_event *event,
56 struct perf_sample *sample);
50 57
51typedef void (*machine__process_t)(struct machine *machine, void *data); 58typedef 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
449static 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
448int usage_with_options_internal(const char * const *usagestr, 532int 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
561int parse_options_usage(const char * const *usagestr, 567int 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
585opt:
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
160extern int parse_options_usage(const char * const *usagestr, 160extern 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
163extern void parse_options_start(struct parse_opt_ctx_t *ctx, 165extern 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
5regex_t parent_regex; 6regex_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
45static int64_t cmp_null(void *l, void *r) 46static 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)
63static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, 64static 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
70struct sort_entry sort_thread = { 72struct sort_entry sort_thread = {
@@ -79,25 +81,21 @@ struct sort_entry sort_thread = {
79static int64_t 81static int64_t
80sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 82sort__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
85static int64_t 88static int64_t
86sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) 89sort__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
97static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, 95static 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
103struct sort_entry sort_comm = { 101struct 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
10struct thread *thread__new(pid_t pid, pid_t tid) 11struct 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
39err_thread:
40 free(thread);
41 return NULL;
25} 42}
26 43
27void thread__delete(struct thread *thread) 44void 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
34int thread__set_comm(struct thread *thread, const char *comm) 57struct 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) { 66int 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
86const 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 */
48int thread__comm_len(struct thread *thread) 97int 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
59size_t thread__fprintf(struct thread *thread, FILE *fp) 109size_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
71int thread__fork(struct thread *thread, struct thread *parent) 121int 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
27struct machine; 28struct machine;
29struct comm;
28 30
29struct thread *thread__new(pid_t pid, pid_t tid); 31struct thread *thread__new(pid_t pid, pid_t tid);
30void thread__delete(struct thread *self); 32void 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
36int thread__set_comm(struct thread *self, const char *comm); 38int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp);
37int thread__comm_len(struct thread *self); 39int thread__comm_len(struct thread *self);
40struct comm *thread__comm(const struct thread *thread);
41const char *thread__comm_str(const struct thread *thread);
38void thread__insert_map(struct thread *self, struct map *map); 42void thread__insert_map(struct thread *self, struct map *map);
39int thread__fork(struct thread *self, struct thread *parent); 43int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
40size_t thread__fprintf(struct thread *thread, FILE *fp); 44size_t thread__fprintf(struct thread *thread, FILE *fp);
41 45
42static inline struct map *thread__find_map(struct thread *self, 46static inline struct map *thread__find_map(struct thread *self,