Commit 87968f94 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

  * Add new COMM infrastructure, further improving histogram processing, from
    Frédéric Weisbecker, one fix from Namhyung Kim.

  * Enhance option parse error message, showing just the help lines of the
    options affected, from Namhyung Kim.

  * Fixup PERF_SAMPLE_TRANSACTION handling in sample synthesizing and
    'perf test', from Adrian Hunter.

  * Set up output options for in-stream attributes, from Adrian Hunter.

  * Fix 32-bit cross build, from Adrian Hunter.

  * Fix libunwind build and feature detection for 32-bit build, from Adrian Hunter.

  * Always use perf_evsel__set_sample_bit to set sample_type, from Adrian Hunter.
    perf evlist: Add a debug print if event buffer mmap fails

  * Add missing data.h into LIB_H headers, fix from Jiri Olsa.

  * libtraceevent updates from upstream trace-cmd repo, from Steven Rostedt.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 2a3ede8c 6d862b8c
...@@ -305,6 +305,11 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid) ...@@ -305,6 +305,11 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
return 0; return 0;
} }
void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock)
{
pevent->trace_clock = trace_clock;
}
struct func_map { struct func_map {
unsigned long long addr; unsigned long long addr;
char *func; char *func;
...@@ -599,10 +604,11 @@ find_printk(struct pevent *pevent, unsigned long long addr) ...@@ -599,10 +604,11 @@ find_printk(struct pevent *pevent, unsigned long long addr)
* This registers a string by the address it was stored in the kernel. * This registers a string by the address it was stored in the kernel.
* The @fmt passed in is duplicated. * The @fmt passed in is duplicated.
*/ */
int pevent_register_print_string(struct pevent *pevent, char *fmt, int pevent_register_print_string(struct pevent *pevent, const char *fmt,
unsigned long long addr) unsigned long long addr)
{ {
struct printk_list *item = malloc(sizeof(*item)); struct printk_list *item = malloc(sizeof(*item));
char *p;
if (!item) if (!item)
return -1; return -1;
...@@ -610,10 +616,21 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt, ...@@ -610,10 +616,21 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt,
item->next = pevent->printklist; item->next = pevent->printklist;
item->addr = addr; item->addr = addr;
/* Strip off quotes and '\n' from the end */
if (fmt[0] == '"')
fmt++;
item->printk = strdup(fmt); item->printk = strdup(fmt);
if (!item->printk) if (!item->printk)
goto out_free; goto out_free;
p = item->printk + strlen(item->printk) - 1;
if (*p == '"')
*p = 0;
p -= 2;
if (strcmp(p, "\\n") == 0)
*p = 0;
pevent->printklist = item; pevent->printklist = item;
pevent->printk_count++; pevent->printk_count++;
...@@ -3488,6 +3505,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, ...@@ -3488,6 +3505,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
struct pevent *pevent = event->pevent; struct pevent *pevent = event->pevent;
struct print_flag_sym *flag; struct print_flag_sym *flag;
struct format_field *field; struct format_field *field;
struct printk_map *printk;
unsigned long long val, fval; unsigned long long val, fval;
unsigned long addr; unsigned long addr;
char *str; char *str;
...@@ -3523,7 +3541,12 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, ...@@ -3523,7 +3541,12 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
if (!(field->flags & FIELD_IS_ARRAY) && if (!(field->flags & FIELD_IS_ARRAY) &&
field->size == pevent->long_size) { field->size == pevent->long_size) {
addr = *(unsigned long *)(data + field->offset); addr = *(unsigned long *)(data + field->offset);
trace_seq_printf(s, "%lx", addr); /* Check if it matches a print format */
printk = find_printk(pevent, addr);
if (printk)
trace_seq_puts(s, printk->printk);
else
trace_seq_printf(s, "%lx", addr);
break; break;
} }
str = malloc(len + 1); str = malloc(len + 1);
...@@ -3565,15 +3588,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, ...@@ -3565,15 +3588,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
} }
break; break;
case PRINT_HEX: case PRINT_HEX:
field = arg->hex.field->field.field; if (arg->hex.field->type == PRINT_DYNAMIC_ARRAY) {
if (!field) { unsigned long offset;
str = arg->hex.field->field.name; offset = pevent_read_number(pevent,
field = pevent_find_any_field(event, str); data + arg->hex.field->dynarray.field->offset,
if (!field) arg->hex.field->dynarray.field->size);
goto out_warning_field; hex = data + (offset & 0xffff);
arg->hex.field->field.field = field; } else {
field = arg->hex.field->field.field;
if (!field) {
str = arg->hex.field->field.name;
field = pevent_find_any_field(event, str);
if (!field)
goto out_warning_field;
arg->hex.field->field.field = field;
}
hex = data + field->offset;
} }
hex = data + field->offset;
len = eval_num_arg(data, size, event, arg->hex.size); len = eval_num_arg(data, size, event, arg->hex.size);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (i) if (i)
...@@ -3771,8 +3802,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc ...@@ -3771,8 +3802,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
if (asprintf(&arg->atom.atom, "%lld", ip) < 0) if (asprintf(&arg->atom.atom, "%lld", ip) < 0)
goto out_free; goto out_free;
/* skip the first "%pf : " */ /* skip the first "%pf: " */
for (ptr = fmt + 6, bptr = data + field->offset; for (ptr = fmt + 5, bptr = data + field->offset;
bptr < data + size && *ptr; ptr++) { bptr < data + size && *ptr; ptr++) {
int ls = 0; int ls = 0;
...@@ -3882,7 +3913,6 @@ get_bprint_format(void *data, int size __maybe_unused, ...@@ -3882,7 +3913,6 @@ get_bprint_format(void *data, int size __maybe_unused,
struct format_field *field; struct format_field *field;
struct printk_map *printk; struct printk_map *printk;
char *format; char *format;
char *p;
field = pevent->bprint_fmt_field; field = pevent->bprint_fmt_field;
...@@ -3899,25 +3929,13 @@ get_bprint_format(void *data, int size __maybe_unused, ...@@ -3899,25 +3929,13 @@ get_bprint_format(void *data, int size __maybe_unused,
printk = find_printk(pevent, addr); printk = find_printk(pevent, addr);
if (!printk) { if (!printk) {
if (asprintf(&format, "%%pf : (NO FORMAT FOUND at %llx)\n", addr) < 0) if (asprintf(&format, "%%pf: (NO FORMAT FOUND at %llx)\n", addr) < 0)
return NULL; return NULL;
return format; return format;
} }
p = printk->printk; if (asprintf(&format, "%s: %s", "%pf", printk->printk) < 0)
/* Remove any quotes. */
if (*p == '"')
p++;
if (asprintf(&format, "%s : %s", "%pf", p) < 0)
return NULL; return NULL;
/* remove ending quotes and new line since we will add one too */
p = format + strlen(format) - 1;
if (*p == '"')
*p = 0;
p -= 2;
if (strcmp(p, "\\n") == 0)
*p = 0;
return format; return format;
} }
...@@ -3963,7 +3981,7 @@ static int is_printable_array(char *p, unsigned int len) ...@@ -3963,7 +3981,7 @@ static int is_printable_array(char *p, unsigned int len)
unsigned int i; unsigned int i;
for (i = 0; i < len && p[i]; i++) for (i = 0; i < len && p[i]; i++)
if (!isprint(p[i])) if (!isprint(p[i]) && !isspace(p[i]))
return 0; return 0;
return 1; return 1;
} }
...@@ -4428,11 +4446,11 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event, ...@@ -4428,11 +4446,11 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
{ {
int print_pretty = 1; int print_pretty = 1;
if (event->pevent->print_raw) if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW))
print_event_fields(s, record->data, record->size, event); print_event_fields(s, record->data, record->size, event);
else { else {
if (event->handler) if (event->handler && !(event->flags & EVENT_FL_NOHANDLE))
print_pretty = event->handler(s, record, event, print_pretty = event->handler(s, record, event,
event->context); event->context);
...@@ -4443,8 +4461,21 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event, ...@@ -4443,8 +4461,21 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
trace_seq_terminate(s); trace_seq_terminate(s);
} }
static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock)
{
if (!use_trace_clock)
return true;
if (!strcmp(trace_clock, "local") || !strcmp(trace_clock, "global")
|| !strcmp(trace_clock, "uptime") || !strcmp(trace_clock, "perf"))
return true;
/* trace_clock is setting in tsc or counter mode */
return false;
}
void pevent_print_event(struct pevent *pevent, struct trace_seq *s, void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
struct pevent_record *record) struct pevent_record *record, bool use_trace_clock)
{ {
static const char *spaces = " "; /* 20 spaces */ static const char *spaces = " "; /* 20 spaces */
struct event_format *event; struct event_format *event;
...@@ -4457,9 +4488,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s, ...@@ -4457,9 +4488,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
int pid; int pid;
int len; int len;
int p; int p;
bool use_usec_format;
secs = record->ts / NSECS_PER_SEC; use_usec_format = is_timestamp_in_us(pevent->trace_clock,
nsecs = record->ts - secs * NSECS_PER_SEC; use_trace_clock);
if (use_usec_format) {
secs = record->ts / NSECS_PER_SEC;
nsecs = record->ts - secs * NSECS_PER_SEC;
}
if (record->size < 0) { if (record->size < 0) {
do_warning("ug! negative record size %d", record->size); 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,15 +4520,20 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
} else } else
trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu); trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
if (pevent->flags & PEVENT_NSEC_OUTPUT) { if (use_usec_format) {
usecs = nsecs; if (pevent->flags & PEVENT_NSEC_OUTPUT) {
p = 9; usecs = nsecs;
} else { p = 9;
usecs = (nsecs + 500) / NSECS_PER_USEC; } else {
p = 6; usecs = (nsecs + 500) / NSECS_PER_USEC;
} p = 6;
}
trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name); trace_seq_printf(s, " %5lu.%0*lu: %s: ",
secs, p, usecs, event->name);
} else
trace_seq_printf(s, " %12llu: %s: ",
record->ts, event->name);
/* Space out the event names evenly. */ /* Space out the event names evenly. */
len = strlen(event->name); len = strlen(event->name);
...@@ -5326,6 +5367,48 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, ...@@ -5326,6 +5367,48 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
return -1; return -1;
} }
/**
* pevent_print_func_field - print a field and a format for function pointers
* @s: The seq to print to
* @fmt: The printf format to print the field with.
* @event: the event that the field is for
* @name: The name of the field
* @record: The record with the field name.
* @err: print default error if failed.
*
* Returns: 0 on success, -1 field not found, or 1 if buffer is full.
*/
int pevent_print_func_field(struct trace_seq *s, const char *fmt,
struct event_format *event, const char *name,
struct pevent_record *record, int err)
{
struct format_field *field = pevent_find_field(event, name);
struct pevent *pevent = event->pevent;
unsigned long long val;
struct func_map *func;
char tmp[128];
if (!field)
goto failed;
if (pevent_read_number_field(field, record->data, &val))
goto failed;
func = find_func(pevent, val);
if (func)
snprintf(tmp, 128, "%s/0x%llx", func->func, func->addr - val);
else
sprintf(tmp, "0x%08llx", val);
return trace_seq_printf(s, fmt, tmp);
failed:
if (err)
trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
return -1;
}
static void free_func_handle(struct pevent_function_handler *func) static void free_func_handle(struct pevent_function_handler *func)
{ {
struct pevent_func_params *params; struct pevent_func_params *params;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#ifndef _PARSE_EVENTS_H #ifndef _PARSE_EVENTS_H
#define _PARSE_EVENTS_H #define _PARSE_EVENTS_H
#include <stdbool.h>
#include <stdarg.h> #include <stdarg.h>
#include <regex.h> #include <regex.h>
...@@ -307,6 +308,8 @@ enum { ...@@ -307,6 +308,8 @@ enum {
EVENT_FL_ISBPRINT = 0x04, EVENT_FL_ISBPRINT = 0x04,
EVENT_FL_ISFUNCENT = 0x10, EVENT_FL_ISFUNCENT = 0x10,
EVENT_FL_ISFUNCRET = 0x20, EVENT_FL_ISFUNCRET = 0x20,
EVENT_FL_NOHANDLE = 0x40,
EVENT_FL_PRINTRAW = 0x80,
EVENT_FL_FAILED = 0x80000000 EVENT_FL_FAILED = 0x80000000
}; };
...@@ -450,6 +453,8 @@ struct pevent { ...@@ -450,6 +453,8 @@ struct pevent {
/* cache */ /* cache */
struct event_format *last_event; struct event_format *last_event;
char *trace_clock;
}; };
static inline void pevent_set_flag(struct pevent *pevent, int flag) static inline void pevent_set_flag(struct pevent *pevent, int flag)
...@@ -527,14 +532,15 @@ enum trace_flag_type { ...@@ -527,14 +532,15 @@ enum trace_flag_type {
}; };
int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock);
int pevent_register_function(struct pevent *pevent, char *name, int pevent_register_function(struct pevent *pevent, char *name,
unsigned long long addr, char *mod); unsigned long long addr, char *mod);
int pevent_register_print_string(struct pevent *pevent, char *fmt, int pevent_register_print_string(struct pevent *pevent, const char *fmt,
unsigned long long addr); unsigned long long addr);
int pevent_pid_is_registered(struct pevent *pevent, int pid); int pevent_pid_is_registered(struct pevent *pevent, int pid);
void pevent_print_event(struct pevent *pevent, struct trace_seq *s, void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
struct pevent_record *record); struct pevent_record *record, bool use_trace_clock);
int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
int long_size); int long_size);
...@@ -563,6 +569,10 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, ...@@ -563,6 +569,10 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
struct event_format *event, const char *name, struct event_format *event, const char *name,
struct pevent_record *record, int err); struct pevent_record *record, int err);
int pevent_print_func_field(struct trace_seq *s, const char *fmt,
struct event_format *event, const char *name,
struct pevent_record *record, int err);
int pevent_register_event_handler(struct pevent *pevent, int id, int pevent_register_event_handler(struct pevent *pevent, int id,
const char *sys_name, const char *event_name, const char *sys_name, const char *event_name,
pevent_event_handler_func func, void *context); pevent_event_handler_func func, void *context);
......
...@@ -273,6 +273,7 @@ LIB_H += util/color.h ...@@ -273,6 +273,7 @@ LIB_H += util/color.h
LIB_H += util/values.h LIB_H += util/values.h
LIB_H += util/sort.h LIB_H += util/sort.h
LIB_H += util/hist.h LIB_H += util/hist.h
LIB_H += util/comm.h
LIB_H += util/thread.h LIB_H += util/thread.h
LIB_H += util/thread_map.h LIB_H += util/thread_map.h
LIB_H += util/trace-event.h LIB_H += util/trace-event.h
...@@ -295,6 +296,7 @@ LIB_H += ui/helpline.h ...@@ -295,6 +296,7 @@ LIB_H += ui/helpline.h
LIB_H += ui/progress.h LIB_H += ui/progress.h
LIB_H += ui/util.h LIB_H += ui/util.h
LIB_H += ui/ui.h LIB_H += ui/ui.h
LIB_H += util/data.h
LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o LIB_OBJS += $(OUTPUT)util/alias.o
...@@ -340,6 +342,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o ...@@ -340,6 +342,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o
LIB_OBJS += $(OUTPUT)util/map.o LIB_OBJS += $(OUTPUT)util/map.o
LIB_OBJS += $(OUTPUT)util/pstack.o LIB_OBJS += $(OUTPUT)util/pstack.o
LIB_OBJS += $(OUTPUT)util/session.o LIB_OBJS += $(OUTPUT)util/session.o
LIB_OBJS += $(OUTPUT)util/comm.o
LIB_OBJS += $(OUTPUT)util/thread.o LIB_OBJS += $(OUTPUT)util/thread.o
LIB_OBJS += $(OUTPUT)util/thread_map.o LIB_OBJS += $(OUTPUT)util/thread_map.o
LIB_OBJS += $(OUTPUT)util/trace-event-parse.o LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
...@@ -708,7 +711,7 @@ $(LIB_FILE): $(LIB_OBJS) ...@@ -708,7 +711,7 @@ $(LIB_FILE): $(LIB_OBJS)
TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
$(LIBTRACEEVENT): $(TE_SOURCES) $(LIBTRACEEVENT): $(TE_SOURCES)
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libtraceevent.a $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a
$(LIBTRACEEVENT)-clean: $(LIBTRACEEVENT)-clean:
$(call QUIET_CLEAN, libtraceevent) $(call QUIET_CLEAN, libtraceevent)
......
...@@ -315,7 +315,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -315,7 +315,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
return -1; return -1;
} }
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
if (evsel->handler.func != NULL) { if (evsel->handler.func != NULL) {
tracepoint_handler f = evsel->handler.func; tracepoint_handler f = evsel->handler.func;
......
...@@ -767,7 +767,7 @@ static void dump_threads(void) ...@@ -767,7 +767,7 @@ static void dump_threads(void)
while (node) { while (node) {
st = container_of(node, struct thread_stat, rb); st = container_of(node, struct thread_stat, rb);
t = perf_session__findnew(session, st->tid); t = perf_session__findnew(session, st->tid);
pr_info("%10d: %s\n", st->tid, t->comm); pr_info("%10d: %s\n", st->tid, thread__comm_str(t));
node = rb_next(node); node = rb_next(node);
}; };
} }
......
...@@ -905,13 +905,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -905,13 +905,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
input_name = "perf.data"; input_name = "perf.data";
} }
if (strcmp(input_name, "-") != 0)
setup_browser(true);
else {
use_browser = 0;
perf_hpp__init();
}
file.path = input_name; file.path = input_name;
file.force = report.force; file.force = report.force;
...@@ -954,8 +947,22 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -954,8 +947,22 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
} }
if (setup_sorting() < 0) if (setup_sorting() < 0) {
usage_with_options(report_usage, options); parse_options_usage(report_usage, options, "s", 1);
goto error;
}
if (parent_pattern != default_parent_pattern) {
if (sort_dimension__add("parent") < 0)
goto error;
}
if (strcmp(input_name, "-") != 0)
setup_browser(true);
else {
use_browser = 0;
perf_hpp__init();
}
/* /*
* Only in the TUI browser we are doing integrated annotation, * Only in the TUI browser we are doing integrated annotation,
...@@ -986,11 +993,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -986,11 +993,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
if (symbol__init() < 0) if (symbol__init() < 0)
goto error; goto error;
if (parent_pattern != default_parent_pattern) {
if (sort_dimension__add("parent") < 0)
goto error;
}
if (argc) { if (argc) {
/* /*
* Special case: if there's an argument left then assume that * Special case: if there's an argument left then assume that
......
...@@ -737,12 +737,12 @@ static int replay_fork_event(struct perf_sched *sched, ...@@ -737,12 +737,12 @@ static int replay_fork_event(struct perf_sched *sched,
if (verbose) { if (verbose) {
printf("fork event\n"); printf("fork event\n");
printf("... parent: %s/%d\n", parent->comm, parent->tid); printf("... parent: %s/%d\n", thread__comm_str(parent), parent->tid);
printf("... child: %s/%d\n", child->comm, child->tid); printf("... child: %s/%d\n", thread__comm_str(child), child->tid);
} }
register_pid(sched, parent->tid, parent->comm); register_pid(sched, parent->tid, thread__comm_str(parent));
register_pid(sched, child->tid, child->comm); register_pid(sched, child->tid, thread__comm_str(child));
return 0; return 0;
} }
...@@ -1077,7 +1077,7 @@ static int latency_migrate_task_event(struct perf_sched *sched, ...@@ -1077,7 +1077,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
if (!atoms) { if (!atoms) {
if (thread_atoms_insert(sched, migrant)) if (thread_atoms_insert(sched, migrant))
return -1; return -1;
register_pid(sched, migrant->tid, migrant->comm); register_pid(sched, migrant->tid, thread__comm_str(migrant));
atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
if (!atoms) { if (!atoms) {
pr_err("migration-event: Internal tree error"); 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,13 +1111,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
/* /*
* Ignore idle threads: * Ignore idle threads:
*/ */
if (!strcmp(work_list->thread->comm, "swapper")) if (!strcmp(thread__comm_str(work_list->thread), "swapper"))
return; return;
sched->all_runtime += work_list->total_runtime; sched->all_runtime += work_list->total_runtime;
sched->all_count += work_list->nb_atoms; sched->all_count += work_list->nb_atoms;
ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid); ret = printf(" %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid);
for (i = 0; i < 24 - ret; i++) for (i = 0; i < 24 - ret; i++)
printf(" "); printf(" ");
...@@ -1334,7 +1334,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, ...@@ -1334,7 +1334,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
printf(" %12.6f secs ", (double)timestamp/1e9); printf(" %12.6f secs ", (double)timestamp/1e9);
if (new_shortname) { if (new_shortname) {
printf("%s => %s:%d\n", printf("%s => %s:%d\n",
sched_in->shortname, sched_in->comm, sched_in->tid); sched_in->shortname, thread__comm_str(sched_in), sched_in->tid);
} else { } else {
printf("\n"); printf("\n");
} }
......
...@@ -229,6 +229,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, ...@@ -229,6 +229,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
return 0; return 0;
} }
static void set_print_ip_opts(struct perf_event_attr *attr)
{
unsigned int type = attr->type;
output[type].print_ip_opts = 0;
if (PRINT_FIELD(IP))
output[type].print_ip_opts |= PRINT_IP_OPT_IP;
if (PRINT_FIELD(SYM))
output[type].print_ip_opts |= PRINT_IP_OPT_SYM;
if (PRINT_FIELD(DSO))
output[type].print_ip_opts |= PRINT_IP_OPT_DSO;
if (PRINT_FIELD(SYMOFFSET))
output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
}
/* /*
* verify all user requested events exist and the samples * verify all user requested events exist and the samples
* have the expected data * have the expected data
...@@ -237,7 +255,6 @@ static int perf_session__check_output_opt(struct perf_session *session) ...@@ -237,7 +255,6 @@ static int perf_session__check_output_opt(struct perf_session *session)
{ {
int j; int j;
struct perf_evsel *evsel; struct perf_evsel *evsel;
struct perf_event_attr *attr;
for (j = 0; j < PERF_TYPE_MAX; ++j) { for (j = 0; j < PERF_TYPE_MAX; ++j) {
evsel = perf_session__find_first_evtype(session, j); evsel = perf_session__find_first_evtype(session, j);
...@@ -260,20 +277,7 @@ static int perf_session__check_output_opt(struct perf_session *session) ...@@ -260,20 +277,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
if (evsel == NULL) if (evsel == NULL)
continue; continue;
attr = &evsel->attr; set_print_ip_opts(&evsel->attr);
output[j].print_ip_opts = 0;
if (PRINT_FIELD(IP))
output[j].print_ip_opts |= PRINT_IP_OPT_IP;
if (PRINT_FIELD(SYM))
output[j].print_ip_opts |= PRINT_IP_OPT_SYM;
if (PRINT_FIELD(DSO))
output[j].print_ip_opts |= PRINT_IP_OPT_DSO;
if (PRINT_FIELD(SYMOFFSET))
output[j].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
} }
return 0; return 0;
...@@ -291,11 +295,11 @@ static void print_sample_start(struct perf_sample *sample, ...@@ -291,11 +295,11 @@ static void print_sample_start(struct perf_sample *sample,
if (PRINT_FIELD(COMM)) { if (PRINT_FIELD(COMM)) {
if (latency_format) if (latency_format)
printf("%8.8s ", thread->comm); printf("%8.8s ", thread__comm_str(thread));
else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
printf("%s ", thread->comm); printf("%s ", thread__comm_str(thread));
else else
printf("%16s ", thread->comm); printf("%16s ", thread__comm_str(thread));
} }
if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
...@@ -547,6 +551,34 @@ struct perf_script { ...@@ -547,6 +551,34 @@ struct perf_script {
struct perf_session *session; struct perf_session *session;
}; };
static int process_attr(struct perf_tool *tool, union perf_event *event,
struct perf_evlist **pevlist)
{
struct perf_script *scr = container_of(tool, struct perf_script, tool);
struct perf_evlist *evlist;
struct perf_evsel *evsel, *pos;
int err;
err = perf_event__process_attr(tool, event, pevlist);
if (err)
return err;
evlist = *pevlist;
evsel = perf_evlist__last(*pevlist);
if (evsel->attr.type >= PERF_TYPE_MAX)
return 0;
list_for_each_entry(pos, &evlist->entries, node) {
if (pos->attr.type == evsel->attr.type && pos != evsel)
return 0;
}
set_print_ip_opts(&evsel->attr);
return perf_evsel__check_attr(evsel, scr->session);
}
static void sig_handler(int sig __maybe_unused) static void sig_handler(int sig __maybe_unused)
{ {
session_done = 1; session_done = 1;
...@@ -1272,7 +1304,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1272,7 +1304,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.attr = perf_event__process_attr, .attr = process_attr,
.tracing_data = perf_event__process_tracing_data, .tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id, .build_id = perf_event__process_build_id,
.ordered_samples = true, .ordered_samples = true,
......
...@@ -1596,7 +1596,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1596,7 +1596,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"perf stat [<options>] [<command>]", "perf stat [<options>] [<command>]",
NULL NULL
}; };
int status = -ENOMEM, run_idx; int status = -EINVAL, run_idx;
const char *mode; const char *mode;
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
...@@ -1614,12 +1614,15 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1614,12 +1614,15 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (output_name && output_fd) { if (output_name && output_fd) {
fprintf(stderr, "cannot use both --output and --log-fd\n"); fprintf(stderr, "cannot use both --output and --log-fd\n");
usage_with_options(stat_usage, options); parse_options_usage(stat_usage, options, "o", 1);
parse_options_usage(NULL, options, "log-fd", 0);
goto out;
} }
if (output_fd < 0) { if (output_fd < 0) {
fprintf(stderr, "argument to --log-fd must be a > 0\n"); fprintf(stderr, "argument to --log-fd must be a > 0\n");
usage_with_options(stat_usage, options); parse_options_usage(stat_usage, options, "log-fd", 0);
goto out;
} }
if (!output) { if (!output) {
...@@ -1656,7 +1659,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1656,7 +1659,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
/* User explicitly passed -B? */ /* User explicitly passed -B? */
if (big_num_opt == 1) { if (big_num_opt == 1) {
fprintf(stderr, "-B option not supported with -x\n"); fprintf(stderr, "-B option not supported with -x\n");
usage_with_options(stat_usage, options); parse_options_usage(stat_usage, options, "B", 1);
parse_options_usage(NULL, options, "x", 1);
goto out;
} else /* Nope, so disable big number formatting */ } else /* Nope, so disable big number formatting */
big_num = false; big_num = false;
} else if (big_num_opt == 0) /* User passed --no-big-num */ } 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,7 +1671,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
usage_with_options(stat_usage, options); usage_with_options(stat_usage, options);
if (run_count < 0) { if (run_count < 0) {
usage_with_options(stat_usage, options); pr_err("Run count must be a positive number\n");
parse_options_usage(stat_usage, options, "r", 1);
goto out;
} else if (run_count == 0) { } else if (run_count == 0) {
forever = true; forever = true;
run_count = 1; run_count = 1;
...@@ -1678,8 +1685,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1678,8 +1685,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
fprintf(stderr, "both cgroup and no-aggregation " fprintf(stderr, "both cgroup and no-aggregation "
"modes only available in system-wide mode\n"); "modes only available in system-wide mode\n");
usage_with_options(stat_usage, options); parse_options_usage(stat_usage, options, "G", 1);
return -1; parse_options_usage(NULL, options, "A", 1);
parse_options_usage(NULL, options, "a", 1);
goto out;
} }
if (add_default_attributes()) if (add_default_attributes())
...@@ -1688,25 +1697,28 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1688,25 +1697,28 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
perf_target__validate(&target); perf_target__validate(&target);
if (perf_evlist__create_maps(evsel_list, &target) < 0) { if (perf_evlist__create_maps(evsel_list, &target) < 0) {
if (perf_target__has_task(&target)) if (perf_target__has_task(&target)) {
pr_err("Problems finding threads of monitor\n"); pr_err("Problems finding threads of monitor\n");
if (perf_target__has_cpu(&target)) parse_options_usage(stat_usage, options, "p", 1);
parse_options_usage(NULL, options, "t", 1);
} else if (perf_target__has_cpu(&target)) {
perror("failed to parse CPUs map"); perror("failed to parse CPUs map");
parse_options_usage(stat_usage, options, "C", 1);
usage_with_options(stat_usage, options); parse_options_usage(NULL, options, "a", 1);
return -1; }
goto out;
} }
if (interval && interval < 100) { if (interval && interval < 100) {
pr_err("print interval must be >= 100ms\n"); pr_err("print interval must be >= 100ms\n");
usage_with_options(stat_usage, options); parse_options_usage(stat_usage, options, "I", 1);
return -1; goto out_free_maps;
} }
if (perf_evlist__alloc_stats(evsel_list, interval)) if (perf_evlist__alloc_stats(evsel_list, interval))
goto out_free_maps; goto out_free_maps;
if (perf_stat_init_aggr_mode()) if (perf_stat_init_aggr_mode())
goto out; goto out_free_maps;
/* /*
* We dont want to block the signals - that would cause * We dont want to block the signals - that would cause
......
...@@ -856,7 +856,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) ...@@ -856,7 +856,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
&sample, machine); &sample, machine);
} else if (event->header.type < PERF_RECORD_MAX) { } else if (event->header.type < PERF_RECORD_MAX) {
hists__inc_nr_events(&evsel->hists, event->header.type); hists__inc_nr_events(&evsel->hists, event->header.type);
machine__process_event(machine, event); machine__process_event(machine, event, &sample);
} else } else
++session->stats.nr_unknown_events; ++session->stats.nr_unknown_events;
next_event: next_event:
...@@ -1040,7 +1040,7 @@ parse_percent_limit(const struct option *opt, const char *arg, ...@@ -1040,7 +1040,7 @@ parse_percent_limit(const struct option *opt, const char *arg,
int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
int status; int status = -1;
char errbuf[BUFSIZ]; char errbuf[BUFSIZ];
struct perf_top top = { struct perf_top top = {
.count_filter = 5, .count_filter = 5,
...@@ -1159,8 +1159,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1159,8 +1159,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (sort_order == default_sort_order) if (sort_order == default_sort_order)
sort_order = "dso,symbol"; sort_order = "dso,symbol";
if (setup_sorting() < 0) if (setup_sorting() < 0) {
usage_with_options(top_usage, options); parse_options_usage(top_usage, options, "s", 1);
goto out_delete_evlist;
}
/* display thread wants entries to be collapsed in a different tree */ /* display thread wants entries to be collapsed in a different tree */
sort__need_collapse = 1; sort__need_collapse = 1;
......
...@@ -1114,7 +1114,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre ...@@ -1114,7 +1114,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
if (trace->multiple_threads) { if (trace->multiple_threads) {
if (trace->show_comm) if (trace->show_comm)
printed += fprintf(fp, "%.14s/", thread->comm); printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
printed += fprintf(fp, "%d ", thread->tid); printed += fprintf(fp, "%d ", thread->tid);
} }
...@@ -1122,7 +1122,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre ...@@ -1122,7 +1122,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
} }
static int trace__process_event(struct trace *trace, struct machine *machine, static int trace__process_event(struct trace *trace, struct machine *machine,
union perf_event *event) union perf_event *event, struct perf_sample *sample)
{ {
int ret = 0; int ret = 0;
...@@ -1130,9 +1130,9 @@ static int trace__process_event(struct trace *trace, struct machine *machine, ...@@ -1130,9 +1130,9 @@ static int trace__process_event(struct trace *trace, struct machine *machine,
case PERF_RECORD_LOST: case PERF_RECORD_LOST:
color_fprintf(trace->output, PERF_COLOR_RED, color_fprintf(trace->output, PERF_COLOR_RED,
"LOST %" PRIu64 " events!\n", event->lost.lost); "LOST %" PRIu64 " events!\n", event->lost.lost);
ret = machine__process_lost_event(machine, event); ret = machine__process_lost_event(machine, event, sample);
default: default:
ret = machine__process_event(machine, event); ret = machine__process_event(machine, event, sample);
break; break;
} }
...@@ -1141,11 +1141,11 @@ static int trace__process_event(struct trace *trace, struct machine *machine, ...@@ -1141,11 +1141,11 @@ static int trace__process_event(struct trace *trace, struct machine *machine,
static int trace__tool_process(struct perf_tool *tool, static int trace__tool_process(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample __maybe_unused, struct perf_sample *sample,
struct machine *machine) struct machine *machine)
{ {
struct trace *trace = container_of(tool, struct trace, tool); struct trace *trace = container_of(tool, struct trace, tool);
return trace__process_event(trace, machine, event); return trace__process_event(trace, machine, event, sample);
} }
static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
...@@ -1751,7 +1751,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) ...@@ -1751,7 +1751,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
trace->base_time = sample.time; trace->base_time = sample.time;
if (type != PERF_RECORD_SAMPLE) { if (type != PERF_RECORD_SAMPLE) {
trace__process_event(trace, trace->host, event); trace__process_event(trace, trace->host, event, &sample);
continue; continue;
} }
...@@ -1986,7 +1986,7 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) ...@@ -1986,7 +1986,7 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
else if (ratio > 5.0) else if (ratio > 5.0)
color = PERF_COLOR_YELLOW; color = PERF_COLOR_YELLOW;
printed += color_fprintf(fp, color, "%20s", thread->comm); printed += color_fprintf(fp, color, "%20s", thread__comm_str(thread));
printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
printed += color_fprintf(fp, color, "%5.1f%%", ratio); printed += color_fprintf(fp, color, "%5.1f%%", ratio);
printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
......
...@@ -25,9 +25,11 @@ ifeq ($(ARCH),x86_64) ...@@ -25,9 +25,11 @@ ifeq ($(ARCH),x86_64)
RAW_ARCH := x86_64 RAW_ARCH := x86_64
CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
else
LIBUNWIND_LIBS = -lunwind -lunwind-x86
endif endif
NO_PERF_REGS := 0 NO_PERF_REGS := 0
LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
endif endif
ifeq ($(NO_PERF_REGS),0) ifeq ($(NO_PERF_REGS),0)
...@@ -96,7 +98,7 @@ endif ...@@ -96,7 +98,7 @@ endif
feature_check = $(eval $(feature_check_code)) feature_check = $(eval $(feature_check_code))
define feature_check_code define feature_check_code
feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) LDFLAGS=$(LDFLAGS) -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0) 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)
endef endef
feature_set = $(eval $(feature_set_code)) feature_set = $(eval $(feature_set_code))
...@@ -173,7 +175,7 @@ ifeq ($(feature-all), 1) ...@@ -173,7 +175,7 @@ ifeq ($(feature-all), 1)
# #
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat)))
else else
$(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1) $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1)
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
endif endif
......
...@@ -31,12 +31,12 @@ CC := $(CC) -MD ...@@ -31,12 +31,12 @@ CC := $(CC) -MD
all: $(FILES) all: $(FILES)
BUILD = $(CC) $(LDFLAGS) -o $(OUTPUT)$@ $@.c BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
############################### ###############################
test-all: test-all:
$(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 $(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
test-hello: test-hello:
$(BUILD) $(BUILD)
...@@ -72,7 +72,7 @@ test-libnuma: ...@@ -72,7 +72,7 @@ test-libnuma:
$(BUILD) -lnuma $(BUILD) -lnuma
test-libunwind: test-libunwind:
$(BUILD) -lunwind -lunwind-x86_64 -lelf $(BUILD) $(LIBUNWIND_LIBS) -lelf
test-libaudit: test-libaudit:
$(BUILD) -laudit $(BUILD) -laudit
......
...@@ -276,7 +276,7 @@ static int process_event(struct machine *machine, struct perf_evlist *evlist, ...@@ -276,7 +276,7 @@ static int process_event(struct machine *machine, struct perf_evlist *evlist,
return process_sample_event(machine, evlist, event, state); return process_sample_event(machine, evlist, event, state);
if (event->header.type < PERF_RECORD_MAX) if (event->header.type < PERF_RECORD_MAX)
return machine__process_event(machine, event); return machine__process_event(machine, event, NULL);
return 0; return 0;
} }
......
...@@ -93,7 +93,7 @@ static struct machine *setup_fake_machine(struct machines *machines) ...@@ -93,7 +93,7 @@ static struct machine *setup_fake_machine(struct machines *machines)
if (thread == NULL) if (thread == NULL)
goto out; goto out;
thread__set_comm(thread, fake_threads[i].comm); thread__set_comm(thread, fake_threads[i].comm, 0);
} }
for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) { for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
...@@ -110,7 +110,7 @@ static struct machine *setup_fake_machine(struct machines *machines) ...@@ -110,7 +110,7 @@ static struct machine *setup_fake_machine(struct machines *machines)
strcpy(fake_mmap_event.mmap.filename, strcpy(fake_mmap_event.mmap.filename,
fake_mmap_info[i].filename); fake_mmap_info[i].filename);
machine__process_mmap_event(machine, &fake_mmap_event); machine__process_mmap_event(machine, &fake_mmap_event, NULL);
} }
for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) { for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
...@@ -421,7 +421,7 @@ static void print_hists(struct hists *hists) ...@@ -421,7 +421,7 @@ static void print_hists(struct hists *hists)
he = rb_entry(node, struct hist_entry, rb_node_in); he = rb_entry(node, struct hist_entry, rb_node_in);
pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
i, he->thread->comm, he->ms.map->dso->short_name, i, thread__comm_str(he->thread), he->ms.map->dso->short_name,
he->ms.sym->name, he->stat.period); he->ms.sym->name, he->stat.period);
i++; i++;
......
...@@ -121,6 +121,9 @@ static bool samples_same(const struct perf_sample *s1, ...@@ -121,6 +121,9 @@ static bool samples_same(const struct perf_sample *s1,
if (type & PERF_SAMPLE_DATA_SRC) if (type & PERF_SAMPLE_DATA_SRC)
COMP(data_src); COMP(data_src);
if (type & PERF_SAMPLE_TRANSACTION)
COMP(transaction);
return true; return true;
} }
...@@ -165,6 +168,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format) ...@@ -165,6 +168,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
.cpu = 110, .cpu = 110,
.raw_size = sizeof(raw_data), .raw_size = sizeof(raw_data),
.data_src = 111, .data_src = 111,
.transaction = 112,
.raw_data = (void *)raw_data, .raw_data = (void *)raw_data,
.callchain = &callchain.callchain, .callchain = &callchain.callchain,
.branch_stack = &branch_stack.branch_stack, .branch_stack = &branch_stack.branch_stack,
...@@ -273,7 +277,8 @@ int test__sample_parsing(void) ...@@ -273,7 +277,8 @@ int test__sample_parsing(void)
/* /*
* Fail the test if it has not been updated when new sample format bits * Fail the test if it has not been updated when new sample format bits
* were added. * were added. Please actually update the test rather than just change
* the condition below.
*/ */
if (PERF_SAMPLE_MAX > PERF_SAMPLE_TRANSACTION << 1) { if (PERF_SAMPLE_MAX > PERF_SAMPLE_TRANSACTION << 1) {
pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n"); pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n");
......
...@@ -1255,7 +1255,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, ...@@ -1255,7 +1255,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
if (thread) if (thread)
printed += scnprintf(bf + printed, size - printed, printed += scnprintf(bf + printed, size - printed,
", Thread: %s(%d)", ", Thread: %s(%d)",
(thread->comm_set ? thread->comm : ""), (thread->comm_set ? thread__comm_str(thread) : ""),
thread->tid); thread->tid);
if (dso) if (dso)
printed += scnprintf(bf + printed, size - printed, printed += scnprintf(bf + printed, size - printed,
...@@ -1578,7 +1578,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1578,7 +1578,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (thread != NULL && if (thread != NULL &&
asprintf(&options[nr_options], "Zoom %s %s(%d) thread", asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
(browser->hists->thread_filter ? "out of" : "into"), (browser->hists->thread_filter ? "out of" : "into"),
(thread->comm_set ? thread->comm : ""), (thread->comm_set ? thread__comm_str(thread) : ""),
thread->tid) > 0) thread->tid) > 0)
zoom_thread = nr_options++; zoom_thread = nr_options++;
...@@ -1598,7 +1598,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1598,7 +1598,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
struct symbol *sym; struct symbol *sym;
if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
browser->he_selection->thread->comm) > 0) thread__comm_str(browser->he_selection->thread)) > 0)
scripts_comm = nr_options++; scripts_comm = nr_options++;
sym = browser->he_selection->ms.sym; sym = browser->he_selection->ms.sym;
...@@ -1701,7 +1701,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1701,7 +1701,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
sort_thread.elide = false; sort_thread.elide = false;
} else { } else {
ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
thread->comm_set ? thread->comm : "", thread->comm_set ? thread__comm_str(thread) : "",
thread->tid); thread->tid);
browser->hists->thread_filter = thread; browser->hists->thread_filter = thread;
sort_thread.elide = true; sort_thread.elide = true;
...@@ -1717,7 +1717,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1717,7 +1717,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
memset(script_opt, 0, 64); memset(script_opt, 0, 64);
if (choice == scripts_comm) if (choice == scripts_comm)
sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm); sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread));
if (choice == scripts_symbol) if (choice == scripts_symbol)
sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
......
#include "comm.h"
#include "util.h"
#include <stdlib.h>
#include <stdio.h>
struct comm_str {
char *str;
struct rb_node rb_node;
int ref;
};
/* Should perhaps be moved to struct machine */
static struct rb_root comm_str_root;
static void comm_str__get(struct comm_str *cs)
{
cs->ref++;
}
static void comm_str__put(struct comm_str *cs)
{
if (!--cs->ref) {
rb_erase(&cs->rb_node, &comm_str_root);
free(cs->str);
free(cs);
}
}
static struct comm_str *comm_str__alloc(const char *str)
{
struct comm_str *cs;
cs = zalloc(sizeof(*cs));
if (!cs)
return NULL;
cs->str = strdup(str);
if (!cs->str) {
free(cs);
return NULL;
}
return cs;
}
static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
{
struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL;
struct comm_str *iter, *new;
int cmp;
while (*p != NULL) {
parent = *p;
iter = rb_entry(parent, struct comm_str, rb_node);
cmp = strcmp(str, iter->str);
if (!cmp)
return iter;
if (cmp < 0)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
new = comm_str__alloc(str);
if (!new)
return NULL;
rb_link_node(&new->rb_node, parent, p);
rb_insert_color(&new->rb_node, root);
return new;
}
struct comm *comm__new(const char *str, u64 timestamp)
{
struct comm *comm = zalloc(sizeof(*comm));
if (!comm)
return NULL;
comm->start = timestamp;
comm->comm_str = comm_str__findnew(str, &comm_str_root);
if (!comm->comm_str) {
free(comm);
return NULL;
}
comm_str__get(comm->comm_str);
return comm;
}
void comm__override(struct comm *comm, const char *str, u64 timestamp)
{
struct comm_str *old = comm->comm_str;
comm->comm_str = comm_str__findnew(str, &comm_str_root);
if (!comm->comm_str) {
comm->comm_str = old;
return;
}
comm->start = timestamp;
comm_str__get(comm->comm_str);
comm_str__put(old);
}
void comm__free(struct comm *comm)
{
comm_str__put(comm->comm_str);
free(comm);
}
const char *comm__str(const struct comm *comm)
{
return comm->comm_str->str;
}
#ifndef __PERF_COMM_H
#define __PERF_COMM_H
#include "../perf.h"
#include <linux/rbtree.h>
#include <linux/list.h>
struct comm_str;
struct comm {
struct comm_str *comm_str;
u64 start;
struct list_head list;
};
void comm__free(struct comm *comm);
struct comm *comm__new(const char *str, u64 timestamp);
const char *comm__str(const struct comm *comm);
void comm__override(struct comm *comm, const char *str, u64 timestamp);
#endif /* __PERF_COMM_H */
...@@ -512,18 +512,18 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) ...@@ -512,18 +512,18 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
int perf_event__process_comm(struct perf_tool *tool __maybe_unused, int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample __maybe_unused, struct perf_sample *sample,
struct machine *machine) struct machine *machine)
{ {
return machine__process_comm_event(machine, event); return machine__process_comm_event(machine, event, sample);
} }
int perf_event__process_lost(struct perf_tool *tool __maybe_unused, int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample __maybe_unused, struct perf_sample *sample,
struct machine *machine) struct machine *machine)
{ {
return machine__process_lost_event(machine, event); return machine__process_lost_event(machine, event, sample);
} }
size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
...@@ -546,18 +546,18 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) ...@@ -546,18 +546,18 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample __maybe_unused, struct perf_sample *sample,
struct machine *machine) struct machine *machine)
{ {
return machine__process_mmap_event(machine, event); return machine__process_mmap_event(machine, event, sample);
} }
int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample __maybe_unused, struct perf_sample *sample,
struct machine *machine) struct machine *machine)
{ {
return machine__process_mmap2_event(machine, event); return machine__process_mmap2_event(machine, event, sample);
} }
size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
...@@ -569,18 +569,18 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) ...@@ -569,18 +569,18 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
int perf_event__process_fork(struct perf_tool *tool __maybe_unused, int perf_event__process_fork(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample __maybe_unused, struct perf_sample *sample,
struct machine *machine) struct machine *machine)
{ {
return machine__process_fork_event(machine, event); return machine__process_fork_event(machine, event, sample);
} }
int perf_event__process_exit(struct perf_tool *tool __maybe_unused, int perf_event__process_exit(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample __maybe_unused, struct perf_sample *sample,
struct machine *machine) struct machine *machine)
{ {
return machine__process_exit_event(machine, event); return machine__process_exit_event(machine, event, sample);
} }
size_t perf_event__fprintf(union perf_event *event, FILE *fp) size_t perf_event__fprintf(union perf_event *event, FILE *fp)
...@@ -611,10 +611,10 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) ...@@ -611,10 +611,10 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
int perf_event__process(struct perf_tool *tool __maybe_unused, int perf_event__process(struct perf_tool *tool __maybe_unused,
union perf_event *event, union perf_event *event,
struct perf_sample *sample __maybe_unused, struct perf_sample *sample,
struct machine *machine) struct machine *machine)
{ {
return machine__process_event(machine, event); return machine__process_event(machine, event, sample);
} }
void thread__find_addr_map(struct thread *self, void thread__find_addr_map(struct thread *self,
...@@ -721,10 +721,10 @@ int perf_event__preprocess_sample(const union perf_event *event, ...@@ -721,10 +721,10 @@ int perf_event__preprocess_sample(const union perf_event *event,
return -1; return -1;
if (symbol_conf.comm_list && if (symbol_conf.comm_list &&
!strlist__has_entry(symbol_conf.comm_list, thread->comm)) !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread)))
goto out_filtered; goto out_filtered;
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
/* /*
* Have we already created the kernel maps for this machine? * Have we already created the kernel maps for this machine?
* *
......
...@@ -607,6 +607,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, ...@@ -607,6 +607,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
MAP_SHARED, fd, 0); MAP_SHARED, fd, 0);
if (evlist->mmap[idx].base == MAP_FAILED) { if (evlist->mmap[idx].base == MAP_FAILED) {
pr_debug2("failed to mmap perf event ring buffer, error %d\n",
errno);
evlist->mmap[idx].base = NULL; evlist->mmap[idx].base = NULL;
return -1; return -1;
} }
......
...@@ -663,7 +663,7 @@ void perf_evsel__config(struct perf_evsel *evsel, ...@@ -663,7 +663,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
} }
if (opts->sample_address) if (opts->sample_address)
attr->sample_type |= PERF_SAMPLE_DATA_SRC; perf_evsel__set_sample_bit(evsel, DATA_SRC);
if (opts->no_delay) { if (opts->no_delay) {
attr->watermark = 0; attr->watermark = 0;
...@@ -675,13 +675,13 @@ void perf_evsel__config(struct perf_evsel *evsel, ...@@ -675,13 +675,13 @@ void perf_evsel__config(struct perf_evsel *evsel,
} }
if (opts->sample_weight) if (opts->sample_weight)
attr->sample_type |= PERF_SAMPLE_WEIGHT; perf_evsel__set_sample_bit(evsel, WEIGHT);
attr->mmap = track; attr->mmap = track;
attr->comm = track; attr->comm = track;
if (opts->sample_transaction) if (opts->sample_transaction)
attr->sample_type |= PERF_SAMPLE_TRANSACTION; perf_evsel__set_sample_bit(evsel, TRANSACTION);
/* /*
* XXX see the function comment above * XXX see the function comment above
...@@ -1051,6 +1051,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, ...@@ -1051,6 +1051,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
group_fd, flags); group_fd, flags);
if (FD(evsel, cpu, thread) < 0) { if (FD(evsel, cpu, thread) < 0) {
err = -errno; err = -errno;
pr_debug2("perf_event_open failed, error %d\n",
err);
goto try_fallback; goto try_fallback;
} }
set_rlimit = NO_CHANGE; set_rlimit = NO_CHANGE;
...@@ -1479,6 +1481,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, ...@@ -1479,6 +1481,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
data->transaction = 0; data->transaction = 0;
if (type & PERF_SAMPLE_TRANSACTION) { if (type & PERF_SAMPLE_TRANSACTION) {
OVERFLOW_CHECK_u64(array);
data->transaction = *array; data->transaction = *array;
array++; array++;
} }
...@@ -1575,6 +1578,9 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, ...@@ -1575,6 +1578,9 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_DATA_SRC) if (type & PERF_SAMPLE_DATA_SRC)
result += sizeof(u64); result += sizeof(u64);
if (type & PERF_SAMPLE_TRANSACTION)
result += sizeof(u64);
return result; return result;
} }
...@@ -1748,6 +1754,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, ...@@ -1748,6 +1754,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
array++; array++;
} }
if (type & PERF_SAMPLE_TRANSACTION) {
*array = sample->transaction;
array++;
}
return 0; return 0;
} }
......
...@@ -416,6 +416,7 @@ struct hist_entry *__hists__add_mem_entry(struct hists *hists, ...@@ -416,6 +416,7 @@ struct hist_entry *__hists__add_mem_entry(struct hists *hists,
{ {
struct hist_entry entry = { struct hist_entry entry = {
.thread = al->thread, .thread = al->thread,
.comm = thread__comm(al->thread),
.ms = { .ms = {
.map = al->map, .map = al->map,
.sym = al->sym, .sym = al->sym,
...@@ -446,6 +447,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *hists, ...@@ -446,6 +447,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *hists,
{ {
struct hist_entry entry = { struct hist_entry entry = {
.thread = al->thread, .thread = al->thread,
.comm = thread__comm(al->thread),
.ms = { .ms = {
.map = bi->to.map, .map = bi->to.map,
.sym = bi->to.sym, .sym = bi->to.sym,
...@@ -475,6 +477,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, ...@@ -475,6 +477,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
{ {
struct hist_entry entry = { struct hist_entry entry = {
.thread = al->thread, .thread = al->thread,
.comm = thread__comm(al->thread),
.ms = { .ms = {
.map = al->map, .map = al->map,
.sym = al->sym, .sym = al->sym,
......
...@@ -40,7 +40,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) ...@@ -40,7 +40,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
return -ENOMEM; return -ENOMEM;
snprintf(comm, sizeof(comm), "[guest/%d]", pid); snprintf(comm, sizeof(comm), "[guest/%d]", pid);
thread__set_comm(thread, comm); thread__set_comm(thread, comm, 0);
} }
return 0; return 0;
...@@ -331,7 +331,8 @@ struct thread *machine__find_thread(struct machine *machine, pid_t tid) ...@@ -331,7 +331,8 @@ struct thread *machine__find_thread(struct machine *machine, pid_t tid)
return __machine__findnew_thread(machine, 0, tid, false); return __machine__findnew_thread(machine, 0, tid, false);
} }
int machine__process_comm_event(struct machine *machine, union perf_event *event) int machine__process_comm_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample)
{ {
struct thread *thread = machine__findnew_thread(machine, struct thread *thread = machine__findnew_thread(machine,
event->comm.pid, event->comm.pid,
...@@ -340,7 +341,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event ...@@ -340,7 +341,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
if (dump_trace) if (dump_trace)
perf_event__fprintf_comm(event, stdout); perf_event__fprintf_comm(event, stdout);
if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) {
dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
return -1; return -1;
} }
...@@ -349,7 +350,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event ...@@ -349,7 +350,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
} }
int machine__process_lost_event(struct machine *machine __maybe_unused, int machine__process_lost_event(struct machine *machine __maybe_unused,
union perf_event *event) union perf_event *event, struct perf_sample *sample __maybe_unused)
{ {
dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
event->lost.id, event->lost.lost); event->lost.id, event->lost.lost);
...@@ -984,7 +985,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine, ...@@ -984,7 +985,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
} }
int machine__process_mmap2_event(struct machine *machine, int machine__process_mmap2_event(struct machine *machine,
union perf_event *event) union perf_event *event,
struct perf_sample *sample __maybe_unused)
{ {
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
struct thread *thread; struct thread *thread;
...@@ -1031,7 +1033,8 @@ int machine__process_mmap2_event(struct machine *machine, ...@@ -1031,7 +1033,8 @@ int machine__process_mmap2_event(struct machine *machine,
return 0; return 0;
} }
int machine__process_mmap_event(struct machine *machine, union perf_event *event) int machine__process_mmap_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample __maybe_unused)
{ {
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
struct thread *thread; struct thread *thread;
...@@ -1088,7 +1091,8 @@ static void machine__remove_thread(struct machine *machine, struct thread *th) ...@@ -1088,7 +1091,8 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)
list_add_tail(&th->node, &machine->dead_threads); list_add_tail(&th->node, &machine->dead_threads);
} }
int machine__process_fork_event(struct machine *machine, union perf_event *event) int machine__process_fork_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample)
{ {
struct thread *thread = machine__find_thread(machine, event->fork.tid); struct thread *thread = machine__find_thread(machine, event->fork.tid);
struct thread *parent = machine__findnew_thread(machine, struct thread *parent = machine__findnew_thread(machine,
...@@ -1105,7 +1109,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event ...@@ -1105,7 +1109,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
perf_event__fprintf_task(event, stdout); perf_event__fprintf_task(event, stdout);
if (thread == NULL || parent == NULL || if (thread == NULL || parent == NULL ||
thread__fork(thread, parent) < 0) { thread__fork(thread, parent, sample->time) < 0) {
dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
return -1; return -1;
} }
...@@ -1113,8 +1117,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event ...@@ -1113,8 +1117,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
return 0; return 0;
} }
int machine__process_exit_event(struct machine *machine __maybe_unused, int machine__process_exit_event(struct machine *machine, union perf_event *event,
union perf_event *event) struct perf_sample *sample __maybe_unused)
{ {
struct thread *thread = machine__find_thread(machine, event->fork.tid); struct thread *thread = machine__find_thread(machine, event->fork.tid);
...@@ -1127,23 +1131,24 @@ int machine__process_exit_event(struct machine *machine __maybe_unused, ...@@ -1127,23 +1131,24 @@ int machine__process_exit_event(struct machine *machine __maybe_unused,
return 0; return 0;
} }
int machine__process_event(struct machine *machine, union perf_event *event) int machine__process_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample)
{ {
int ret; int ret;
switch (event->header.type) { switch (event->header.type) {
case PERF_RECORD_COMM: case PERF_RECORD_COMM:
ret = machine__process_comm_event(machine, event); break; ret = machine__process_comm_event(machine, event, sample); break;
case PERF_RECORD_MMAP: case PERF_RECORD_MMAP:
ret = machine__process_mmap_event(machine, event); break; ret = machine__process_mmap_event(machine, event, sample); break;
case PERF_RECORD_MMAP2: case PERF_RECORD_MMAP2:
ret = machine__process_mmap2_event(machine, event); break; ret = machine__process_mmap2_event(machine, event, sample); break;
case PERF_RECORD_FORK: case PERF_RECORD_FORK:
ret = machine__process_fork_event(machine, event); break; ret = machine__process_fork_event(machine, event, sample); break;
case PERF_RECORD_EXIT: case PERF_RECORD_EXIT:
ret = machine__process_exit_event(machine, event); break; ret = machine__process_exit_event(machine, event, sample); break;
case PERF_RECORD_LOST: case PERF_RECORD_LOST:
ret = machine__process_lost_event(machine, event); break; ret = machine__process_lost_event(machine, event, sample); break;
default: default:
ret = -1; ret = -1;
break; break;
......
...@@ -40,13 +40,20 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type) ...@@ -40,13 +40,20 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
struct thread *machine__find_thread(struct machine *machine, pid_t tid); struct thread *machine__find_thread(struct machine *machine, pid_t tid);
int machine__process_comm_event(struct machine *machine, union perf_event *event); int machine__process_comm_event(struct machine *machine, union perf_event *event,
int machine__process_exit_event(struct machine *machine, union perf_event *event); struct perf_sample *sample);
int machine__process_fork_event(struct machine *machine, union perf_event *event); int machine__process_exit_event(struct machine *machine, union perf_event *event,
int machine__process_lost_event(struct machine *machine, union perf_event *event); struct perf_sample *sample);
int machine__process_mmap_event(struct machine *machine, union perf_event *event); int machine__process_fork_event(struct machine *machine, union perf_event *event,
int machine__process_mmap2_event(struct machine *machine, union perf_event *event); struct perf_sample *sample);
int machine__process_event(struct machine *machine, union perf_event *event); int machine__process_lost_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
int machine__process_mmap_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
int machine__process_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
typedef void (*machine__process_t)(struct machine *machine, void *data); typedef void (*machine__process_t)(struct machine *machine, void *data);
......
...@@ -339,10 +339,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, ...@@ -339,10 +339,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
if (arg[1] != '-') { if (arg[1] != '-') {
ctx->opt = arg + 1; ctx->opt = arg + 1;
if (internal_help && *ctx->opt == 'h') if (internal_help && *ctx->opt == 'h')
return parse_options_usage(usagestr, options); return usage_with_options_internal(usagestr, options, 0);
switch (parse_short_opt(ctx, options)) { switch (parse_short_opt(ctx, options)) {
case -1: case -1:
return parse_options_usage(usagestr, options); return parse_options_usage(usagestr, options, arg + 1, 1);
case -2: case -2:
goto unknown; goto unknown;
default: default:
...@@ -352,10 +352,11 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, ...@@ -352,10 +352,11 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
check_typos(arg + 1, options); check_typos(arg + 1, options);
while (ctx->opt) { while (ctx->opt) {
if (internal_help && *ctx->opt == 'h') if (internal_help && *ctx->opt == 'h')
return parse_options_usage(usagestr, options); return usage_with_options_internal(usagestr, options, 0);
arg = ctx->opt;
switch (parse_short_opt(ctx, options)) { switch (parse_short_opt(ctx, options)) {
case -1: case -1:
return parse_options_usage(usagestr, options); return parse_options_usage(usagestr, options, arg, 1);
case -2: case -2:
/* fake a short option thing to hide the fact that we may have /* fake a short option thing to hide the fact that we may have
* started to parse aggregated stuff * started to parse aggregated stuff
...@@ -383,12 +384,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, ...@@ -383,12 +384,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
if (internal_help && !strcmp(arg + 2, "help-all")) if (internal_help && !strcmp(arg + 2, "help-all"))
return usage_with_options_internal(usagestr, options, 1); return usage_with_options_internal(usagestr, options, 1);
if (internal_help && !strcmp(arg + 2, "help")) if (internal_help && !strcmp(arg + 2, "help"))
return parse_options_usage(usagestr, options); return usage_with_options_internal(usagestr, options, 0);
if (!strcmp(arg + 2, "list-opts")) if (!strcmp(arg + 2, "list-opts"))
return PARSE_OPT_LIST; return PARSE_OPT_LIST;
switch (parse_long_opt(ctx, arg + 2, options)) { switch (parse_long_opt(ctx, arg + 2, options)) {
case -1: case -1:
return parse_options_usage(usagestr, options); return parse_options_usage(usagestr, options, arg + 2, 0);
case -2: case -2:
goto unknown; goto unknown;
default: default:
...@@ -445,6 +446,89 @@ int parse_options(int argc, const char **argv, const struct option *options, ...@@ -445,6 +446,89 @@ int parse_options(int argc, const char **argv, const struct option *options,
#define USAGE_OPTS_WIDTH 24 #define USAGE_OPTS_WIDTH 24
#define USAGE_GAP 2 #define USAGE_GAP 2
static void print_option_help(const struct option *opts, int full)
{
size_t pos;
int pad;
if (opts->type == OPTION_GROUP) {
fputc('\n', stderr);
if (*opts->help)
fprintf(stderr, "%s\n", opts->help);
return;
}
if (!full && (opts->flags & PARSE_OPT_HIDDEN))
return;
pos = fprintf(stderr, " ");
if (opts->short_name)
pos += fprintf(stderr, "-%c", opts->short_name);
else
pos += fprintf(stderr, " ");
if (opts->long_name && opts->short_name)
pos += fprintf(stderr, ", ");
if (opts->long_name)
pos += fprintf(stderr, "--%s", opts->long_name);
switch (opts->type) {
case OPTION_ARGUMENT:
break;
case OPTION_LONG:
case OPTION_U64:
case OPTION_INTEGER:
case OPTION_UINTEGER:
if (opts->flags & PARSE_OPT_OPTARG)
if (opts->long_name)
pos += fprintf(stderr, "[=<n>]");
else
pos += fprintf(stderr, "[<n>]");
else
pos += fprintf(stderr, " <n>");
break;
case OPTION_CALLBACK:
if (opts->flags & PARSE_OPT_NOARG)
break;
/* FALLTHROUGH */
case OPTION_STRING:
if (opts->argh) {
if (opts->flags & PARSE_OPT_OPTARG)
if (opts->long_name)
pos += fprintf(stderr, "[=<%s>]", opts->argh);
else
pos += fprintf(stderr, "[<%s>]", opts->argh);
else
pos += fprintf(stderr, " <%s>", opts->argh);
} else {
if (opts->flags & PARSE_OPT_OPTARG)
if (opts->long_name)
pos += fprintf(stderr, "[=...]");
else
pos += fprintf(stderr, "[...]");
else
pos += fprintf(stderr, " ...");
}
break;
default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
case OPTION_END:
case OPTION_GROUP:
case OPTION_BIT:
case OPTION_BOOLEAN:
case OPTION_INCR:
case OPTION_SET_UINT:
case OPTION_SET_PTR:
break;
}
if (pos <= USAGE_OPTS_WIDTH)
pad = USAGE_OPTS_WIDTH - pos;
else {
fputc('\n', stderr);
pad = USAGE_OPTS_WIDTH;
}
fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
}
int usage_with_options_internal(const char * const *usagestr, int usage_with_options_internal(const char * const *usagestr,
const struct option *opts, int full) const struct option *opts, int full)
{ {
...@@ -464,87 +548,9 @@ int usage_with_options_internal(const char * const *usagestr, ...@@ -464,87 +548,9 @@ int usage_with_options_internal(const char * const *usagestr,
if (opts->type != OPTION_GROUP) if (opts->type != OPTION_GROUP)
fputc('\n', stderr); fputc('\n', stderr);
for (; opts->type != OPTION_END; opts++) { for ( ; opts->type != OPTION_END; opts++)
size_t pos; print_option_help(opts, full);
int pad;
if (opts->type == OPTION_GROUP) {
fputc('\n', stderr);
if (*opts->help)
fprintf(stderr, "%s\n", opts->help);
continue;
}
if (!full && (opts->flags & PARSE_OPT_HIDDEN))
continue;
pos = fprintf(stderr, " ");
if (opts->short_name)
pos += fprintf(stderr, "-%c", opts->short_name);
else
pos += fprintf(stderr, " ");
if (opts->long_name && opts->short_name)
pos += fprintf(stderr, ", ");
if (opts->long_name)
pos += fprintf(stderr, "--%s", opts->long_name);
switch (opts->type) {
case OPTION_ARGUMENT:
break;
case OPTION_LONG:
case OPTION_U64:
case OPTION_INTEGER:
case OPTION_UINTEGER:
if (opts->flags & PARSE_OPT_OPTARG)
if (opts->long_name)
pos += fprintf(stderr, "[=<n>]");
else
pos += fprintf(stderr, "[<n>]");
else
pos += fprintf(stderr, " <n>");
break;
case OPTION_CALLBACK:
if (opts->flags & PARSE_OPT_NOARG)
break;
/* FALLTHROUGH */
case OPTION_STRING:
if (opts->argh) {
if (opts->flags & PARSE_OPT_OPTARG)
if (opts->long_name)
pos += fprintf(stderr, "[=<%s>]", opts->argh);
else
pos += fprintf(stderr, "[<%s>]", opts->argh);
else
pos += fprintf(stderr, " <%s>", opts->argh);
} else {
if (opts->flags & PARSE_OPT_OPTARG)
if (opts->long_name)
pos += fprintf(stderr, "[=...]");
else
pos += fprintf(stderr, "[...]");
else
pos += fprintf(stderr, " ...");
}
break;
default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
case OPTION_END:
case OPTION_GROUP:
case OPTION_BIT:
case OPTION_BOOLEAN:
case OPTION_INCR:
case OPTION_SET_UINT:
case OPTION_SET_PTR:
break;
}
if (pos <= USAGE_OPTS_WIDTH)
pad = USAGE_OPTS_WIDTH - pos;
else {
fputc('\n', stderr);
pad = USAGE_OPTS_WIDTH;
}
fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
}
fputc('\n', stderr); fputc('\n', stderr);
return PARSE_OPT_HELP; return PARSE_OPT_HELP;
...@@ -559,9 +565,45 @@ void usage_with_options(const char * const *usagestr, ...@@ -559,9 +565,45 @@ void usage_with_options(const char * const *usagestr,
} }
int parse_options_usage(const char * const *usagestr, int parse_options_usage(const char * const *usagestr,
const struct option *opts) const struct option *opts,
const char *optstr, bool short_opt)
{ {
return usage_with_options_internal(usagestr, opts, 0); if (!usagestr)
goto opt;
fprintf(stderr, "\n usage: %s\n", *usagestr++);
while (*usagestr && **usagestr)
fprintf(stderr, " or: %s\n", *usagestr++);
while (*usagestr) {
fprintf(stderr, "%s%s\n",
**usagestr ? " " : "",
*usagestr);
usagestr++;
}
fputc('\n', stderr);
opt:
for ( ; opts->type != OPTION_END; opts++) {
if (short_opt) {
if (opts->short_name == *optstr)
break;
continue;
}
if (opts->long_name == NULL)
continue;
if (!prefixcmp(optstr, opts->long_name))
break;
if (!prefixcmp(optstr, "no-") &&
!prefixcmp(optstr + 3, opts->long_name))
break;
}
if (opts->type != OPTION_END)
print_option_help(opts, 0);
return PARSE_OPT_HELP;
} }
......
...@@ -158,7 +158,9 @@ struct parse_opt_ctx_t { ...@@ -158,7 +158,9 @@ struct parse_opt_ctx_t {
}; };
extern int parse_options_usage(const char * const *usagestr, extern int parse_options_usage(const char * const *usagestr,
const struct option *opts); const struct option *opts,
const char *optstr,
bool short_opt);
extern void parse_options_start(struct parse_opt_ctx_t *ctx, extern void parse_options_start(struct parse_opt_ctx_t *ctx,
int argc, const char **argv, int flags); int argc, const char **argv, int flags);
......
...@@ -583,7 +583,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, ...@@ -583,7 +583,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
} }
if (die_find_member(&type, field->name, die_mem) == NULL) { if (die_find_member(&type, field->name, die_mem) == NULL) {
pr_warning("%s(tyep:%s) has no member %s.\n", varname, pr_warning("%s(type:%s) has no member %s.\n", varname,
dwarf_diename(&type), field->name); dwarf_diename(&type), field->name);
return -EINVAL; return -EINVAL;
} }
......
...@@ -273,7 +273,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, ...@@ -273,7 +273,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
int cpu = sample->cpu; int cpu = sample->cpu;
void *data = sample->raw_data; void *data = sample->raw_data;
unsigned long long nsecs = sample->time; unsigned long long nsecs = sample->time;
char *comm = thread->comm; const char *comm = thread__comm_str(thread);
dSP; dSP;
......
...@@ -250,7 +250,7 @@ static void python_process_tracepoint(union perf_event *perf_event ...@@ -250,7 +250,7 @@ static void python_process_tracepoint(union perf_event *perf_event
int cpu = sample->cpu; int cpu = sample->cpu;
void *data = sample->raw_data; void *data = sample->raw_data;
unsigned long long nsecs = sample->time; unsigned long long nsecs = sample->time;
char *comm = thread->comm; const char *comm = thread__comm_str(thread);
t = PyTuple_New(MAX_FIELDS); t = PyTuple_New(MAX_FIELDS);
if (!t) if (!t)
...@@ -389,7 +389,7 @@ static void python_process_general_event(union perf_event *perf_event ...@@ -389,7 +389,7 @@ static void python_process_general_event(union perf_event *perf_event
pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize(
(const char *)sample->raw_data, sample->raw_size)); (const char *)sample->raw_data, sample->raw_size));
pydict_set_item_string_decref(dict, "comm", pydict_set_item_string_decref(dict, "comm",
PyString_FromString(thread->comm)); PyString_FromString(thread__comm_str(thread)));
if (al->map) { if (al->map) {
pydict_set_item_string_decref(dict, "dso", pydict_set_item_string_decref(dict, "dso",
PyString_FromString(al->map->dso->name)); PyString_FromString(al->map->dso->name));
......
...@@ -1100,7 +1100,7 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se ...@@ -1100,7 +1100,7 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
{ {
struct thread *thread = perf_session__findnew(self, 0); struct thread *thread = perf_session__findnew(self, 0);
if (thread == NULL || thread__set_comm(thread, "swapper")) { if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
pr_err("problem inserting idle task.\n"); pr_err("problem inserting idle task.\n");
thread = NULL; thread = NULL;
} }
......
#include "sort.h" #include "sort.h"
#include "hist.h" #include "hist.h"
#include "comm.h"
#include "symbol.h" #include "symbol.h"
regex_t parent_regex; regex_t parent_regex;
...@@ -42,7 +43,7 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) ...@@ -42,7 +43,7 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
return n; return n;
} }
static int64_t cmp_null(void *l, void *r) static int64_t cmp_null(const void *l, const void *r)
{ {
if (!l && !r) if (!l && !r)
return 0; return 0;
...@@ -63,8 +64,9 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -63,8 +64,9 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
const char *comm = thread__comm_str(he->thread);
return repsep_snprintf(bf, size, "%*s:%5d", width - 6, return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
he->thread->comm ?: "", he->thread->tid); comm ?: "", he->thread->tid);
} }
struct sort_entry sort_thread = { struct sort_entry sort_thread = {
...@@ -79,25 +81,21 @@ struct sort_entry sort_thread = { ...@@ -79,25 +81,21 @@ struct sort_entry sort_thread = {
static int64_t static int64_t
sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
return right->thread->tid - left->thread->tid; /* Compare the addr that should be unique among comm */
return comm__str(right->comm) - comm__str(left->comm);
} }
static int64_t static int64_t
sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
{ {
char *comm_l = left->thread->comm; /* Compare the addr that should be unique among comm */
char *comm_r = right->thread->comm; return comm__str(right->comm) - comm__str(left->comm);
if (!comm_l || !comm_r)
return cmp_null(comm_l, comm_r);
return strcmp(comm_l, comm_r);
} }
static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return repsep_snprintf(bf, size, "%*s", width, he->thread->comm); return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
} }
struct sort_entry sort_comm = { struct sort_entry sort_comm = {
......
...@@ -84,6 +84,7 @@ struct hist_entry { ...@@ -84,6 +84,7 @@ struct hist_entry {
struct he_stat stat; struct he_stat stat;
struct map_symbol ms; struct map_symbol ms;
struct thread *thread; struct thread *thread;
struct comm *comm;
u64 ip; u64 ip;
u64 transaction; u64 transaction;
s32 cpu; s32 cpu;
......
...@@ -6,9 +6,12 @@ ...@@ -6,9 +6,12 @@
#include "thread.h" #include "thread.h"
#include "util.h" #include "util.h"
#include "debug.h" #include "debug.h"
#include "comm.h"
struct thread *thread__new(pid_t pid, pid_t tid) struct thread *thread__new(pid_t pid, pid_t tid)
{ {
char *comm_str;
struct comm *comm;
struct thread *thread = zalloc(sizeof(*thread)); struct thread *thread = zalloc(sizeof(*thread));
if (thread != NULL) { if (thread != NULL) {
...@@ -16,41 +19,88 @@ struct thread *thread__new(pid_t pid, pid_t tid) ...@@ -16,41 +19,88 @@ struct thread *thread__new(pid_t pid, pid_t tid)
thread->pid_ = pid; thread->pid_ = pid;
thread->tid = tid; thread->tid = tid;
thread->ppid = -1; thread->ppid = -1;
thread->comm = malloc(32); INIT_LIST_HEAD(&thread->comm_list);
if (thread->comm)
snprintf(thread->comm, 32, ":%d", thread->tid); comm_str = malloc(32);
if (!comm_str)
goto err_thread;
snprintf(comm_str, 32, ":%d", tid);
comm = comm__new(comm_str, 0);
free(comm_str);
if (!comm)
goto err_thread;
list_add(&comm->list, &thread->comm_list);
} }
return thread; return thread;
err_thread:
free(thread);
return NULL;
} }
void thread__delete(struct thread *thread) void thread__delete(struct thread *thread)
{ {
struct comm *comm, *tmp;
map_groups__exit(&thread->mg); map_groups__exit(&thread->mg);
free(thread->comm); list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
list_del(&comm->list);
comm__free(comm);
}
free(thread); free(thread);
} }
int thread__set_comm(struct thread *thread, const char *comm) struct comm *thread__comm(const struct thread *thread)
{ {
int err; if (list_empty(&thread->comm_list))
return NULL;
if (thread->comm) return list_first_entry(&thread->comm_list, struct comm, list);
free(thread->comm); }
thread->comm = strdup(comm);
err = thread->comm == NULL ? -ENOMEM : 0; /* CHECKME: time should always be 0 if event aren't ordered */
if (!err) { int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
thread->comm_set = true; {
struct comm *new, *curr = thread__comm(thread);
/* Override latest entry if it had no specific time coverage */
if (!curr->start) {
comm__override(curr, str, timestamp);
return 0;
} }
return err;
new = comm__new(str, timestamp);
if (!new)
return -ENOMEM;
list_add(&new->list, &thread->comm_list);
thread->comm_set = true;
return 0;
}
const char *thread__comm_str(const struct thread *thread)
{
const struct comm *comm = thread__comm(thread);
if (!comm)
return NULL;
return comm__str(comm);
} }
/* CHECKME: it should probably better return the max comm len from its comm list */
int thread__comm_len(struct thread *thread) int thread__comm_len(struct thread *thread)
{ {
if (!thread->comm_len) { if (!thread->comm_len) {
if (!thread->comm) const char *comm = thread__comm_str(thread);
if (!comm)
return 0; return 0;
thread->comm_len = strlen(thread->comm); thread->comm_len = strlen(comm);
} }
return thread->comm_len; return thread->comm_len;
...@@ -58,7 +108,7 @@ int thread__comm_len(struct thread *thread) ...@@ -58,7 +108,7 @@ int thread__comm_len(struct thread *thread)
size_t thread__fprintf(struct thread *thread, FILE *fp) size_t thread__fprintf(struct thread *thread, FILE *fp)
{ {
return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) + return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
map_groups__fprintf(&thread->mg, verbose, fp); map_groups__fprintf(&thread->mg, verbose, fp);
} }
...@@ -68,16 +118,17 @@ void thread__insert_map(struct thread *thread, struct map *map) ...@@ -68,16 +118,17 @@ void thread__insert_map(struct thread *thread, struct map *map)
map_groups__insert(&thread->mg, map); map_groups__insert(&thread->mg, map);
} }
int thread__fork(struct thread *thread, struct thread *parent) int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
{ {
int i; int i, err;
if (parent->comm_set) { if (parent->comm_set) {
if (thread->comm) const char *comm = thread__comm_str(parent);
free(thread->comm); if (!comm)
thread->comm = strdup(parent->comm);
if (!thread->comm)
return -ENOMEM; return -ENOMEM;
err = thread__set_comm(thread, comm, timestamp);
if (!err)
return err;
thread->comm_set = true; thread->comm_set = true;
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define __PERF_THREAD_H #define __PERF_THREAD_H
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/list.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include "symbol.h" #include "symbol.h"
...@@ -18,13 +19,14 @@ struct thread { ...@@ -18,13 +19,14 @@ struct thread {
char shortname[3]; char shortname[3];
bool comm_set; bool comm_set;
bool dead; /* if set thread has exited */ bool dead; /* if set thread has exited */
char *comm; struct list_head comm_list;
int comm_len; int comm_len;
void *priv; void *priv;
}; };
struct machine; struct machine;
struct comm;
struct thread *thread__new(pid_t pid, pid_t tid); struct thread *thread__new(pid_t pid, pid_t tid);
void thread__delete(struct thread *self); void thread__delete(struct thread *self);
...@@ -33,10 +35,12 @@ static inline void thread__exited(struct thread *thread) ...@@ -33,10 +35,12 @@ static inline void thread__exited(struct thread *thread)
thread->dead = true; thread->dead = true;
} }
int thread__set_comm(struct thread *self, const char *comm); int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp);
int thread__comm_len(struct thread *self); int thread__comm_len(struct thread *self);
struct comm *thread__comm(const struct thread *thread);
const char *thread__comm_str(const struct thread *thread);
void thread__insert_map(struct thread *self, struct map *map); void thread__insert_map(struct thread *self, struct map *map);
int thread__fork(struct thread *self, struct thread *parent); int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
size_t thread__fprintf(struct thread *thread, FILE *fp); size_t thread__fprintf(struct thread *thread, FILE *fp);
static inline struct map *thread__find_map(struct thread *self, static inline struct map *thread__find_map(struct thread *self,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment