aboutsummaryrefslogtreecommitdiff
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-record.txt60
-rw-r--r--tools/perf/Makefile29
-rw-r--r--tools/perf/builtin-report.c4
-rw-r--r--tools/perf/util/symbol.c85
4 files changed, 167 insertions, 11 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 1dbc1eeb4c0..6be696b0a2b 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -29,13 +29,67 @@ OPTIONS
Select the PMU event. Selection can be a symbolic event name
(use 'perf list' to list all events) or a raw PMU
event (eventsel+umask) in the form of rNNN where NNN is a
- hexadecimal event descriptor.
+ hexadecimal event descriptor.
-a::
- system-wide collection
+ System-wide collection.
-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
--------
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 4b20fa47c3a..1916e44b9bb 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -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')
# If we're on a 64-bit kernel, use -m64
-ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
- M64 := -m64
+ifndef NO_64BIT
+ ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
+ M64 := -m64
+ endif
endif
# CFLAGS and LDFLAGS are for the users to override from the command line.
@@ -345,7 +347,6 @@ BUILTIN_OBJS += builtin-stat.o
BUILTIN_OBJS += builtin-top.o
PERFLIBS = $(LIB_FILE)
-EXTLIBS = -lbfd -liberty
#
# Platform specific tweaks
@@ -374,6 +375,28 @@ ifeq ($(uname_S),Darwin)
PTHREAD_LIBS =
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
ifdef NO_R_TO_GCC_LINKER
# Some gcc does not accept and pass -R to the linker to specify
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index ce4f28645e6..8cb58d68a00 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -31,7 +31,7 @@
static char const *input_name = "perf.data";
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 *dso_list_str, *comm_list_str, *sym_list_str,
*col_width_list_str;
@@ -1424,7 +1424,7 @@ print_entries:
if (sort_order == default_sort_order &&
parent_pattern == default_parent_pattern) {
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");
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b4fe0579bd6..16ddca20294 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -6,7 +6,16 @@
#include <libelf.h>
#include <gelf.h>
#include <elf.h>
+
+#ifndef NO_DEMANGLE
#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;
@@ -652,10 +661,69 @@ out_close:
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 size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
- char *name = malloc(size);
+ int size = PATH_MAX;
+ char *name = malloc(size), *build_id = NULL;
int variant = 0;
int ret = -1;
int fd;
@@ -677,7 +745,18 @@ more:
case 1: /* Ubuntu */
snprintf(name, size, "/usr/lib/debug%s", self->name);
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);
break;