Commit da758dde authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perfcounters-fixes-for-linus' of...

Merge branch 'perfcounters-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'perfcounters-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  perf_counter: Fix double list iteration in per task precise stats
  perf: Auto-detect libelf
  perf symbol: Fix symbol parsing in certain cases: use the build-id as a symlink
  perf_counter/powerpc: Check oprofile_cpu_type for NULL before using it
  ftrace: Fix perf-tracepoint OOPS
  perf report: Add missing command line options to man page
  perf: Auto-detect libbfd
  perf report: Make --sort comm,dso,symbol the default
parents 389623fe 1054598c
...@@ -407,7 +407,8 @@ struct power_pmu mpc7450_pmu = { ...@@ -407,7 +407,8 @@ struct power_pmu mpc7450_pmu = {
static int init_mpc7450_pmu(void) static int init_mpc7450_pmu(void)
{ {
if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450")) if (!cur_cpu_spec->oprofile_cpu_type ||
strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450"))
return -ENODEV; return -ENODEV;
return register_power_pmu(&mpc7450_pmu); return register_power_pmu(&mpc7450_pmu);
......
...@@ -606,7 +606,8 @@ static struct power_pmu power4_pmu = { ...@@ -606,7 +606,8 @@ static struct power_pmu power4_pmu = {
static int init_power4_pmu(void) static int init_power4_pmu(void)
{ {
if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4")) if (!cur_cpu_spec->oprofile_cpu_type ||
strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4"))
return -ENODEV; return -ENODEV;
return register_power_pmu(&power4_pmu); return register_power_pmu(&power4_pmu);
......
...@@ -678,8 +678,9 @@ static struct power_pmu power5p_pmu = { ...@@ -678,8 +678,9 @@ static struct power_pmu power5p_pmu = {
static int init_power5p_pmu(void) static int init_power5p_pmu(void)
{ {
if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5+") if (!cur_cpu_spec->oprofile_cpu_type ||
&& strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5++")) (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5+")
&& strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5++")))
return -ENODEV; return -ENODEV;
return register_power_pmu(&power5p_pmu); return register_power_pmu(&power5p_pmu);
......
...@@ -618,7 +618,8 @@ static struct power_pmu power5_pmu = { ...@@ -618,7 +618,8 @@ static struct power_pmu power5_pmu = {
static int init_power5_pmu(void) static int init_power5_pmu(void)
{ {
if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5")) if (!cur_cpu_spec->oprofile_cpu_type ||
strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5"))
return -ENODEV; return -ENODEV;
return register_power_pmu(&power5_pmu); return register_power_pmu(&power5_pmu);
......
...@@ -537,7 +537,8 @@ static struct power_pmu power6_pmu = { ...@@ -537,7 +537,8 @@ static struct power_pmu power6_pmu = {
static int init_power6_pmu(void) static int init_power6_pmu(void)
{ {
if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6")) if (!cur_cpu_spec->oprofile_cpu_type ||
strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6"))
return -ENODEV; return -ENODEV;
return register_power_pmu(&power6_pmu); return register_power_pmu(&power6_pmu);
......
...@@ -366,7 +366,8 @@ static struct power_pmu power7_pmu = { ...@@ -366,7 +366,8 @@ static struct power_pmu power7_pmu = {
static int init_power7_pmu(void) static int init_power7_pmu(void)
{ {
if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7")) if (!cur_cpu_spec->oprofile_cpu_type ||
strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7"))
return -ENODEV; return -ENODEV;
return register_power_pmu(&power7_pmu); return register_power_pmu(&power7_pmu);
......
...@@ -488,8 +488,9 @@ static struct power_pmu ppc970_pmu = { ...@@ -488,8 +488,9 @@ static struct power_pmu ppc970_pmu = {
static int init_ppc970_pmu(void) static int init_ppc970_pmu(void)
{ {
if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970") if (!cur_cpu_spec->oprofile_cpu_type ||
&& strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")) (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970")
&& strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")))
return -ENODEV; return -ENODEV;
return register_power_pmu(&ppc970_pmu); return register_power_pmu(&ppc970_pmu);
......
...@@ -119,11 +119,9 @@ struct ftrace_event_call { ...@@ -119,11 +119,9 @@ struct ftrace_event_call {
void *filter; void *filter;
void *mod; void *mod;
#ifdef CONFIG_EVENT_PROFILE atomic_t profile_count;
atomic_t profile_count; int (*profile_enable)(struct ftrace_event_call *);
int (*profile_enable)(struct ftrace_event_call *); void (*profile_disable)(struct ftrace_event_call *);
void (*profile_disable)(struct ftrace_event_call *);
#endif
}; };
#define MAX_FILTER_PRED 32 #define MAX_FILTER_PRED 32
......
...@@ -1104,7 +1104,7 @@ static void perf_counter_sync_stat(struct perf_counter_context *ctx, ...@@ -1104,7 +1104,7 @@ static void perf_counter_sync_stat(struct perf_counter_context *ctx,
__perf_counter_sync_stat(counter, next_counter); __perf_counter_sync_stat(counter, next_counter);
counter = list_next_entry(counter, event_entry); counter = list_next_entry(counter, event_entry);
next_counter = list_next_entry(counter, event_entry); next_counter = list_next_entry(next_counter, event_entry);
} }
} }
......
...@@ -14,7 +14,7 @@ int ftrace_profile_enable(int event_id) ...@@ -14,7 +14,7 @@ int ftrace_profile_enable(int event_id)
mutex_lock(&event_mutex); mutex_lock(&event_mutex);
list_for_each_entry(event, &ftrace_events, list) { list_for_each_entry(event, &ftrace_events, list) {
if (event->id == event_id) { if (event->id == event_id && event->profile_enable) {
ret = event->profile_enable(event); ret = event->profile_enable(event);
break; break;
} }
......
...@@ -940,7 +940,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, ...@@ -940,7 +940,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
entry = trace_create_file("enable", 0644, call->dir, call, entry = trace_create_file("enable", 0644, call->dir, call,
enable); enable);
if (call->id) if (call->id && call->profile_enable)
entry = trace_create_file("id", 0444, call->dir, call, entry = trace_create_file("id", 0444, call->dir, call,
id); id);
......
...@@ -29,13 +29,67 @@ OPTIONS ...@@ -29,13 +29,67 @@ OPTIONS
Select the PMU event. Selection can be a symbolic event name Select the PMU event. Selection can be a symbolic event name
(use 'perf list' to list all events) or a raw PMU (use 'perf list' to list all events) or a raw PMU
event (eventsel+umask) in the form of rNNN where NNN is a event (eventsel+umask) in the form of rNNN where NNN is a
hexadecimal event descriptor. hexadecimal event descriptor.
-a:: -a::
system-wide collection System-wide collection.
-l:: -l::
scale counter values Scale counter values.
-p::
--pid=::
Record events on existing pid.
-r::
--realtime=::
Collect data with this RT SCHED_FIFO priority.
-A::
--append::
Append to the output file to do incremental profiling.
-f::
--force::
Overwrite existing data file.
-c::
--count=::
Event period to sample.
-o::
--output=::
Output file name.
-i::
--inherit::
Child tasks inherit counters.
-F::
--freq=::
Profile at this frequency.
-m::
--mmap-pages=::
Number of mmap data pages.
-g::
--call-graph::
Do call-graph (stack chain/backtrace) recording.
-v::
--verbose::
Be more verbose (show counter open errors, etc).
-s::
--stat::
Per thread counts.
-d::
--data::
Sample addresses.
-n::
--no-samples::
Don't sample.
SEE ALSO SEE ALSO
-------- --------
......
...@@ -158,8 +158,10 @@ uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') ...@@ -158,8 +158,10 @@ uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
# If we're on a 64-bit kernel, use -m64 # If we're on a 64-bit kernel, use -m64
ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M)) ifndef NO_64BIT
M64 := -m64 ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
M64 := -m64
endif
endif endif
# CFLAGS and LDFLAGS are for the users to override from the command line. # CFLAGS and LDFLAGS are for the users to override from the command line.
...@@ -345,7 +347,6 @@ BUILTIN_OBJS += builtin-stat.o ...@@ -345,7 +347,6 @@ BUILTIN_OBJS += builtin-stat.o
BUILTIN_OBJS += builtin-top.o BUILTIN_OBJS += builtin-top.o
PERFLIBS = $(LIB_FILE) PERFLIBS = $(LIB_FILE)
EXTLIBS = -lbfd -liberty
# #
# Platform specific tweaks # Platform specific tweaks
...@@ -374,6 +375,28 @@ ifeq ($(uname_S),Darwin) ...@@ -374,6 +375,28 @@ ifeq ($(uname_S),Darwin)
PTHREAD_LIBS = PTHREAD_LIBS =
endif endif
ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
endif
ifdef NO_DEMANGLE
BASIC_CFLAGS += -DNO_DEMANGLE
else
has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd > /dev/null 2>&1 && echo y")
has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y")
ifeq ($(has_bfd),y)
EXTLIBS += -lbfd
else ifeq ($(has_bfd_iberty),y)
EXTLIBS += -lbfd -liberty
else
msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling)
BASIC_CFLAGS += -DNO_DEMANGLE
endif
endif
ifndef CC_LD_DYNPATH ifndef CC_LD_DYNPATH
ifdef NO_R_TO_GCC_LINKER ifdef NO_R_TO_GCC_LINKER
# Some gcc does not accept and pass -R to the linker to specify # Some gcc does not accept and pass -R to the linker to specify
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
static char const *input_name = "perf.data"; static char const *input_name = "perf.data";
static char *vmlinux = NULL; static char *vmlinux = NULL;
static char default_sort_order[] = "comm,dso"; static char default_sort_order[] = "comm,dso,symbol";
static char *sort_order = default_sort_order; static char *sort_order = default_sort_order;
static char *dso_list_str, *comm_list_str, *sym_list_str, static char *dso_list_str, *comm_list_str, *sym_list_str,
*col_width_list_str; *col_width_list_str;
...@@ -1424,7 +1424,7 @@ static size_t output__fprintf(FILE *fp, u64 total_samples) ...@@ -1424,7 +1424,7 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
if (sort_order == default_sort_order && if (sort_order == default_sort_order &&
parent_pattern == default_parent_pattern) { parent_pattern == default_parent_pattern) {
fprintf(fp, "#\n"); fprintf(fp, "#\n");
fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
fprintf(fp, "#\n"); fprintf(fp, "#\n");
} }
fprintf(fp, "\n"); fprintf(fp, "\n");
......
...@@ -6,7 +6,16 @@ ...@@ -6,7 +6,16 @@
#include <libelf.h> #include <libelf.h>
#include <gelf.h> #include <gelf.h>
#include <elf.h> #include <elf.h>
#ifndef NO_DEMANGLE
#include <bfd.h> #include <bfd.h>
#else
static inline
char *bfd_demangle(void __used *v, const char __used *c, int __used i)
{
return NULL;
}
#endif
const char *sym_hist_filter; const char *sym_hist_filter;
...@@ -652,10 +661,69 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, ...@@ -652,10 +661,69 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
return err; return err;
} }
#define BUILD_ID_SIZE 128
static char *dso__read_build_id(struct dso *self, int verbose)
{
int i;
GElf_Ehdr ehdr;
GElf_Shdr shdr;
Elf_Data *build_id_data;
Elf_Scn *sec;
char *build_id = NULL, *bid;
unsigned char *raw;
Elf *elf;
int fd = open(self->name, O_RDONLY);
if (fd < 0)
goto out;
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
if (elf == NULL) {
if (verbose)
fprintf(stderr, "%s: cannot read %s ELF file.\n",
__func__, self->name);
goto out_close;
}
if (gelf_getehdr(elf, &ehdr) == NULL) {
if (verbose)
fprintf(stderr, "%s: cannot get elf header.\n", __func__);
goto out_elf_end;
}
sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
if (sec == NULL)
goto out_elf_end;
build_id_data = elf_getdata(sec, NULL);
if (build_id_data == NULL)
goto out_elf_end;
build_id = malloc(BUILD_ID_SIZE);
if (build_id == NULL)
goto out_elf_end;
raw = build_id_data->d_buf + 16;
bid = build_id;
for (i = 0; i < 20; ++i) {
sprintf(bid, "%02x", *raw);
++raw;
bid += 2;
}
if (verbose)
printf("%s(%s): %s\n", __func__, self->name, build_id);
out_elf_end:
elf_end(elf);
out_close:
close(fd);
out:
return build_id;
}
int dso__load(struct dso *self, symbol_filter_t filter, int verbose) int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
{ {
int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); int size = PATH_MAX;
char *name = malloc(size); char *name = malloc(size), *build_id = NULL;
int variant = 0; int variant = 0;
int ret = -1; int ret = -1;
int fd; int fd;
...@@ -677,7 +745,18 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose) ...@@ -677,7 +745,18 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
case 1: /* Ubuntu */ case 1: /* Ubuntu */
snprintf(name, size, "/usr/lib/debug%s", self->name); snprintf(name, size, "/usr/lib/debug%s", self->name);
break; break;
case 2: /* Sane people */ case 2:
build_id = dso__read_build_id(self, verbose);
if (build_id != NULL) {
snprintf(name, size,
"/usr/lib/debug/.build-id/%.2s/%s.debug",
build_id, build_id + 2);
free(build_id);
break;
}
variant++;
/* Fall thru */
case 3: /* Sane people */
snprintf(name, size, "%s", self->name); snprintf(name, size, "%s", self->name);
break; break;
......
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