perf/core improvements and fixes

. Fix build for another rbtree.c change, from Adrian Hunter.
 
  . Fixes for perf to build on Android, from Irina Tirdea.
 
  . Make 'perf diff' command work with evsel hists, from Jiri Olsa.
 
  . Use the only field_sep var that is set up: symbol_conf.field_sep,
    fix from Jiri Olsa.
 
  . .gitignore compiled python binaries, from Namhyung Kim.
 
  . Get rid of die() in more libtraceevent places, from Namhyung Kim.
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.14 (GNU/Linux)
 
 iQIcBAABAgAGBQJQSqBrAAoJENZQFvNTUqpAWO4P/RRxxu1gCn4a3llvoJi4x0Ql
 rtTXeBS1jHZPCH8uFxS2qhN8SHD8rLoVB0czx4Fs+jISwrq9hXP0DSVY+710yivM
 2F2O/0JU88dhbSGgQ5prCLqzdUQCzeg4nn1qThwHZgfuoA3wJ9mDVmqIj0urIiN+
 URMEU9mjkxPk4Dn1zi9Fb+fUDcCcgXTxjVIcIzKyNgEVnBRvomcILLAWaR40oshs
 ZTslLTWa7VSAzJaPPHHBlSa+r93JfbKlU3q18Ly2BmytxQLNfQmALHNY42L3VxWj
 1rz0ylAvC7I8qOK1teMly9ecYrKNPeTj9du54loee6wrMrsXd/14BWVEiDdyGEFv
 ChSEd/Tr6tgivj+TQ2IMlAA41ya0WG2SjOjzGXWpQ64BKtQUH9LuBbP+x6xuhGAh
 cnVW3HnbY9YufEaCbyTQ3PNLwuoJDy3xa6PtTzadNhyrYWlcnNP+T6B/sV6jBh0B
 RSw4FbNlJqqaP1bGrcuwLASVqQvEwLBRFVu4OEb5yI1Q/oAua497iz1NzMtrRk9G
 wpC5Ac21eJX+9HKV2KG+It5xmKsg3gQqPQpG1P7itRCOSrJAQjUzMNZkaFdH4Exo
 oatLZZk3P4qvhkjEh3SqAgiUHNYzCWBaAW2M50sgvvGH1jNIOy/gw7l4yU9YlwY5
 TEFw0MYKK+gDhR1SbISk
 =0L9W
 -----END PGP SIGNATURE-----

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:

 * Fix build for another rbtree.c change, from Adrian Hunter.

 * Fixes for perf to build on Android, from Irina Tirdea.

 * Make 'perf diff' command work with evsel hists, from Jiri Olsa.

 * Use the only field_sep var that is set up: symbol_conf.field_sep,
   fix from Jiri Olsa.

 * .gitignore compiled python binaries, from Namhyung Kim.

 * Get rid of die() in more libtraceevent places, from Namhyung Kim.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2012-09-08 13:26:02 +02:00
commit ef34eb4da3
19 changed files with 180 additions and 63 deletions

View File

@ -3889,8 +3889,11 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
goto cont_process; goto cont_process;
case '*': case '*':
/* The argument is the length. */ /* The argument is the length. */
if (!arg) if (!arg) {
die("no argument match"); do_warning("no argument match");
event->flags |= EVENT_FL_FAILED;
goto out_failed;
}
len_arg = eval_num_arg(data, size, event, arg); len_arg = eval_num_arg(data, size, event, arg);
len_as_arg = 1; len_as_arg = 1;
arg = arg->next; arg = arg->next;
@ -3923,15 +3926,21 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
case 'x': case 'x':
case 'X': case 'X':
case 'u': case 'u':
if (!arg) if (!arg) {
die("no argument match"); do_warning("no argument match");
event->flags |= EVENT_FL_FAILED;
goto out_failed;
}
len = ((unsigned long)ptr + 1) - len = ((unsigned long)ptr + 1) -
(unsigned long)saveptr; (unsigned long)saveptr;
/* should never happen */ /* should never happen */
if (len > 31) if (len > 31) {
die("bad format!"); do_warning("bad format!");
event->flags |= EVENT_FL_FAILED;
len = 31;
}
memcpy(format, saveptr, len); memcpy(format, saveptr, len);
format[len] = 0; format[len] = 0;
@ -3995,19 +4004,26 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
trace_seq_printf(s, format, (long long)val); trace_seq_printf(s, format, (long long)val);
break; break;
default: default:
die("bad count (%d)", ls); do_warning("bad count (%d)", ls);
event->flags |= EVENT_FL_FAILED;
} }
break; break;
case 's': case 's':
if (!arg) if (!arg) {
die("no matching argument"); do_warning("no matching argument");
event->flags |= EVENT_FL_FAILED;
goto out_failed;
}
len = ((unsigned long)ptr + 1) - len = ((unsigned long)ptr + 1) -
(unsigned long)saveptr; (unsigned long)saveptr;
/* should never happen */ /* should never happen */
if (len > 31) if (len > 31) {
die("bad format!"); do_warning("bad format!");
event->flags |= EVENT_FL_FAILED;
len = 31;
}
memcpy(format, saveptr, len); memcpy(format, saveptr, len);
format[len] = 0; format[len] = 0;
@ -4025,6 +4041,11 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
trace_seq_putc(s, *ptr); trace_seq_putc(s, *ptr);
} }
if (event->flags & EVENT_FL_FAILED) {
out_failed:
trace_seq_printf(s, "[FAILED TO PARSE]");
}
if (args) { if (args) {
free_args(args); free_args(args);
free(bprint_fmt); free(bprint_fmt);
@ -4812,8 +4833,8 @@ int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
msg = strerror_r(errnum, buf, buflen); msg = strerror_r(errnum, buf, buflen);
if (msg != buf) { if (msg != buf) {
size_t len = strlen(msg); size_t len = strlen(msg);
char *c = mempcpy(buf, msg, min(buflen-1, len)); memcpy(buf, msg, min(buflen - 1, len));
*c = '\0'; *(buf + min(buflen - 1, len)) = '\0';
} }
return 0; return 0;
} }
@ -5059,6 +5080,7 @@ int pevent_register_print_function(struct pevent *pevent,
struct pevent_func_params *param; struct pevent_func_params *param;
enum pevent_func_arg_type type; enum pevent_func_arg_type type;
va_list ap; va_list ap;
int ret;
func_handle = find_func_handler(pevent, name); func_handle = find_func_handler(pevent, name);
if (func_handle) { if (func_handle) {
@ -5071,14 +5093,21 @@ int pevent_register_print_function(struct pevent *pevent,
remove_func_handler(pevent, name); remove_func_handler(pevent, name);
} }
func_handle = malloc_or_die(sizeof(*func_handle)); func_handle = malloc(sizeof(*func_handle));
if (!func_handle) {
do_warning("Failed to allocate function handler");
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
}
memset(func_handle, 0, sizeof(*func_handle)); memset(func_handle, 0, sizeof(*func_handle));
func_handle->ret_type = ret_type; func_handle->ret_type = ret_type;
func_handle->name = strdup(name); func_handle->name = strdup(name);
func_handle->func = func; func_handle->func = func;
if (!func_handle->name) if (!func_handle->name) {
die("Failed to allocate function name"); do_warning("Failed to allocate function name");
free(func_handle);
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
}
next_param = &(func_handle->params); next_param = &(func_handle->params);
va_start(ap, name); va_start(ap, name);
@ -5088,11 +5117,17 @@ int pevent_register_print_function(struct pevent *pevent,
break; break;
if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) { if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) {
warning("Invalid argument type %d", type); do_warning("Invalid argument type %d", type);
ret = PEVENT_ERRNO__INVALID_ARG_TYPE;
goto out_free; goto out_free;
} }
param = malloc_or_die(sizeof(*param)); param = malloc(sizeof(*param));
if (!param) {
do_warning("Failed to allocate function param");
ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
goto out_free;
}
param->type = type; param->type = type;
param->next = NULL; param->next = NULL;
@ -5110,7 +5145,7 @@ int pevent_register_print_function(struct pevent *pevent,
out_free: out_free:
va_end(ap); va_end(ap);
free_func_handle(func_handle); free_func_handle(func_handle);
return -1; return ret;
} }
/** /**
@ -5162,7 +5197,12 @@ int pevent_register_event_handler(struct pevent *pevent,
not_found: not_found:
/* Save for later use. */ /* Save for later use. */
handle = malloc_or_die(sizeof(*handle)); handle = malloc(sizeof(*handle));
if (!handle) {
do_warning("Failed to allocate event handler");
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
}
memset(handle, 0, sizeof(*handle)); memset(handle, 0, sizeof(*handle));
handle->id = id; handle->id = id;
if (event_name) if (event_name)
@ -5172,7 +5212,11 @@ int pevent_register_event_handler(struct pevent *pevent,
if ((event_name && !handle->event_name) || if ((event_name && !handle->event_name) ||
(sys_name && !handle->sys_name)) { (sys_name && !handle->sys_name)) {
die("Failed to allocate event/sys name"); do_warning("Failed to allocate event/sys name");
free((void *)handle->event_name);
free((void *)handle->sys_name);
free(handle);
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
} }
handle->func = func; handle->func = func;

View File

@ -351,7 +351,8 @@ enum pevent_flag {
_PE(READ_ID_FAILED, "failed to read event id"), \ _PE(READ_ID_FAILED, "failed to read event id"), \
_PE(READ_FORMAT_FAILED, "failed to read event format"), \ _PE(READ_FORMAT_FAILED, "failed to read event format"), \
_PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \
_PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace") _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\
_PE(INVALID_ARG_TYPE, "invalid argument type")
#undef _PE #undef _PE
#define _PE(__code, __str) PEVENT_ERRNO__ ## __code #define _PE(__code, __str) PEVENT_ERRNO__ ## __code

View File

@ -21,3 +21,5 @@ config.mak
config.mak.autogen config.mak.autogen
*-bison.* *-bison.*
*-flex.* *-flex.*
*.pyc
*.pyo

View File

@ -17,6 +17,9 @@ captured via perf record.
If no parameters are passed it will assume perf.data.old and perf.data. If no parameters are passed it will assume perf.data.old and perf.data.
The differential profile is displayed only for events matching both
specified perf.data files.
OPTIONS OPTIONS
------- -------
-M:: -M::

View File

@ -755,6 +755,14 @@ else
endif endif
endif endif
ifdef NO_BACKTRACE
BASIC_CFLAGS += -DNO_BACKTRACE
else
ifneq ($(call try-cc,$(SOURCE_BACKTRACE),),y)
BASIC_CFLAGS += -DNO_BACKTRACE
endif
endif
ifdef ASCIIDOC8 ifdef ASCIIDOC8
export ASCIIDOC8 export ASCIIDOC8
endif endif

View File

@ -10,6 +10,7 @@
#include "util/event.h" #include "util/event.h"
#include "util/hist.h" #include "util/hist.h"
#include "util/evsel.h" #include "util/evsel.h"
#include "util/evlist.h"
#include "util/session.h" #include "util/session.h"
#include "util/tool.h" #include "util/tool.h"
#include "util/sort.h" #include "util/sort.h"
@ -24,11 +25,6 @@ static char diff__default_sort_order[] = "dso,symbol";
static bool force; static bool force;
static bool show_displacement; static bool show_displacement;
struct perf_diff {
struct perf_tool tool;
struct perf_session *session;
};
static int hists__add_entry(struct hists *self, static int hists__add_entry(struct hists *self,
struct addr_location *al, u64 period) struct addr_location *al, u64 period)
{ {
@ -37,14 +33,12 @@ static int hists__add_entry(struct hists *self,
return -ENOMEM; return -ENOMEM;
} }
static int diff__process_sample_event(struct perf_tool *tool, static int diff__process_sample_event(struct perf_tool *tool __used,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel __used, struct perf_evsel *evsel,
struct machine *machine) struct machine *machine)
{ {
struct perf_diff *_diff = container_of(tool, struct perf_diff, tool);
struct perf_session *session = _diff->session;
struct addr_location al; struct addr_location al;
if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
@ -56,26 +50,24 @@ static int diff__process_sample_event(struct perf_tool *tool,
if (al.filtered || al.sym == NULL) if (al.filtered || al.sym == NULL)
return 0; return 0;
if (hists__add_entry(&session->hists, &al, sample->period)) { if (hists__add_entry(&evsel->hists, &al, sample->period)) {
pr_warning("problem incrementing symbol period, skipping event\n"); pr_warning("problem incrementing symbol period, skipping event\n");
return -1; return -1;
} }
session->hists.stats.total_period += sample->period; evsel->hists.stats.total_period += sample->period;
return 0; return 0;
} }
static struct perf_diff diff = { static struct perf_tool tool = {
.tool = { .sample = diff__process_sample_event,
.sample = diff__process_sample_event, .mmap = perf_event__process_mmap,
.mmap = perf_event__process_mmap, .comm = perf_event__process_comm,
.comm = perf_event__process_comm, .exit = perf_event__process_task,
.exit = perf_event__process_task, .fork = perf_event__process_task,
.fork = perf_event__process_task, .lost = perf_event__process_lost,
.lost = perf_event__process_lost, .ordered_samples = true,
.ordered_samples = true, .ordering_requires_timestamps = true,
.ordering_requires_timestamps = true,
},
}; };
static void perf_session__insert_hist_entry_by_name(struct rb_root *root, static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@ -146,34 +138,71 @@ static void hists__match(struct hists *older, struct hists *newer)
} }
} }
static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
struct perf_evlist *evlist)
{
struct perf_evsel *e;
list_for_each_entry(e, &evlist->entries, node)
if (perf_evsel__match2(evsel, e))
return e;
return NULL;
}
static int __cmd_diff(void) static int __cmd_diff(void)
{ {
int ret, i; int ret, i;
#define older (session[0]) #define older (session[0])
#define newer (session[1]) #define newer (session[1])
struct perf_session *session[2]; struct perf_session *session[2];
struct perf_evlist *evlist_new, *evlist_old;
struct perf_evsel *evsel;
bool first = true;
older = perf_session__new(input_old, O_RDONLY, force, false, older = perf_session__new(input_old, O_RDONLY, force, false,
&diff.tool); &tool);
newer = perf_session__new(input_new, O_RDONLY, force, false, newer = perf_session__new(input_new, O_RDONLY, force, false,
&diff.tool); &tool);
if (session[0] == NULL || session[1] == NULL) if (session[0] == NULL || session[1] == NULL)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < 2; ++i) { for (i = 0; i < 2; ++i) {
diff.session = session[i]; ret = perf_session__process_events(session[i], &tool);
ret = perf_session__process_events(session[i], &diff.tool);
if (ret) if (ret)
goto out_delete; goto out_delete;
hists__output_resort(&session[i]->hists);
} }
if (show_displacement) evlist_old = older->evlist;
hists__resort_entries(&older->hists); evlist_new = newer->evlist;
list_for_each_entry(evsel, &evlist_new->entries, node)
hists__output_resort(&evsel->hists);
list_for_each_entry(evsel, &evlist_old->entries, node) {
hists__output_resort(&evsel->hists);
if (show_displacement)
hists__resort_entries(&evsel->hists);
}
list_for_each_entry(evsel, &evlist_new->entries, node) {
struct perf_evsel *evsel_old;
evsel_old = evsel_match(evsel, evlist_old);
if (!evsel_old)
continue;
fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
perf_evsel__name(evsel));
first = false;
hists__match(&evsel_old->hists, &evsel->hists);
hists__fprintf(&evsel->hists, &evsel_old->hists,
show_displacement, true, 0, 0, stdout);
}
hists__match(&older->hists, &newer->hists);
hists__fprintf(&newer->hists, &older->hists,
show_displacement, true, 0, 0, stdout);
out_delete: out_delete:
for (i = 0; i < 2; ++i) for (i = 0; i < 2; ++i)
perf_session__delete(session[i]); perf_session__delete(session[i]);

View File

@ -179,3 +179,17 @@ int main(void)
} }
endef endef
endif endif
ifndef NO_BACKTRACE
define SOURCE_BACKTRACE
#include <execinfo.h>
#include <stdio.h>
int main(void)
{
backtrace(NULL, 0);
backtrace_symbols(NULL, 0);
return 0;
}
endef
endif

View File

@ -14,6 +14,7 @@
#include "util/run-command.h" #include "util/run-command.h"
#include "util/parse-events.h" #include "util/parse-events.h"
#include "util/debugfs.h" #include "util/debugfs.h"
#include <pthread.h>
const char perf_usage_string[] = const char perf_usage_string[] =
"perf [--version] [--help] COMMAND [ARGS]"; "perf [--version] [--help] COMMAND [ARGS]";

View File

@ -7,6 +7,7 @@
#include "symbol.h" #include "symbol.h"
#include <linux/list.h> #include <linux/list.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <pthread.h>
struct ins; struct ins;

View File

@ -23,7 +23,7 @@ static char *test_file(int size)
int fd, i; int fd, i;
unsigned char *buf; unsigned char *buf;
fd = mkostemp(templ, O_CREAT|O_WRONLY|O_TRUNC); fd = mkstemp(templ);
buf = malloc(size); buf = malloc(size);
if (!buf) { if (!buf) {

View File

@ -124,6 +124,13 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
(evsel->attr.type == PERF_TYPE_##t && \ (evsel->attr.type == PERF_TYPE_##t && \
evsel->attr.config == PERF_COUNT_##c) evsel->attr.config == PERF_COUNT_##c)
static inline bool perf_evsel__match2(struct perf_evsel *e1,
struct perf_evsel *e2)
{
return (e1->attr.type == e2->attr.type) &&
(e1->attr.config == e2->attr.config);
}
int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
int cpu, int thread, bool scale); int cpu, int thread, bool scale);

View File

@ -3,6 +3,7 @@
#include "exec_cmd.h" #include "exec_cmd.h"
#include "levenshtein.h" #include "levenshtein.h"
#include "help.h" #include "help.h"
#include <termios.h>
void add_cmdname(struct cmdnames *cmds, const char *name, size_t len) void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
{ {

View File

@ -1 +1,2 @@
#include <stdbool.h>
#include "../../../../include/linux/rbtree.h" #include "../../../../include/linux/rbtree.h"

View File

@ -36,9 +36,7 @@ struct perf_session {
struct pevent *pevent; struct pevent *pevent;
/* /*
* FIXME: Need to split this up further, we need global * FIXME: Need to split this up further, we need global
* stats + per event stats. 'perf diff' also needs * stats + per event stats.
* to properly support multiple events in a single
* perf.data file.
*/ */
struct hists hists; struct hists hists;
int fd; int fd;

View File

@ -12,8 +12,6 @@ int sort__branch_mode = -1; /* -1 = means not set */
enum sort_type sort__first_dimension; enum sort_type sort__first_dimension;
char * field_sep;
LIST_HEAD(hist_entry__sort_list); LIST_HEAD(hist_entry__sort_list);
static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
@ -23,11 +21,11 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
va_start(ap, fmt); va_start(ap, fmt);
n = vsnprintf(bf, size, fmt, ap); n = vsnprintf(bf, size, fmt, ap);
if (field_sep && n > 0) { if (symbol_conf.field_sep && n > 0) {
char *sep = bf; char *sep = bf;
while (1) { while (1) {
sep = strchr(sep, *field_sep); sep = strchr(sep, *symbol_conf.field_sep);
if (sep == NULL) if (sep == NULL)
break; break;
*sep = '.'; *sep = '.';

View File

@ -32,7 +32,6 @@ extern const char default_sort_order[];
extern int sort__need_collapse; extern int sort__need_collapse;
extern int sort__has_parent; extern int sort__has_parent;
extern int sort__branch_mode; extern int sort__branch_mode;
extern char *field_sep;
extern struct sort_entry sort_comm; extern struct sort_entry sort_comm;
extern struct sort_entry sort_dso; extern struct sort_entry sort_dso;
extern struct sort_entry sort_sym; extern struct sort_entry sort_sym;

View File

@ -10,6 +10,9 @@
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <stdio.h> #include <stdio.h>
#include <byteswap.h> #include <byteswap.h>
#if defined(__BIONIC__)
#include <libgen.h>
#endif
#ifndef NO_LIBELF_SUPPORT #ifndef NO_LIBELF_SUPPORT
#include <libelf.h> #include <libelf.h>

View File

@ -5,6 +5,7 @@
#include "types.h" #include "types.h"
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <termios.h>
struct perf_evlist; struct perf_evlist;
struct perf_evsel; struct perf_evsel;

View File

@ -1,7 +1,9 @@
#include "../perf.h" #include "../perf.h"
#include "util.h" #include "util.h"
#include <sys/mman.h> #include <sys/mman.h>
#ifndef NO_BACKTRACE
#include <execinfo.h> #include <execinfo.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -163,6 +165,7 @@ size_t hex_width(u64 v)
} }
/* Obtain a backtrace and print it to stdout. */ /* Obtain a backtrace and print it to stdout. */
#ifndef NO_BACKTRACE
void dump_stack(void) void dump_stack(void)
{ {
void *array[16]; void *array[16];
@ -177,3 +180,6 @@ void dump_stack(void)
free(strings); free(strings);
} }
#else
void dump_stack(void) {}
#endif