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)
return 0;
}
void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock)
{
pevent->trace_clock = trace_clock;
}
struct func_map {
unsigned long long addr;
char *func;
......@@ -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.
* 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)
{
struct printk_list *item = malloc(sizeof(*item));
char *p;
if (!item)
return -1;
......@@ -610,10 +616,21 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt,
item->next = pevent->printklist;
item->addr = addr;
/* Strip off quotes and '\n' from the end */
if (fmt[0] == '"')
fmt++;
item->printk = strdup(fmt);
if (!item->printk)
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->printk_count++;
......@@ -3488,6 +3505,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
struct pevent *pevent = event->pevent;
struct print_flag_sym *flag;
struct format_field *field;
struct printk_map *printk;
unsigned long long val, fval;
unsigned long addr;
char *str;
......@@ -3523,7 +3541,12 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
if (!(field->flags & FIELD_IS_ARRAY) &&
field->size == pevent->long_size) {
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;
}
str = malloc(len + 1);
......@@ -3565,15 +3588,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
}
break;
case PRINT_HEX:
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;
if (arg->hex.field->type == PRINT_DYNAMIC_ARRAY) {
unsigned long offset;
offset = pevent_read_number(pevent,
data + arg->hex.field->dynarray.field->offset,
arg->hex.field->dynarray.field->size);
hex = data + (offset & 0xffff);
} 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);
for (i = 0; i < len; i++) {
if (i)
......@@ -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)
goto out_free;
/* skip the first "%pf : " */
for (ptr = fmt + 6, bptr = data + field->offset;
/* skip the first "%pf: " */
for (ptr = fmt + 5, bptr = data + field->offset;
bptr < data + size && *ptr; ptr++) {
int ls = 0;
......@@ -3882,7 +3913,6 @@ get_bprint_format(void *data, int size __maybe_unused,
struct format_field *field;
struct printk_map *printk;
char *format;
char *p;
field = pevent->bprint_fmt_field;
......@@ -3899,25 +3929,13 @@ get_bprint_format(void *data, int size __maybe_unused,
printk = find_printk(pevent, addr);
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 format;
}
p = printk->printk;
/* Remove any quotes. */
if (*p == '"')
p++;
if (asprintf(&format, "%s : %s", "%pf", p) < 0)
if (asprintf(&format, "%s: %s", "%pf", printk->printk) < 0)
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;
}
......@@ -3963,7 +3981,7 @@ static int is_printable_array(char *p, unsigned int len)
unsigned int i;
for (i = 0; i < len && p[i]; i++)
if (!isprint(p[i]))
if (!isprint(p[i]) && !isspace(p[i]))
return 0;
return 1;
}
......@@ -4428,11 +4446,11 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
{
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);
else {
if (event->handler)
if (event->handler && !(event->flags & EVENT_FL_NOHANDLE))
print_pretty = event->handler(s, record, event,
event->context);
......@@ -4443,8 +4461,21 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
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,
struct pevent_record *record)
struct pevent_record *record, bool use_trace_clock)
{
static const char *spaces = " "; /* 20 spaces */
struct event_format *event;
......@@ -4457,9 +4488,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
int pid;
int len;
int p;
bool use_usec_format;
secs = record->ts / NSECS_PER_SEC;
nsecs = record->ts - secs * NSECS_PER_SEC;
use_usec_format = is_timestamp_in_us(pevent->trace_clock,
use_trace_clock);
if (use_usec_format) {
secs = record->ts / NSECS_PER_SEC;
nsecs = record->ts - secs * NSECS_PER_SEC;
}
if (record->size < 0) {
do_warning("ug! negative record size %d", record->size);
......@@ -4484,15 +4520,20 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
} else
trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
if (pevent->flags & PEVENT_NSEC_OUTPUT) {
usecs = nsecs;
p = 9;
} else {
usecs = (nsecs + 500) / NSECS_PER_USEC;
p = 6;
}
if (use_usec_format) {
if (pevent->flags & PEVENT_NSEC_OUTPUT) {
usecs = nsecs;
p = 9;
} else {
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. */
len = strlen(event->name);
......@@ -5326,6 +5367,48 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
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)
{
struct pevent_func_params *params;
......
......@@ -20,6 +20,7 @@
#ifndef _PARSE_EVENTS_H
#define _PARSE_EVENTS_H
#include <stdbool.h>
#include <stdarg.h>
#include <regex.h>
......@@ -307,6 +308,8 @@ enum {
EVENT_FL_ISBPRINT = 0x04,
EVENT_FL_ISFUNCENT = 0x10,
EVENT_FL_ISFUNCRET = 0x20,
EVENT_FL_NOHANDLE = 0x40,
EVENT_FL_PRINTRAW = 0x80,
EVENT_FL_FAILED = 0x80000000
};
......@@ -450,6 +453,8 @@ struct pevent {
/* cache */
struct event_format *last_event;
char *trace_clock;
};
static inline void pevent_set_flag(struct pevent *pevent, int flag)
......@@ -527,14 +532,15 @@ enum trace_flag_type {
};
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,
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);
int pevent_pid_is_registered(struct pevent *pevent, int pid);
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 long_size);
......@@ -563,6 +569,10 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
struct event_format *event, const char *name,
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,
const char *sys_name, const char *event_name,
pevent_event_handler_func func, void *context);
......
......@@ -273,6 +273,7 @@ LIB_H += util/color.h
LIB_H += util/values.h
LIB_H += util/sort.h
LIB_H += util/hist.h
LIB_H += util/comm.h
LIB_H += util/thread.h
LIB_H += util/thread_map.h
LIB_H += util/trace-event.h
......@@ -295,6 +296,7 @@ LIB_H += ui/helpline.h
LIB_H += ui/progress.h
LIB_H += ui/util.h
LIB_H += ui/ui.h
LIB_H += util/data.h
LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o
......@@ -340,6 +342,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o
LIB_OBJS += $(OUTPUT)util/map.o
LIB_OBJS += $(OUTPUT)util/pstack.o
LIB_OBJS += $(OUTPUT)util/session.o
LIB_OBJS += $(OUTPUT)util/comm.o
LIB_OBJS += $(OUTPUT)util/thread.o
LIB_OBJS += $(OUTPUT)util/thread_map.o
LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
......@@ -708,7 +711,7 @@ $(LIB_FILE): $(LIB_OBJS)
TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
$(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:
$(call QUIET_CLEAN, libtraceevent)
......
......@@ -315,7 +315,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
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) {
tracepoint_handler f = evsel->handler.func;
......
......@@ -767,7 +767,7 @@ static void dump_threads(void)
while (node) {
st = container_of(node, struct thread_stat, rb);
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);
};
}
......
......@@ -905,13 +905,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
input_name = "perf.data";
}
if (strcmp(input_name, "-") != 0)
setup_browser(true);
else {
use_browser = 0;
perf_hpp__init();
}
file.path = input_name;
file.force = report.force;
......@@ -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";
}
if (setup_sorting() < 0)
usage_with_options(report_usage, options);
if (setup_sorting() < 0) {
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,
......@@ -986,11 +993,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
if (symbol__init() < 0)
goto error;
if (parent_pattern != default_parent_pattern) {
if (sort_dimension__add("parent") < 0)
goto error;
}
if (argc) {
/*
* Special case: if there's an argument left then assume that
......
......@@ -737,12 +737,12 @@ static int replay_fork_event(struct perf_sched *sched,
if (verbose) {
printf("fork event\n");
printf("... parent: %s/%d\n", parent->comm, parent->tid);
printf("... child: %s/%d\n", child->comm, child->tid);
printf("... parent: %s/%d\n", thread__comm_str(parent), parent->tid);
printf("... child: %s/%d\n", thread__comm_str(child), child->tid);
}
register_pid(sched, parent->tid, parent->comm);
register_pid(sched, child->tid, child->comm);
register_pid(sched, parent->tid, thread__comm_str(parent));
register_pid(sched, child->tid, thread__comm_str(child));
return 0;
}
......@@ -1077,7 +1077,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
if (!atoms) {
if (thread_atoms_insert(sched, migrant))
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);
if (!atoms) {
pr_err("migration-event: Internal tree error");
......@@ -1111,13 +1111,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
/*
* Ignore idle threads:
*/
if (!strcmp(work_list->thread->comm, "swapper"))
if (!strcmp(thread__comm_str(work_list->thread), "swapper"))
return;
sched->all_runtime += work_list->total_runtime;
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++)
printf(" ");
......@@ -1334,7 +1334,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
printf(" %12.6f secs ", (double)timestamp/1e9);
if (new_shortname) {
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 {
printf("\n");
}
......
......@@ -229,6 +229,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
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
* have the expected data
......@@ -237,7 +255,6 @@ static int perf_session__check_output_opt(struct perf_session *session)
{
int j;
struct perf_evsel *evsel;
struct perf_event_attr *attr;
for (j = 0; j < PERF_TYPE_MAX; ++j) {
evsel = perf_session__find_first_evtype(session, j);
......@@ -260,20 +277,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
if (evsel == NULL)
continue;
attr = &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;
set_print_ip_opts(&evsel->attr);
}
return 0;
......@@ -291,11 +295,11 @@ static void print_sample_start(struct perf_sample *sample,
if (PRINT_FIELD(COMM)) {
if (latency_format)
printf("%8.8s ", thread->comm);
printf("%8.8s ", thread__comm_str(thread));
else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
printf("%s ", thread->comm);
printf("%s ", thread__comm_str(thread));
else
printf("%16s ", thread->comm);
printf("%16s ", thread__comm_str(thread));
}
if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
......@@ -547,6 +551,34 @@ struct perf_script {
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)
{
session_done = 1;
......@@ -1272,7 +1304,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
.attr = perf_event__process_attr,
.attr = process_attr,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.ordered_samples = true,
......
......@@ -1596,7 +1596,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"perf stat [<options>] [<command>]",
NULL
};
int status = -ENOMEM, run_idx;
int status = -EINVAL, run_idx;
const char *mode;
setlocale(LC_ALL, "");
......@@ -1614,12 +1614,15 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (output_name && output_fd) {
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) {
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) {
......@@ -1656,7 +1659,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
/* User explicitly passed -B? */
if (big_num_opt == 1) {
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 */
big_num = false;
} 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)
usage_with_options(stat_usage, options);
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) {
forever = true;
run_count = 1;
......@@ -1678,8 +1685,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
fprintf(stderr, "both cgroup and no-aggregation "
"modes only available in system-wide mode\n");
usage_with_options(stat_usage, options);
return -1;
parse_options_usage(stat_usage, options, "G", 1);
parse_options_usage(NULL, options, "A", 1);
parse_options_usage(NULL, options, "a", 1);
goto out;
}
if (add_default_attributes())
......@@ -1688,25 +1697,28 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
perf_target__validate(&target);
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");
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");
usage_with_options(stat_usage, options);
return -1;
parse_options_usage(stat_usage, options, "C", 1);
parse_options_usage(NULL, options, "a", 1);
}
goto out;
}
if (interval && interval < 100) {
pr_err("print interval must be >= 100ms\n");
usage_with_options(stat_usage, options);
return -1;
parse_options_usage(stat_usage, options, "I", 1);
goto out_free_maps;
}
if (perf_evlist__alloc_stats(evsel_list, interval))
goto out_free_maps;
if (perf_stat_init_aggr_mode())
goto out;
goto out_free_maps;
/*
* 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)
&sample, machine);
} else if (event->header.type < PERF_RECORD_MAX) {
hists__inc_nr_events(&evsel->hists, event->header.type);
machine__process_event(machine, event);
machine__process_event(machine, event, &sample);
} else
++session->stats.nr_unknown_events;
next_event:
......@@ -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 status;
int status = -1;
char errbuf[BUFSIZ];
struct perf_top top = {
.count_filter = 5,
......@@ -1159,8 +1159,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (sort_order == default_sort_order)
sort_order = "dso,symbol";
if (setup_sorting() < 0)
usage_with_options(top_usage, options);
if (setup_sorting() < 0) {
parse_options_usage(top_usage, options, "s", 1);
goto out_delete_evlist;
}
/* display thread wants entries to be collapsed in a different tree */
sort__need_collapse = 1;
......
......@@ -1114,7 +1114,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
if (trace->multiple_threads) {
if (trace->show_comm)
printed += fprintf(fp, "%.14s/", thread->comm);
printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
printed += fprintf(fp, "%d ", thread->tid);
}
......@@ -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,
union perf_event *event)
union perf_event *event, struct perf_sample *sample)
{
int ret = 0;
......@@ -1130,9 +1130,9 @@ static int trace__process_event(struct trace *trace, struct machine *machine,
case PERF_RECORD_LOST:
color_fprintf(trace->output, PERF_COLOR_RED,
"LOST %" PRIu64 " events!\n", event->lost.lost);
ret = machine__process_lost_event(machine, event);
ret = machine__process_lost_event(machine, event, sample);
default:
ret = machine__process_event(machine, event);
ret = machine__process_event(machine, event, sample);
break;
}
......@@ -1141,11 +1141,11 @@ static int trace__process_event(struct trace *trace, struct machine *machine,
static int trace__tool_process(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct perf_sample *sample,
struct machine *machine)
{
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)
......@@ -1751,7 +1751,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
trace->base_time = sample.time;
if (type != PERF_RECORD_SAMPLE) {
trace__process_event(trace, trace->host, event);
trace__process_event(trace, trace->host, event, &sample);
continue;
}
......@@ -1986,7 +1986,7 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
else if (ratio > 5.0)
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 += color_fprintf(fp, color, "%5.1f%%", ratio);
printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
......
......@@ -25,9 +25,11 @@ ifeq ($(ARCH),x86_64)
RAW_ARCH := x86_64
CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
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
NO_PERF_REGS := 0
LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
endif
ifeq ($(NO_PERF_REGS),0)
......@@ -96,7 +98,7 @@ endif
feature_check = $(eval $(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
feature_set = $(eval $(feature_set_code))
......@@ -173,7 +175,7 @@ ifeq ($(feature-all), 1)
#
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat)))
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)))
endif
......
......@@ -31,12 +31,12 @@ CC := $(CC) -MD
all: $(FILES)
BUILD = $(CC) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
###############################
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:
$(BUILD)
......@@ -72,7 +72,7 @@ test-libnuma:
$(BUILD) -lnuma
test-libunwind:
$(BUILD) -lunwind -lunwind-x86_64 -lelf
$(BUILD) $(LIBUNWIND_LIBS) -lelf
test-libaudit:
$(BUILD) -laudit
......
......@@ -276,7 +276,7 @@ static int process_event(struct machine *machine, struct perf_evlist *evlist,
return process_sample_event(machine, evlist, event, state);
if (event->header.type < PERF_RECORD_MAX)
return machine__process_event(machine, event);
return machine__process_event(machine, event, NULL);
return 0;
}
......
......@@ -93,7 +93,7 @@ static struct machine *setup_fake_machine(struct machines *machines)
if (thread == NULL)
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++) {
......@@ -110,7 +110,7 @@ static struct machine *setup_fake_machine(struct machines *machines)
strcpy(fake_mmap_event.mmap.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++) {
......@@ -421,7 +421,7 @@ static void print_hists(struct hists *hists)
he = rb_entry(node, struct hist_entry, rb_node_in);
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);
i++;
......
......@@ -121,6 +121,9 @@ static bool samples_same(const struct perf_sample *s1,
if (type & PERF_SAMPLE_DATA_SRC)
COMP(data_src);
if (type & PERF_SAMPLE_TRANSACTION)
COMP(transaction);
return true;
}
......@@ -165,6 +168,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
.cpu = 110,
.raw_size = sizeof(raw_data),
.data_src = 111,
.transaction = 112,
.raw_data = (void *)raw_data,
.callchain = &callchain.callchain,
.branch_stack = &branch_stack.branch_stack,
......@@ -273,7 +277,8 @@ int test__sample_parsing(void)
/*
* 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) {
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,
if (thread)
printed += scnprintf(bf + printed, size - printed,
", Thread: %s(%d)",
(thread->comm_set ? thread->comm : ""),
(thread->comm_set ? thread__comm_str(thread) : ""),
thread->tid);
if (dso)
printed += scnprintf(bf + printed, size - printed,
......@@ -1578,7 +1578,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (thread != NULL &&
asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
(browser->hists->thread_filter ? "out of" : "into"),
(thread->comm_set ? thread->comm : ""),
(thread->comm_set ? thread__comm_str(thread) : ""),
thread->tid) > 0)
zoom_thread = nr_options++;
......@@ -1598,7 +1598,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
struct symbol *sym;
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++;
sym = browser->he_selection->ms.sym;
......@@ -1701,7 +1701,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
sort_thread.elide = false;
} else {
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);
browser->hists->thread_filter = thread;
sort_thread.elide = true;
......@@ -1717,7 +1717,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
memset(script_opt, 0, 64);
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)
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)
int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct perf_sample *sample,
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,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct perf_sample *sample,
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)
......@@ -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,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct perf_sample *sample,
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,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct perf_sample *sample,
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)
......@@ -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,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct perf_sample *sample,
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,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct perf_sample *sample,
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)
......@@ -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,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct perf_sample *sample,
struct machine *machine)
{
return machine__process_event(machine, event);
return machine__process_event(machine, event, sample);
}
void thread__find_addr_map(struct thread *self,
......@@ -721,10 +721,10 @@ int perf_event__preprocess_sample(const union perf_event *event,
return -1;
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;
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?
*
......
......@@ -607,6 +607,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
MAP_SHARED, fd, 0);
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;
return -1;
}
......
......@@ -663,7 +663,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
}
if (opts->sample_address)
attr->sample_type |= PERF_SAMPLE_DATA_SRC;
perf_evsel__set_sample_bit(evsel, DATA_SRC);
if (opts->no_delay) {
attr->watermark = 0;
......@@ -675,13 +675,13 @@ void perf_evsel__config(struct perf_evsel *evsel,
}
if (opts->sample_weight)
attr->sample_type |= PERF_SAMPLE_WEIGHT;
perf_evsel__set_sample_bit(evsel, WEIGHT);
attr->mmap = track;
attr->comm = track;
if (opts->sample_transaction)
attr->sample_type |= PERF_SAMPLE_TRANSACTION;
perf_evsel__set_sample_bit(evsel, TRANSACTION);
/*
* XXX see the function comment above
......@@ -1051,6 +1051,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
group_fd, flags);
if (FD(evsel, cpu, thread) < 0) {
err = -errno;
pr_debug2("perf_event_open failed, error %d\n",
err);
goto try_fallback;
}
set_rlimit = NO_CHANGE;
......@@ -1479,6 +1481,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
data->transaction = 0;
if (type & PERF_SAMPLE_TRANSACTION) {
OVERFLOW_CHECK_u64(array);
data->transaction = *array;
array++;
}
......@@ -1575,6 +1578,9 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_DATA_SRC)
result += sizeof(u64);
if (type & PERF_SAMPLE_TRANSACTION)
result += sizeof(u64);
return result;
}
......@@ -1748,6 +1754,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
array++;
}
if (type & PERF_SAMPLE_TRANSACTION) {
*array = sample->transaction;
array++;
}
return 0;
}
......
......@@ -416,6 +416,7 @@ struct hist_entry *__hists__add_mem_entry(struct hists *hists,
{
struct hist_entry entry = {
.thread = al->thread,
.comm = thread__comm(al->thread),
.ms = {
.map = al->map,
.sym = al->sym,
......@@ -446,6 +447,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *hists,
{
struct hist_entry entry = {
.thread = al->thread,
.comm = thread__comm(al->thread),
.ms = {
.map = bi->to.map,
.sym = bi->to.sym,
......@@ -475,6 +477,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
{
struct hist_entry entry = {
.thread = al->thread,
.comm = thread__comm(al->thread),
.ms = {
.map = al->map,
.sym = al->sym,
......
......@@ -40,7 +40,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
return -ENOMEM;
snprintf(comm, sizeof(comm), "[guest/%d]", pid);
thread__set_comm(thread, comm);
thread__set_comm(thread, comm, 0);
}
return 0;
......@@ -331,7 +331,8 @@ struct thread *machine__find_thread(struct machine *machine, pid_t tid)
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,
event->comm.pid,
......@@ -340,7 +341,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
if (dump_trace)
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");
return -1;
}
......@@ -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,
union perf_event *event)
union perf_event *event, struct perf_sample *sample __maybe_unused)
{
dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
event->lost.id, event->lost.lost);
......@@ -984,7 +985,8 @@ static int machine__process_kernel_mmap_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;
struct thread *thread;
......@@ -1031,7 +1033,8 @@ int machine__process_mmap2_event(struct machine *machine,
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;
struct thread *thread;
......@@ -1088,7 +1091,8 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)
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 *parent = machine__findnew_thread(machine,
......@@ -1105,7 +1109,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
perf_event__fprintf_task(event, stdout);
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");
return -1;
}
......@@ -1113,8 +1117,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
return 0;
}
int machine__process_exit_event(struct machine *machine __maybe_unused,
union perf_event *event)
int machine__process_exit_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample __maybe_unused)
{
struct thread *thread = machine__find_thread(machine, event->fork.tid);
......@@ -1127,23 +1131,24 @@ int machine__process_exit_event(struct machine *machine __maybe_unused,
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;
switch (event->header.type) {
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:
ret = machine__process_mmap_event(machine, event); break;
ret = machine__process_mmap_event(machine, event, sample); break;
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:
ret = machine__process_fork_event(machine, event); break;
ret = machine__process_fork_event(machine, event, sample); break;
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:
ret = machine__process_lost_event(machine, event); break;
ret = machine__process_lost_event(machine, event, sample); break;
default:
ret = -1;
break;
......
......@@ -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);
int machine__process_comm_event(struct machine *machine, union perf_event *event);
int machine__process_exit_event(struct machine *machine, union perf_event *event);
int machine__process_fork_event(struct machine *machine, union perf_event *event);
int machine__process_lost_event(struct machine *machine, union perf_event *event);
int machine__process_mmap_event(struct machine *machine, union perf_event *event);
int machine__process_mmap2_event(struct machine *machine, union perf_event *event);
int machine__process_event(struct machine *machine, union perf_event *event);
int machine__process_comm_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
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,
struct perf_sample *sample);
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);
......
......@@ -339,10 +339,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
if (arg[1] != '-') {
ctx->opt = arg + 1;
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)) {
case -1:
return parse_options_usage(usagestr, options);
return parse_options_usage(usagestr, options, arg + 1, 1);
case -2:
goto unknown;
default:
......@@ -352,10 +352,11 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
check_typos(arg + 1, options);
while (ctx->opt) {
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)) {
case -1:
return parse_options_usage(usagestr, options);
return parse_options_usage(usagestr, options, arg, 1);
case -2:
/* fake a short option thing to hide the fact that we may have
* started to parse aggregated stuff
......@@ -383,12 +384,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
if (internal_help && !strcmp(arg + 2, "help-all"))
return usage_with_options_internal(usagestr, options, 1);
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"))
return PARSE_OPT_LIST;
switch (parse_long_opt(ctx, arg + 2, options)) {
case -1:
return parse_options_usage(usagestr, options);
return parse_options_usage(usagestr, options, arg + 2, 0);
case -2:
goto unknown;
default:
......@@ -445,6 +446,89 @@ int parse_options(int argc, const char **argv, const struct option *options,
#define USAGE_OPTS_WIDTH 24
#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,
const struct option *opts, int full)
{
......@@ -464,87 +548,9 @@ int usage_with_options_internal(const char * const *usagestr,
if (opts->type != OPTION_GROUP)
fputc('\n', stderr);
for (; opts->type != OPTION_END; opts++) {
size_t pos;
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;
}
for ( ; opts->type != OPTION_END; opts++)
print_option_help(opts, full);
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);
return PARSE_OPT_HELP;
......@@ -559,9 +565,45 @@ void usage_with_options(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 {
};
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,
int argc, const char **argv, int flags);
......
......@@ -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) {
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);
return -EINVAL;
}
......
......@@ -273,7 +273,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
int cpu = sample->cpu;
void *data = sample->raw_data;
unsigned long long nsecs = sample->time;
char *comm = thread->comm;
const char *comm = thread__comm_str(thread);
dSP;
......
......@@ -250,7 +250,7 @@ static void python_process_tracepoint(union perf_event *perf_event
int cpu = sample->cpu;
void *data = sample->raw_data;
unsigned long long nsecs = sample->time;
char *comm = thread->comm;
const char *comm = thread__comm_str(thread);
t = PyTuple_New(MAX_FIELDS);
if (!t)
......@@ -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(
(const char *)sample->raw_data, sample->raw_size));
pydict_set_item_string_decref(dict, "comm",
PyString_FromString(thread->comm));
PyString_FromString(thread__comm_str(thread)));
if (al->map) {
pydict_set_item_string_decref(dict, "dso",
PyString_FromString(al->map->dso->name));
......
......@@ -1100,7 +1100,7 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
{
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");
thread = NULL;
}
......
#include "sort.h"
#include "hist.h"
#include "comm.h"
#include "symbol.h"
regex_t parent_regex;
......@@ -42,7 +43,7 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
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)
return 0;
......@@ -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,
size_t size, unsigned int width)
{
const char *comm = thread__comm_str(he->thread);
return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
he->thread->comm ?: "", he->thread->tid);
comm ?: "", he->thread->tid);
}
struct sort_entry sort_thread = {
......@@ -79,25 +81,21 @@ struct sort_entry sort_thread = {
static int64_t
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
sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
{
char *comm_l = left->thread->comm;
char *comm_r = right->thread->comm;
if (!comm_l || !comm_r)
return cmp_null(comm_l, comm_r);
return strcmp(comm_l, comm_r);
/* Compare the addr that should be unique among comm */
return comm__str(right->comm) - comm__str(left->comm);
}
static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
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 = {
......
......@@ -84,6 +84,7 @@ struct hist_entry {
struct he_stat stat;
struct map_symbol ms;
struct thread *thread;
struct comm *comm;
u64 ip;
u64 transaction;
s32 cpu;
......
......@@ -6,9 +6,12 @@
#include "thread.h"
#include "util.h"
#include "debug.h"
#include "comm.h"
struct thread *thread__new(pid_t pid, pid_t tid)
{
char *comm_str;
struct comm *comm;
struct thread *thread = zalloc(sizeof(*thread));
if (thread != NULL) {
......@@ -16,41 +19,88 @@ struct thread *thread__new(pid_t pid, pid_t tid)
thread->pid_ = pid;
thread->tid = tid;
thread->ppid = -1;
thread->comm = malloc(32);
if (thread->comm)
snprintf(thread->comm, 32, ":%d", thread->tid);
INIT_LIST_HEAD(&thread->comm_list);
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;
err_thread:
free(thread);
return NULL;
}
void thread__delete(struct thread *thread)
{
struct comm *comm, *tmp;
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);
}
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)
free(thread->comm);
thread->comm = strdup(comm);
err = thread->comm == NULL ? -ENOMEM : 0;
if (!err) {
thread->comm_set = true;
return list_first_entry(&thread->comm_list, struct comm, list);
}
/* CHECKME: time should always be 0 if event aren't ordered */
int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
{
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)
{
if (!thread->comm_len) {
if (!thread->comm)
const char *comm = thread__comm_str(thread);
if (!comm)
return 0;
thread->comm_len = strlen(thread->comm);
thread->comm_len = strlen(comm);
}
return thread->comm_len;
......@@ -58,7 +108,7 @@ int thread__comm_len(struct thread *thread)
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);
}
......@@ -68,16 +118,17 @@ void thread__insert_map(struct thread *thread, struct map *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 (thread->comm)
free(thread->comm);
thread->comm = strdup(parent->comm);
if (!thread->comm)
const char *comm = thread__comm_str(parent);
if (!comm)
return -ENOMEM;
err = thread__set_comm(thread, comm, timestamp);
if (!err)
return err;
thread->comm_set = true;
}
......
......@@ -2,6 +2,7 @@
#define __PERF_THREAD_H
#include <linux/rbtree.h>
#include <linux/list.h>
#include <unistd.h>
#include <sys/types.h>
#include "symbol.h"
......@@ -18,13 +19,14 @@ struct thread {
char shortname[3];
bool comm_set;
bool dead; /* if set thread has exited */
char *comm;
struct list_head comm_list;
int comm_len;
void *priv;
};
struct machine;
struct comm;
struct thread *thread__new(pid_t pid, pid_t tid);
void thread__delete(struct thread *self);
......@@ -33,10 +35,12 @@ static inline void thread__exited(struct thread *thread)
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);
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);
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);
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