2009-12-27 23:38:01

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 01/10] perf record: We should fork only if a program was specified to run

From: Arnaldo Carvalho de Melo <[email protected]>

IOW: Now 'perf record -a' works, this was a bug introduced in:

856e96608a72412d319e498a3a7c557571f811bd
"perf record: Properly synchronize child creation"

Also fix the -C usage, i.e. allow for profiling all the tasks in one
CPU.

Reported-by: Pekka Enberg <[email protected]>
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-record.c | 14 ++++++++------
1 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 63136d0..2654253 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -402,7 +402,7 @@ static void atexit_header(void)
perf_header__write(&session->header, output, true);
}

-static int __cmd_record(int argc __used, const char **argv)
+static int __cmd_record(int argc, const char **argv)
{
int i, counter;
struct stat st;
@@ -411,6 +411,7 @@ static int __cmd_record(int argc __used, const char **argv)
int err;
unsigned long waking = 0;
int child_ready_pipe[2], go_pipe[2];
+ const bool forks = target_pid == -1 && argc > 0;
char buf;

page_size = sysconf(_SC_PAGE_SIZE);
@@ -422,7 +423,7 @@ static int __cmd_record(int argc __used, const char **argv)
signal(SIGCHLD, sig_handler);
signal(SIGINT, sig_handler);

- if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
+ if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
perror("failed to create pipes");
exit(-1);
}
@@ -483,7 +484,7 @@ static int __cmd_record(int argc __used, const char **argv)

atexit(atexit_header);

- if (target_pid == -1) {
+ if (forks) {
pid = fork();
if (pid < 0) {
perror("failed to fork");
@@ -550,7 +551,7 @@ static int __cmd_record(int argc __used, const char **argv)
return err;
}

- if (!system_wide)
+ if (!system_wide && profile_cpu == -1)
event__synthesize_thread(pid, process_synthesized_event,
session);
else
@@ -569,7 +570,8 @@ static int __cmd_record(int argc __used, const char **argv)
/*
* Let the child rip
*/
- close(go_pipe[1]);
+ if (forks)
+ close(go_pipe[1]);

for (;;) {
int hits = samples;
@@ -667,7 +669,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)

argc = parse_options(argc, argv, options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
- if (!argc && target_pid == -1 && (!system_wide || profile_cpu == -1))
+ if (!argc && target_pid == -1 && !system_wide && profile_cpu == -1)
usage_with_options(record_usage, options);

symbol__init();
--
1.6.2.5


2009-12-27 23:37:43

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 02/10] perf tools: Add missing header files to LIB_H Makefile variable

From: Arnaldo Carvalho de Melo <[email protected]>

So that changes in them trigger rebuilds, like when we're doing bisects.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 4390d22..652a470 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -343,13 +343,18 @@ LIB_H += util/include/linux/string.h
LIB_H += util/include/linux/types.h
LIB_H += util/include/asm/asm-offsets.h
LIB_H += util/include/asm/bitops.h
+LIB_H += util/include/asm/bug.h
LIB_H += util/include/asm/byteorder.h
LIB_H += util/include/asm/swab.h
LIB_H += util/include/asm/system.h
LIB_H += util/include/asm/uaccess.h
LIB_H += perf.h
+LIB_H += util/cache.h
+LIB_H += util/callchain.h
+LIB_H += util/debug.h
LIB_H += util/debugfs.h
LIB_H += util/event.h
+LIB_H += util/exec_cmd.h
LIB_H += util/types.h
LIB_H += util/levenshtein.h
LIB_H += util/parse-options.h
@@ -362,6 +367,7 @@ LIB_H += util/session.h
LIB_H += util/strbuf.h
LIB_H += util/string.h
LIB_H += util/strlist.h
+LIB_H += util/svghelper.h
LIB_H += util/run-command.h
LIB_H += util/sigchain.h
LIB_H += util/symbol.h
@@ -370,6 +376,8 @@ LIB_H += util/values.h
LIB_H += util/sort.h
LIB_H += util/hist.h
LIB_H += util/thread.h
+LIB_H += util/trace-event.h
+LIB_H += util/trace-event-perl.h
LIB_H += util/probe-finder.h
LIB_H += util/probe-event.h

--
1.6.2.5

2009-12-27 23:38:53

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 03/10] perf session: Move the event processing routines to session.c

From: Arnaldo Carvalho de Melo <[email protected]>

No need for an extra "data_map" file since the routines there operate
mainly on a perf_session instance.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile | 1 -
tools/perf/util/data_map.c | 252 --------------------------------------------
tools/perf/util/session.c | 245 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 245 insertions(+), 253 deletions(-)
delete mode 100644 tools/perf/util/data_map.c

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 652a470..4172c3b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -423,7 +423,6 @@ LIB_OBJS += util/trace-event-perl.o
LIB_OBJS += util/svghelper.o
LIB_OBJS += util/sort.o
LIB_OBJS += util/hist.o
-LIB_OBJS += util/data_map.o
LIB_OBJS += util/probe-event.o

BUILTIN_OBJS += builtin-annotate.o
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
deleted file mode 100644
index b557b83..0000000
--- a/tools/perf/util/data_map.c
+++ /dev/null
@@ -1,252 +0,0 @@
-#include "symbol.h"
-#include "util.h"
-#include "debug.h"
-#include "thread.h"
-#include "session.h"
-
-static int process_event_stub(event_t *event __used,
- struct perf_session *session __used)
-{
- dump_printf(": unhandled!\n");
- return 0;
-}
-
-static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
-{
- if (!handler->process_sample_event)
- handler->process_sample_event = process_event_stub;
- if (!handler->process_mmap_event)
- handler->process_mmap_event = process_event_stub;
- if (!handler->process_comm_event)
- handler->process_comm_event = process_event_stub;
- if (!handler->process_fork_event)
- handler->process_fork_event = process_event_stub;
- if (!handler->process_exit_event)
- handler->process_exit_event = process_event_stub;
- if (!handler->process_lost_event)
- handler->process_lost_event = process_event_stub;
- if (!handler->process_read_event)
- handler->process_read_event = process_event_stub;
- if (!handler->process_throttle_event)
- handler->process_throttle_event = process_event_stub;
- if (!handler->process_unthrottle_event)
- handler->process_unthrottle_event = process_event_stub;
-}
-
-static const char *event__name[] = {
- [0] = "TOTAL",
- [PERF_RECORD_MMAP] = "MMAP",
- [PERF_RECORD_LOST] = "LOST",
- [PERF_RECORD_COMM] = "COMM",
- [PERF_RECORD_EXIT] = "EXIT",
- [PERF_RECORD_THROTTLE] = "THROTTLE",
- [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
- [PERF_RECORD_FORK] = "FORK",
- [PERF_RECORD_READ] = "READ",
- [PERF_RECORD_SAMPLE] = "SAMPLE",
-};
-
-unsigned long event__total[PERF_RECORD_MAX];
-
-void event__print_totals(void)
-{
- int i;
- for (i = 0; i < PERF_RECORD_MAX; ++i)
- pr_info("%10s events: %10ld\n",
- event__name[i], event__total[i]);
-}
-
-static int process_event(event_t *event, struct perf_session *session,
- struct perf_event_ops *ops,
- unsigned long offset, unsigned long head)
-{
- trace_event(event);
-
- if (event->header.type < PERF_RECORD_MAX) {
- dump_printf("%p [%p]: PERF_RECORD_%s",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event__name[event->header.type]);
- ++event__total[0];
- ++event__total[event->header.type];
- }
-
- switch (event->header.type) {
- case PERF_RECORD_SAMPLE:
- return ops->process_sample_event(event, session);
- case PERF_RECORD_MMAP:
- return ops->process_mmap_event(event, session);
- case PERF_RECORD_COMM:
- return ops->process_comm_event(event, session);
- case PERF_RECORD_FORK:
- return ops->process_fork_event(event, session);
- case PERF_RECORD_EXIT:
- return ops->process_exit_event(event, session);
- case PERF_RECORD_LOST:
- return ops->process_lost_event(event, session);
- case PERF_RECORD_READ:
- return ops->process_read_event(event, session);
- case PERF_RECORD_THROTTLE:
- return ops->process_throttle_event(event, session);
- case PERF_RECORD_UNTHROTTLE:
- return ops->process_unthrottle_event(event, session);
- default:
- ops->total_unknown++;
- return -1;
- }
-}
-
-int perf_header__read_build_ids(int input, u64 offset, u64 size)
-{
- struct build_id_event bev;
- char filename[PATH_MAX];
- u64 limit = offset + size;
- int err = -1;
-
- while (offset < limit) {
- struct dso *dso;
- ssize_t len;
-
- if (read(input, &bev, sizeof(bev)) != sizeof(bev))
- goto out;
-
- len = bev.header.size - sizeof(bev);
- if (read(input, filename, len) != len)
- goto out;
-
- dso = dsos__findnew(filename);
- if (dso != NULL)
- dso__set_build_id(dso, &bev.build_id);
-
- offset += bev.header.size;
- }
- err = 0;
-out:
- return err;
-}
-
-static struct thread *perf_session__register_idle_thread(struct perf_session *self)
-{
- struct thread *thread = perf_session__findnew(self, 0);
-
- if (!thread || thread__set_comm(thread, "swapper")) {
- pr_err("problem inserting idle task.\n");
- thread = NULL;
- }
-
- return thread;
-}
-
-int perf_session__process_events(struct perf_session *self,
- struct perf_event_ops *ops)
-{
- int err;
- unsigned long head, shift;
- unsigned long offset = 0;
- size_t page_size;
- event_t *event;
- uint32_t size;
- char *buf;
-
- if (perf_session__register_idle_thread(self) == NULL)
- return -ENOMEM;
-
- perf_event_ops__fill_defaults(ops);
-
- page_size = getpagesize();
-
- head = self->header.data_offset;
- self->sample_type = perf_header__sample_type(&self->header);
-
- err = -EINVAL;
- if (ops->sample_type_check && ops->sample_type_check(self) < 0)
- goto out_err;
-
- if (!ops->full_paths) {
- char bf[PATH_MAX];
-
- if (getcwd(bf, sizeof(bf)) == NULL) {
- err = -errno;
-out_getcwd_err:
- pr_err("failed to get the current directory\n");
- goto out_err;
- }
- self->cwd = strdup(bf);
- if (self->cwd == NULL) {
- err = -ENOMEM;
- goto out_getcwd_err;
- }
- self->cwdlen = strlen(self->cwd);
- }
-
- shift = page_size * (head / page_size);
- offset += shift;
- head -= shift;
-
-remap:
- buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
- MAP_SHARED, self->fd, offset);
- if (buf == MAP_FAILED) {
- pr_err("failed to mmap file\n");
- err = -errno;
- goto out_err;
- }
-
-more:
- event = (event_t *)(buf + head);
-
- size = event->header.size;
- if (!size)
- size = 8;
-
- if (head + event->header.size >= page_size * self->mmap_window) {
- int munmap_ret;
-
- shift = page_size * (head / page_size);
-
- munmap_ret = munmap(buf, page_size * self->mmap_window);
- assert(munmap_ret == 0);
-
- offset += shift;
- head -= shift;
- goto remap;
- }
-
- size = event->header.size;
-
- dump_printf("\n%p [%p]: event: %d\n",
- (void *)(offset + head),
- (void *)(long)event->header.size,
- event->header.type);
-
- if (!size || process_event(event, self, ops, offset, head) < 0) {
-
- dump_printf("%p [%p]: skipping unknown header type: %d\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->header.type);
-
- /*
- * assume we lost track of the stream, check alignment, and
- * increment a single u64 in the hope to catch on again 'soon'.
- */
-
- if (unlikely(head & 7))
- head &= ~7ULL;
-
- size = 8;
- }
-
- head += size;
-
- if (offset + head >= self->header.data_offset + self->header.data_size)
- goto done;
-
- if (offset + head < self->size)
- goto more;
-
-done:
- err = 0;
-out_err:
- return err;
-}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ce3a6c8..736d4fd 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -148,3 +148,248 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,

return syms;
}
+
+static int process_event_stub(event_t *event __used,
+ struct perf_session *session __used)
+{
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
+static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
+{
+ if (handler->process_sample_event == NULL)
+ handler->process_sample_event = process_event_stub;
+ if (handler->process_mmap_event == NULL)
+ handler->process_mmap_event = process_event_stub;
+ if (handler->process_comm_event == NULL)
+ handler->process_comm_event = process_event_stub;
+ if (handler->process_fork_event == NULL)
+ handler->process_fork_event = process_event_stub;
+ if (handler->process_exit_event == NULL)
+ handler->process_exit_event = process_event_stub;
+ if (handler->process_lost_event == NULL)
+ handler->process_lost_event = process_event_stub;
+ if (handler->process_read_event == NULL)
+ handler->process_read_event = process_event_stub;
+ if (handler->process_throttle_event == NULL)
+ handler->process_throttle_event = process_event_stub;
+ if (handler->process_unthrottle_event == NULL)
+ handler->process_unthrottle_event = process_event_stub;
+}
+
+static const char *event__name[] = {
+ [0] = "TOTAL",
+ [PERF_RECORD_MMAP] = "MMAP",
+ [PERF_RECORD_LOST] = "LOST",
+ [PERF_RECORD_COMM] = "COMM",
+ [PERF_RECORD_EXIT] = "EXIT",
+ [PERF_RECORD_THROTTLE] = "THROTTLE",
+ [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
+ [PERF_RECORD_FORK] = "FORK",
+ [PERF_RECORD_READ] = "READ",
+ [PERF_RECORD_SAMPLE] = "SAMPLE",
+};
+
+unsigned long event__total[PERF_RECORD_MAX];
+
+void event__print_totals(void)
+{
+ int i;
+ for (i = 0; i < PERF_RECORD_MAX; ++i)
+ pr_info("%10s events: %10ld\n",
+ event__name[i], event__total[i]);
+}
+
+static int perf_session__process_event(struct perf_session *self,
+ event_t *event,
+ struct perf_event_ops *ops,
+ unsigned long offset, unsigned long head)
+{
+ trace_event(event);
+
+ if (event->header.type < PERF_RECORD_MAX) {
+ dump_printf("%p [%p]: PERF_RECORD_%s",
+ (void *)(offset + head),
+ (void *)(long)(event->header.size),
+ event__name[event->header.type]);
+ ++event__total[0];
+ ++event__total[event->header.type];
+ }
+
+ switch (event->header.type) {
+ case PERF_RECORD_SAMPLE:
+ return ops->process_sample_event(event, self);
+ case PERF_RECORD_MMAP:
+ return ops->process_mmap_event(event, self);
+ case PERF_RECORD_COMM:
+ return ops->process_comm_event(event, self);
+ case PERF_RECORD_FORK:
+ return ops->process_fork_event(event, self);
+ case PERF_RECORD_EXIT:
+ return ops->process_exit_event(event, self);
+ case PERF_RECORD_LOST:
+ return ops->process_lost_event(event, self);
+ case PERF_RECORD_READ:
+ return ops->process_read_event(event, self);
+ case PERF_RECORD_THROTTLE:
+ return ops->process_throttle_event(event, self);
+ case PERF_RECORD_UNTHROTTLE:
+ return ops->process_unthrottle_event(event, self);
+ default:
+ ops->total_unknown++;
+ return -1;
+ }
+}
+
+int perf_header__read_build_ids(int input, u64 offset, u64 size)
+{
+ struct build_id_event bev;
+ char filename[PATH_MAX];
+ u64 limit = offset + size;
+ int err = -1;
+
+ while (offset < limit) {
+ struct dso *dso;
+ ssize_t len;
+
+ if (read(input, &bev, sizeof(bev)) != sizeof(bev))
+ goto out;
+
+ len = bev.header.size - sizeof(bev);
+ if (read(input, filename, len) != len)
+ goto out;
+
+ dso = dsos__findnew(filename);
+ if (dso != NULL)
+ dso__set_build_id(dso, &bev.build_id);
+
+ offset += bev.header.size;
+ }
+ err = 0;
+out:
+ return err;
+}
+
+static struct thread *perf_session__register_idle_thread(struct perf_session *self)
+{
+ struct thread *thread = perf_session__findnew(self, 0);
+
+ if (thread == NULL || thread__set_comm(thread, "swapper")) {
+ pr_err("problem inserting idle task.\n");
+ thread = NULL;
+ }
+
+ return thread;
+}
+
+int perf_session__process_events(struct perf_session *self,
+ struct perf_event_ops *ops)
+{
+ int err;
+ unsigned long head, shift;
+ unsigned long offset = 0;
+ size_t page_size;
+ event_t *event;
+ uint32_t size;
+ char *buf;
+
+ if (perf_session__register_idle_thread(self) == NULL)
+ return -ENOMEM;
+
+ perf_event_ops__fill_defaults(ops);
+
+ page_size = getpagesize();
+
+ head = self->header.data_offset;
+ self->sample_type = perf_header__sample_type(&self->header);
+
+ err = -EINVAL;
+ if (ops->sample_type_check && ops->sample_type_check(self) < 0)
+ goto out_err;
+
+ if (!ops->full_paths) {
+ char bf[PATH_MAX];
+
+ if (getcwd(bf, sizeof(bf)) == NULL) {
+ err = -errno;
+out_getcwd_err:
+ pr_err("failed to get the current directory\n");
+ goto out_err;
+ }
+ self->cwd = strdup(bf);
+ if (self->cwd == NULL) {
+ err = -ENOMEM;
+ goto out_getcwd_err;
+ }
+ self->cwdlen = strlen(self->cwd);
+ }
+
+ shift = page_size * (head / page_size);
+ offset += shift;
+ head -= shift;
+
+remap:
+ buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
+ MAP_SHARED, self->fd, offset);
+ if (buf == MAP_FAILED) {
+ pr_err("failed to mmap file\n");
+ err = -errno;
+ goto out_err;
+ }
+
+more:
+ event = (event_t *)(buf + head);
+
+ size = event->header.size;
+ if (size == 0)
+ size = 8;
+
+ if (head + event->header.size >= page_size * self->mmap_window) {
+ int munmap_ret;
+
+ shift = page_size * (head / page_size);
+
+ munmap_ret = munmap(buf, page_size * self->mmap_window);
+ assert(munmap_ret == 0);
+
+ offset += shift;
+ head -= shift;
+ goto remap;
+ }
+
+ size = event->header.size;
+
+ dump_printf("\n%p [%p]: event: %d\n",
+ (void *)(offset + head),
+ (void *)(long)event->header.size,
+ event->header.type);
+
+ if (size == 0 ||
+ perf_session__process_event(self, event, ops, offset, head) < 0) {
+ dump_printf("%p [%p]: skipping unknown header type: %d\n",
+ (void *)(offset + head),
+ (void *)(long)(event->header.size),
+ event->header.type);
+ /*
+ * assume we lost track of the stream, check alignment, and
+ * increment a single u64 in the hope to catch on again 'soon'.
+ */
+ if (unlikely(head & 7))
+ head &= ~7ULL;
+
+ size = 8;
+ }
+
+ head += size;
+
+ if (offset + head >= self->header.data_offset + self->header.data_size)
+ goto done;
+
+ if (offset + head < self->size)
+ goto more;
+done:
+ err = 0;
+out_err:
+ return err;
+}
--
1.6.2.5

2009-12-27 23:39:26

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 04/10] perf tools: Move the map class definition to a separate header

From: Arnaldo Carvalho de Melo <[email protected]>

And this resulted in the need for adding some missing includes in some
places that were getting the definitions needed out of sheer luck.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile | 1 +
tools/perf/util/debug.c | 1 +
tools/perf/util/event.h | 65 ++----------------------------------
tools/perf/util/map.h | 73 ++++++++++++++++++++++++++++++++++++++++
tools/perf/util/probe-finder.h | 2 +
5 files changed, 80 insertions(+), 62 deletions(-)
create mode 100644 tools/perf/util/map.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 4172c3b..fafea0b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -357,6 +357,7 @@ LIB_H += util/event.h
LIB_H += util/exec_cmd.h
LIB_H += util/types.h
LIB_H += util/levenshtein.h
+LIB_H += util/map.h
LIB_H += util/parse-options.h
LIB_H += util/parse-events.h
LIB_H += util/quote.h
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 28d520d..0905600 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -9,6 +9,7 @@
#include "color.h"
#include "event.h"
#include "debug.h"
+#include "util.h"

int verbose = 0;
int dump_trace = 0;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 690a96d..80fb365 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,10 +1,10 @@
#ifndef __PERF_RECORD_H
#define __PERF_RECORD_H

+#include <limits.h>
+
#include "../perf.h"
-#include "util.h"
-#include <linux/list.h>
-#include <linux/rbtree.h>
+#include "map.h"

/*
* PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -101,67 +101,8 @@ struct events_stats {

void event__print_totals(void);

-enum map_type {
- MAP__FUNCTION = 0,
- MAP__VARIABLE,
-};
-
-#define MAP__NR_TYPES (MAP__VARIABLE + 1)
-
-struct map {
- union {
- struct rb_node rb_node;
- struct list_head node;
- };
- u64 start;
- u64 end;
- enum map_type type;
- u64 pgoff;
- u64 (*map_ip)(struct map *, u64);
- u64 (*unmap_ip)(struct map *, u64);
- struct dso *dso;
-};
-
-static inline u64 map__map_ip(struct map *map, u64 ip)
-{
- return ip - map->start + map->pgoff;
-}
-
-static inline u64 map__unmap_ip(struct map *map, u64 ip)
-{
- return ip + map->start - map->pgoff;
-}
-
-static inline u64 identity__map_ip(struct map *map __used, u64 ip)
-{
- return ip;
-}
-
-struct symbol;
-
-typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
-
-void map__init(struct map *self, enum map_type type,
- u64 start, u64 end, u64 pgoff, struct dso *dso);
-struct map *map__new(struct mmap_event *event, enum map_type,
- char *cwd, int cwdlen);
-void map__delete(struct map *self);
-struct map *map__clone(struct map *self);
-int map__overlap(struct map *l, struct map *r);
-size_t map__fprintf(struct map *self, FILE *fp);
-
struct perf_session;

-int map__load(struct map *self, struct perf_session *session,
- symbol_filter_t filter);
-struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
- u64 addr, symbol_filter_t filter);
-struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
- struct perf_session *session,
- symbol_filter_t filter);
-void map__fixup_start(struct map *self);
-void map__fixup_end(struct map *self);
-
int event__synthesize_thread(pid_t pid,
int (*process)(event_t *event,
struct perf_session *session),
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
new file mode 100644
index 0000000..72f0b6a
--- /dev/null
+++ b/tools/perf/util/map.h
@@ -0,0 +1,73 @@
+#ifndef __PERF_MAP_H
+#define __PERF_MAP_H
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/types.h>
+
+enum map_type {
+ MAP__FUNCTION = 0,
+ MAP__VARIABLE,
+};
+
+#define MAP__NR_TYPES (MAP__VARIABLE + 1)
+
+struct dso;
+
+struct map {
+ union {
+ struct rb_node rb_node;
+ struct list_head node;
+ };
+ u64 start;
+ u64 end;
+ enum map_type type;
+ u64 pgoff;
+ u64 (*map_ip)(struct map *, u64);
+ u64 (*unmap_ip)(struct map *, u64);
+ struct dso *dso;
+};
+
+static inline u64 map__map_ip(struct map *map, u64 ip)
+{
+ return ip - map->start + map->pgoff;
+}
+
+static inline u64 map__unmap_ip(struct map *map, u64 ip)
+{
+ return ip + map->start - map->pgoff;
+}
+
+static inline u64 identity__map_ip(struct map *map __used, u64 ip)
+{
+ return ip;
+}
+
+struct symbol;
+struct mmap_event;
+
+typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
+
+void map__init(struct map *self, enum map_type type,
+ u64 start, u64 end, u64 pgoff, struct dso *dso);
+struct map *map__new(struct mmap_event *event, enum map_type,
+ char *cwd, int cwdlen);
+void map__delete(struct map *self);
+struct map *map__clone(struct map *self);
+int map__overlap(struct map *l, struct map *r);
+size_t map__fprintf(struct map *self, FILE *fp);
+
+struct perf_session;
+
+int map__load(struct map *self, struct perf_session *session,
+ symbol_filter_t filter);
+struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
+ u64 addr, symbol_filter_t filter);
+struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
+ struct perf_session *session,
+ symbol_filter_t filter);
+void map__fixup_start(struct map *self);
+void map__fixup_end(struct map *self);
+
+#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index a4086aa..e3f3968 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,6 +1,8 @@
#ifndef _PROBE_FINDER_H
#define _PROBE_FINDER_H

+#include "util.h"
+
#define MAX_PATH_LEN 256
#define MAX_PROBE_BUFFER 1024
#define MAX_PROBES 128
--
1.6.2.5

2009-12-27 23:37:30

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 05/10] perf session: Share the common trace sample_check routine as perf_session__has_traces

From: Arnaldo Carvalho de Melo <[email protected]>

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-kmem.c | 14 +-------------
tools/perf/builtin-sched.c | 14 +-------------
tools/perf/builtin-timechart.c | 13 +------------
tools/perf/builtin-trace.c | 14 +-------------
tools/perf/util/session.c | 11 +++++++++++
tools/perf/util/session.h | 2 ++
6 files changed, 17 insertions(+), 51 deletions(-)

diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index fc21ad7..a85936f 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -342,22 +342,10 @@ static int process_sample_event(event_t *event, struct perf_session *session)
return 0;
}

-static int sample_type_check(struct perf_session *session)
-{
- if (!(session->sample_type & PERF_SAMPLE_RAW)) {
- fprintf(stderr,
- "No trace sample to read. Did you call perf record "
- "without -R?");
- return -1;
- }
-
- return 0;
-}
-
static struct perf_event_ops event_ops = {
.process_sample_event = process_sample_event,
.process_comm_event = event__process_comm,
- .sample_type_check = sample_type_check,
+ .sample_type_check = perf_session__has_traces,
};

static double fragmentation(unsigned long n_req, unsigned long n_alloc)
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 80209df..d65098c 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1653,23 +1653,11 @@ static int process_lost_event(event_t *event __used,
return 0;
}

-static int sample_type_check(struct perf_session *session __used)
-{
- if (!(session->sample_type & PERF_SAMPLE_RAW)) {
- fprintf(stderr,
- "No trace sample to read. Did you call perf record "
- "without -R?");
- return -1;
- }
-
- return 0;
-}
-
static struct perf_event_ops event_ops = {
.process_sample_event = process_sample_event,
.process_comm_event = event__process_comm,
.process_lost_event = process_lost_event,
- .sample_type_check = sample_type_check,
+ .sample_type_check = perf_session__has_traces,
};

static int read_events(void)
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index a589a43..b42f337 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1029,23 +1029,12 @@ static void process_samples(struct perf_session *session)
}
}

-static int sample_type_check(struct perf_session *session)
-{
- if (!(session->sample_type & PERF_SAMPLE_RAW)) {
- fprintf(stderr, "No trace samples found in the file.\n"
- "Have you used 'perf timechart record' to record it?\n");
- return -1;
- }
-
- return 0;
-}
-
static struct perf_event_ops event_ops = {
.process_comm_event = process_comm_event,
.process_fork_event = process_fork_event,
.process_exit_event = process_exit_event,
.process_sample_event = queue_sample_event,
- .sample_type_check = sample_type_check,
+ .sample_type_check = perf_session__has_traces,
};

static int __cmd_timechart(void)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 574a215..b0ba2ac 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -103,22 +103,10 @@ static int process_sample_event(event_t *event, struct perf_session *session)
return 0;
}

-static int sample_type_check(struct perf_session *session)
-{
- if (!(session->sample_type & PERF_SAMPLE_RAW)) {
- fprintf(stderr,
- "No trace sample to read. Did you call perf record "
- "without -R?");
- return -1;
- }
-
- return 0;
-}
-
static struct perf_event_ops event_ops = {
.process_sample_event = process_sample_event,
.process_comm_event = event__process_comm,
- .sample_type_check = sample_type_check,
+ .sample_type_check = perf_session__has_traces,
};

static int __cmd_trace(struct perf_session *session)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 736d4fd..60eab8b 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -393,3 +393,14 @@ done:
out_err:
return err;
}
+
+int perf_session__has_traces(struct perf_session *self)
+{
+ if (!(self->sample_type & PERF_SAMPLE_RAW)) {
+ pr_err("No trace sample to read. Did you call perf record "
+ "without -R?");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 32eaa1b..a6951d2 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -56,6 +56,8 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
struct ip_callchain *chain,
struct symbol **parent);

+int perf_session__has_traces(struct perf_session *self);
+
int perf_header__read_build_ids(int input, u64 offset, u64 file_size);

#endif /* __PERF_SESSION_H */
--
1.6.2.5

2009-12-27 23:38:23

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 06/10] perf session: Remove sample_type_check from event_ops

From: Arnaldo Carvalho de Melo <[email protected]>

This is really something tools need to do before asking for the events
to be processed, leaving perf_session__process_events to do just that,
process events.

Also add a msg parameter to perf_session__has_traces() so that the right
message can be printed, fixing a regression added by me in the previous
cset (right timechart message) and also fixing 'perf kmem', that was not
asking if 'perf kmem record' was ran.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-kmem.c | 6 ++++--
tools/perf/builtin-report.c | 16 +++++++++-------
tools/perf/builtin-sched.c | 7 ++++---
tools/perf/builtin-timechart.c | 6 ++++--
tools/perf/builtin-trace.c | 4 +++-
tools/perf/util/session.c | 16 ++++++----------
tools/perf/util/session.h | 3 +--
7 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index a85936f..73b0650 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -345,7 +345,6 @@ static int process_sample_event(event_t *event, struct perf_session *session)
static struct perf_event_ops event_ops = {
.process_sample_event = process_sample_event,
.process_comm_event = event__process_comm,
- .sample_type_check = perf_session__has_traces,
};

static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -492,11 +491,14 @@ static void sort_result(void)

static int __cmd_kmem(void)
{
- int err;
+ int err = -EINVAL;
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
if (session == NULL)
return -ENOMEM;

+ if (!perf_session__has_traces(session, "kmem record"))
+ goto out_delete;
+
setup_pager();
err = perf_session__process_events(session, &event_ops);
if (err != 0)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index db10c0e..0825918 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -156,14 +156,14 @@ static int process_read_event(event_t *event, struct perf_session *session __use
return 0;
}

-static int sample_type_check(struct perf_session *session)
+static int perf_session__setup_sample_type(struct perf_session *self)
{
- if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) {
+ if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
if (sort__has_parent) {
fprintf(stderr, "selected --sort parent, but no"
" callchain data. Did you call"
" perf record without -g?\n");
- return -1;
+ return -EINVAL;
}
if (symbol_conf.use_callchain) {
fprintf(stderr, "selected -g but no callchain data."
@@ -176,7 +176,7 @@ static int sample_type_check(struct perf_session *session)
if (register_callchain_param(&callchain_param) < 0) {
fprintf(stderr, "Can't register callchain"
" params\n");
- return -1;
+ return -EINVAL;
}
}

@@ -191,13 +191,11 @@ static struct perf_event_ops event_ops = {
.process_fork_event = event__process_task,
.process_lost_event = event__process_lost,
.process_read_event = process_read_event,
- .sample_type_check = sample_type_check,
};

-
static int __cmd_report(void)
{
- int ret;
+ int ret = -EINVAL;
struct perf_session *session;

session = perf_session__new(input_name, O_RDONLY, force);
@@ -207,6 +205,10 @@ static int __cmd_report(void)
if (show_threads)
perf_read_values_init(&show_threads_values);

+ ret = perf_session__setup_sample_type(session);
+ if (ret)
+ goto out_delete;
+
ret = perf_session__process_events(session, &event_ops);
if (ret)
goto out_delete;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index d65098c..e862e71 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1657,17 +1657,18 @@ static struct perf_event_ops event_ops = {
.process_sample_event = process_sample_event,
.process_comm_event = event__process_comm,
.process_lost_event = process_lost_event,
- .sample_type_check = perf_session__has_traces,
};

static int read_events(void)
{
- int err;
+ int err = -EINVAL;
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
if (session == NULL)
return -ENOMEM;

- err = perf_session__process_events(session, &event_ops);
+ if (perf_session__has_traces(session, "record -R"))
+ err = perf_session__process_events(session, &event_ops);
+
perf_session__delete(session);
return err;
}
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index b42f337..8252837 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1034,17 +1034,19 @@ static struct perf_event_ops event_ops = {
.process_fork_event = process_fork_event,
.process_exit_event = process_exit_event,
.process_sample_event = queue_sample_event,
- .sample_type_check = perf_session__has_traces,
};

static int __cmd_timechart(void)
{
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
- int ret;
+ int ret = -EINVAL;

if (session == NULL)
return -ENOMEM;

+ if (!perf_session__has_traces(session, "timechart record"))
+ goto out_delete;
+
ret = perf_session__process_events(session, &event_ops);
if (ret)
goto out_delete;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index b0ba2ac..e94f346 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -106,7 +106,6 @@ static int process_sample_event(event_t *event, struct perf_session *session)
static struct perf_event_ops event_ops = {
.process_sample_event = process_sample_event,
.process_comm_event = event__process_comm,
- .sample_type_check = perf_session__has_traces,
};

static int __cmd_trace(struct perf_session *session)
@@ -580,6 +579,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
if (session == NULL)
return -ENOMEM;

+ if (!perf_session__has_traces(session, "record -R"))
+ return -EINVAL;
+
if (generate_script_lang) {
struct stat perf_stat;

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 60eab8b..bc84a52 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -73,6 +73,8 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc

if (mode == O_RDONLY && perf_session__open(self, force) < 0)
goto out_delete;
+
+ self->sample_type = perf_header__sample_type(&self->header);
out:
return self;
out_free:
@@ -302,11 +304,6 @@ int perf_session__process_events(struct perf_session *self,
page_size = getpagesize();

head = self->header.data_offset;
- self->sample_type = perf_header__sample_type(&self->header);
-
- err = -EINVAL;
- if (ops->sample_type_check && ops->sample_type_check(self) < 0)
- goto out_err;

if (!ops->full_paths) {
char bf[PATH_MAX];
@@ -394,13 +391,12 @@ out_err:
return err;
}

-int perf_session__has_traces(struct perf_session *self)
+bool perf_session__has_traces(struct perf_session *self, const char *msg)
{
if (!(self->sample_type & PERF_SAMPLE_RAW)) {
- pr_err("No trace sample to read. Did you call perf record "
- "without -R?");
- return -1;
+ pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
+ return false;
}

- return 0;
+ return true;
}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index a6951d2..5771ccb 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -40,7 +40,6 @@ struct perf_event_ops {
event_op process_read_event;
event_op process_throttle_event;
event_op process_unthrottle_event;
- int (*sample_type_check)(struct perf_session *session);
unsigned long total_unknown;
bool full_paths;
};
@@ -56,7 +55,7 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
struct ip_callchain *chain,
struct symbol **parent);

-int perf_session__has_traces(struct perf_session *self);
+bool perf_session__has_traces(struct perf_session *self, const char *msg);

int perf_header__read_build_ids(int input, u64 offset, u64 file_size);

--
1.6.2.5

2009-12-27 23:37:23

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 07/10] perf session: Move total_unknown to perf_session->unknown events

From: Arnaldo Carvalho de Melo <[email protected]>

As this is a session property, not belonging to perf_event_ops, that can
be shared by many perf_session instances.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/session.c | 3 ++-
tools/perf/util/session.h | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index bc84a52..4ca427f 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -66,6 +66,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
self->mmap_window = 32;
self->cwd = NULL;
self->cwdlen = 0;
+ self->unknown_events = 0;
map_groups__init(&self->kmaps);

if (perf_session__create_kernel_maps(self) < 0)
@@ -239,7 +240,7 @@ static int perf_session__process_event(struct perf_session *self,
case PERF_RECORD_UNTHROTTLE:
return ops->process_unthrottle_event(event, self);
default:
- ops->total_unknown++;
+ self->unknown_events++;
return -1;
}
}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 5771ccb..585937b 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -20,6 +20,7 @@ struct perf_session {
struct thread *last_match;
struct events_stats events_stats;
unsigned long event_total[PERF_RECORD_MAX];
+ unsigned long unknown_events;
struct rb_root hists;
u64 sample_type;
int fd;
@@ -40,7 +41,6 @@ struct perf_event_ops {
event_op process_read_event;
event_op process_throttle_event;
event_op process_unthrottle_event;
- unsigned long total_unknown;
bool full_paths;
};

--
1.6.2.5

2009-12-27 23:37:26

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 08/10] perf session: Move full_paths config to symbol_conf

From: Arnaldo Carvalho de Melo <[email protected]>

Now perf_event_ops has just that, event handlers.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-diff.c | 2 +-
tools/perf/builtin-report.c | 2 +-
tools/perf/util/session.c | 2 +-
tools/perf/util/session.h | 1 -
tools/perf/util/symbol.h | 3 ++-
5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index bd71b8c..e164b3d 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -204,7 +204,7 @@ static const struct option options[] = {
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
"load module symbols - WARNING: use only with -k and LIVE kernel"),
- OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
+ OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
"Don't shorten the pathnames taking into account the cwd"),
OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
"only consider symbols in these dsos"),
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 0825918..f695084 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -321,7 +321,7 @@ static const struct option options[] = {
"pretty printing style key: normal raw"),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
"sort by key(s): pid, comm, dso, symbol, parent"),
- OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
+ OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
"Don't shorten the pathnames taking into account the cwd"),
OPT_STRING('p', "parent", &parent_pattern, "regex",
"regex filter to identify parent, see: '--sort parent'"),
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 4ca427f..4f2eeb5 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -306,7 +306,7 @@ int perf_session__process_events(struct perf_session *self,

head = self->header.data_offset;

- if (!ops->full_paths) {
+ if (!symbol_conf.full_paths) {
char bf[PATH_MAX];

if (getcwd(bf, sizeof(bf)) == NULL) {
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 585937b..2ff77fe 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -41,7 +41,6 @@ struct perf_event_ops {
event_op process_read_event;
event_op process_throttle_event;
event_op process_unthrottle_event;
- bool full_paths;
};

struct perf_session *perf_session__new(const char *filename, int mode, bool force);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8aded23..9eabd60 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -58,7 +58,8 @@ struct symbol_conf {
sort_by_name,
show_nr_samples,
use_callchain,
- exclude_other;
+ exclude_other,
+ full_paths;
const char *vmlinux_name,
*field_sep;
char *dso_list_str,
--
1.6.2.5

2009-12-27 23:38:47

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 09/10] perf session: Remove redundant prefix & suffix from perf_event_ops

From: Arnaldo Carvalho de Melo <[email protected]>

Since now all that we have are perf event handlers, leave just the name
of the event.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-annotate.c | 8 +++---
tools/perf/builtin-diff.c | 12 ++++----
tools/perf/builtin-kmem.c | 4 +-
tools/perf/builtin-report.c | 14 +++++-----
tools/perf/builtin-sched.c | 6 ++--
tools/perf/builtin-timechart.c | 8 +++---
tools/perf/builtin-trace.c | 4 +-
tools/perf/util/session.c | 54 ++++++++++++++++++++--------------------
tools/perf/util/session.h | 18 ++++++------
9 files changed, 64 insertions(+), 64 deletions(-)

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 593ff25..117bbae 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -451,10 +451,10 @@ static void perf_session__find_annotations(struct perf_session *self)
}

static struct perf_event_ops event_ops = {
- .process_sample_event = process_sample_event,
- .process_mmap_event = event__process_mmap,
- .process_comm_event = event__process_comm,
- .process_fork_event = event__process_task,
+ .sample = process_sample_event,
+ .mmap = event__process_mmap,
+ .comm = event__process_comm,
+ .fork = event__process_task,
};

static int __cmd_annotate(void)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index e164b3d..1cbecaf 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -66,12 +66,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
}

static struct perf_event_ops event_ops = {
- .process_sample_event = diff__process_sample_event,
- .process_mmap_event = event__process_mmap,
- .process_comm_event = event__process_comm,
- .process_exit_event = event__process_task,
- .process_fork_event = event__process_task,
- .process_lost_event = event__process_lost,
+ .sample = diff__process_sample_event,
+ .mmap = event__process_mmap,
+ .comm = event__process_comm,
+ .exit = event__process_task,
+ .fork = event__process_task,
+ .lost = event__process_lost,
};

static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 73b0650..4c06828 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -343,8 +343,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
}

static struct perf_event_ops event_ops = {
- .process_sample_event = process_sample_event,
- .process_comm_event = event__process_comm,
+ .sample = process_sample_event,
+ .comm = event__process_comm,
};

static double fragmentation(unsigned long n_req, unsigned long n_alloc)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index f695084..508934b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -184,13 +184,13 @@ static int perf_session__setup_sample_type(struct perf_session *self)
}

static struct perf_event_ops event_ops = {
- .process_sample_event = process_sample_event,
- .process_mmap_event = event__process_mmap,
- .process_comm_event = event__process_comm,
- .process_exit_event = event__process_task,
- .process_fork_event = event__process_task,
- .process_lost_event = event__process_lost,
- .process_read_event = process_read_event,
+ .sample = process_sample_event,
+ .mmap = event__process_mmap,
+ .comm = event__process_comm,
+ .exit = event__process_task,
+ .fork = event__process_task,
+ .lost = event__process_lost,
+ .read = process_read_event,
};

static int __cmd_report(void)
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index e862e71..702322f 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1654,9 +1654,9 @@ static int process_lost_event(event_t *event __used,
}

static struct perf_event_ops event_ops = {
- .process_sample_event = process_sample_event,
- .process_comm_event = event__process_comm,
- .process_lost_event = process_lost_event,
+ .sample = process_sample_event,
+ .comm = event__process_comm,
+ .lost = process_lost_event,
};

static int read_events(void)
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 8252837..5b68d81 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1030,10 +1030,10 @@ static void process_samples(struct perf_session *session)
}

static struct perf_event_ops event_ops = {
- .process_comm_event = process_comm_event,
- .process_fork_event = process_fork_event,
- .process_exit_event = process_exit_event,
- .process_sample_event = queue_sample_event,
+ .comm = process_comm_event,
+ .fork = process_fork_event,
+ .exit = process_exit_event,
+ .sample = queue_sample_event,
};

static int __cmd_timechart(void)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index e94f346..1831434 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -104,8 +104,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
}

static struct perf_event_ops event_ops = {
- .process_sample_event = process_sample_event,
- .process_comm_event = event__process_comm,
+ .sample = process_sample_event,
+ .comm = event__process_comm,
};

static int __cmd_trace(struct perf_session *session)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 4f2eeb5..7f0537d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -161,24 +161,24 @@ static int process_event_stub(event_t *event __used,

static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
{
- if (handler->process_sample_event == NULL)
- handler->process_sample_event = process_event_stub;
- if (handler->process_mmap_event == NULL)
- handler->process_mmap_event = process_event_stub;
- if (handler->process_comm_event == NULL)
- handler->process_comm_event = process_event_stub;
- if (handler->process_fork_event == NULL)
- handler->process_fork_event = process_event_stub;
- if (handler->process_exit_event == NULL)
- handler->process_exit_event = process_event_stub;
- if (handler->process_lost_event == NULL)
- handler->process_lost_event = process_event_stub;
- if (handler->process_read_event == NULL)
- handler->process_read_event = process_event_stub;
- if (handler->process_throttle_event == NULL)
- handler->process_throttle_event = process_event_stub;
- if (handler->process_unthrottle_event == NULL)
- handler->process_unthrottle_event = process_event_stub;
+ if (handler->sample == NULL)
+ handler->sample = process_event_stub;
+ if (handler->mmap == NULL)
+ handler->mmap = process_event_stub;
+ if (handler->comm == NULL)
+ handler->comm = process_event_stub;
+ if (handler->fork == NULL)
+ handler->fork = process_event_stub;
+ if (handler->exit == NULL)
+ handler->exit = process_event_stub;
+ if (handler->lost == NULL)
+ handler->lost = process_event_stub;
+ if (handler->read == NULL)
+ handler->read = process_event_stub;
+ if (handler->throttle == NULL)
+ handler->throttle = process_event_stub;
+ if (handler->unthrottle == NULL)
+ handler->unthrottle = process_event_stub;
}

static const char *event__name[] = {
@@ -222,23 +222,23 @@ static int perf_session__process_event(struct perf_session *self,

switch (event->header.type) {
case PERF_RECORD_SAMPLE:
- return ops->process_sample_event(event, self);
+ return ops->sample(event, self);
case PERF_RECORD_MMAP:
- return ops->process_mmap_event(event, self);
+ return ops->mmap(event, self);
case PERF_RECORD_COMM:
- return ops->process_comm_event(event, self);
+ return ops->comm(event, self);
case PERF_RECORD_FORK:
- return ops->process_fork_event(event, self);
+ return ops->fork(event, self);
case PERF_RECORD_EXIT:
- return ops->process_exit_event(event, self);
+ return ops->exit(event, self);
case PERF_RECORD_LOST:
- return ops->process_lost_event(event, self);
+ return ops->lost(event, self);
case PERF_RECORD_READ:
- return ops->process_read_event(event, self);
+ return ops->read(event, self);
case PERF_RECORD_THROTTLE:
- return ops->process_throttle_event(event, self);
+ return ops->throttle(event, self);
case PERF_RECORD_UNTHROTTLE:
- return ops->process_unthrottle_event(event, self);
+ return ops->unthrottle(event, self);
default:
self->unknown_events++;
return -1;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 2ff77fe..77c5ee2 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -32,15 +32,15 @@ struct perf_session {
typedef int (*event_op)(event_t *self, struct perf_session *session);

struct perf_event_ops {
- event_op process_sample_event;
- event_op process_mmap_event;
- event_op process_comm_event;
- event_op process_fork_event;
- event_op process_exit_event;
- event_op process_lost_event;
- event_op process_read_event;
- event_op process_throttle_event;
- event_op process_unthrottle_event;
+ event_op sample,
+ mmap,
+ comm,
+ fork,
+ exit,
+ lost,
+ read,
+ throttle,
+ unthrottle;
};

struct perf_session *perf_session__new(const char *filename, int mode, bool force);
--
1.6.2.5

2009-12-27 23:38:51

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 10/10] perf record: Introduce a symtab cache

From: Arnaldo Carvalho de Melo <[email protected]>

Now a cache will be created in a ~/.debug debuginfo like hierarchy, so
that at the end of a 'perf record' session all the binaries (with
build-ids) involved get collected and indexed by their build-ids, so
that perf record can find them.

This is interesting when developing software where you want to do a
'perf diff' with the previous build and opens avenues for lots more
interesting tools, like a 'perf diff --graph' that takes more than two
binaries into account.

Tunables for collecting just the symtabs can be added if one doesn't
want to have the full binary, but having the full binary allows things
like 'perf rerecord' or other tools that can re-run the tests by having
access to the exact binary in some perf.data file, so it may well be
interesting to keep the full binary there.

Space consumption is minimised by trying to use hard links, a 'perf
cache' tool to manage the space used, a la ccache is required to purge
older entries.

With this in place it will be possible also to introduce new commands,
'perf archive' and 'perf restore' (or some more suitable and future
proof names) to create a cpio/tar file with the perf data and the files
in the cache that _had_ perf hits of interest.

There are more aspects to polish, like finding the right vmlinux file
to cache, etc, but this is enough for a first step.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Makefile | 1 +
tools/perf/util/header.c | 82 +++++++++++++++++++++++++++++++++++++++++++---
tools/perf/util/symbol.c | 17 +++++++--
tools/perf/util/symbol.h | 2 +
tools/perf/util/util.c | 69 ++++++++++++++++++++++++++++++++++++++
tools/perf/util/util.h | 3 ++
6 files changed, 165 insertions(+), 9 deletions(-)
create mode 100644 tools/perf/util/util.c

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index fafea0b..7c84642 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -425,6 +425,7 @@ LIB_OBJS += util/svghelper.o
LIB_OBJS += util/sort.o
LIB_OBJS += util/hist.o
LIB_OBJS += util/probe-event.o
+LIB_OBJS += util/util.o

BUILTIN_OBJS += builtin-annotate.o

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 8a0bca5..df237c3 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -169,20 +169,23 @@ static int do_write(int fd, const void *buf, size_t size)
return 0;
}

+#define dsos__for_each_with_build_id(pos, head) \
+ list_for_each_entry(pos, head, node) \
+ if (!pos->has_build_id) \
+ continue; \
+ else
+
static int __dsos__write_buildid_table(struct list_head *head, int fd)
{
#define NAME_ALIGN 64
struct dso *pos;
static const char zero_buf[NAME_ALIGN];

- list_for_each_entry(pos, head, node) {
+ dsos__for_each_with_build_id(pos, head) {
int err;
struct build_id_event b;
- size_t len;
+ size_t len = pos->long_name_len + 1;

- if (!pos->has_build_id)
- continue;
- len = pos->long_name_len + 1;
len = ALIGN(len, NAME_ALIGN);
memset(&b, 0, sizeof(b));
memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
@@ -209,6 +212,74 @@ static int dsos__write_buildid_table(int fd)
return err;
}

+static int dso__cache_build_id(struct dso *self, const char *debugdir)
+{
+ const size_t size = PATH_MAX;
+ char *filename = malloc(size),
+ *linkname = malloc(size), *targetname, *sbuild_id;
+ int len, err = -1;
+
+ if (filename == NULL || linkname == NULL)
+ goto out_free;
+
+ len = snprintf(filename, size, "%s%s", debugdir, self->long_name);
+ if (mkdir_p(filename, 0755))
+ goto out_free;
+
+ len += snprintf(filename + len, sizeof(filename) - len, "/");
+ sbuild_id = filename + len;
+ build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
+
+ if (access(filename, F_OK) && link(self->long_name, filename) &&
+ copyfile(self->long_name, filename))
+ goto out_free;
+
+ len = snprintf(linkname, size, "%s/.build-id/%.2s",
+ debugdir, sbuild_id);
+
+ if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
+ goto out_free;
+
+ snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
+ targetname = filename + strlen(debugdir) - 5;
+ memcpy(targetname, "../..", 5);
+
+ if (symlink(targetname, linkname) == 0)
+ err = 0;
+out_free:
+ free(filename);
+ free(linkname);
+ return err;
+}
+
+static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
+{
+ struct dso *pos;
+ int err = 0;
+
+ dsos__for_each_with_build_id(pos, head)
+ if (dso__cache_build_id(pos, debugdir))
+ err = -1;
+
+ return err;
+}
+
+static int dsos__cache_build_ids(void)
+{
+ int err_kernel, err_user;
+ char debugdir[PATH_MAX];
+
+ snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
+ DEBUG_CACHE_DIR);
+
+ if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
+ return -1;
+
+ err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
+ err_user = __dsos__cache_build_ids(&dsos__user, debugdir);
+ return err_kernel || err_user ? -1 : 0;
+}
+
static int perf_header__adds_write(struct perf_header *self, int fd)
{
int nr_sections;
@@ -258,6 +329,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
goto out_free;
}
buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
+ dsos__cache_build_ids();
}

lseek(fd, sec_start, SEEK_SET);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab92763..79ca6a0 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -22,6 +22,7 @@
enum dso_origin {
DSO__ORIG_KERNEL = 0,
DSO__ORIG_JAVA_JIT,
+ DSO__ORIG_BUILD_ID_CACHE,
DSO__ORIG_FEDORA,
DSO__ORIG_UBUNTU,
DSO__ORIG_BUILDID,
@@ -1191,6 +1192,7 @@ char dso__symtab_origin(const struct dso *self)
static const char origin[] = {
[DSO__ORIG_KERNEL] = 'k',
[DSO__ORIG_JAVA_JIT] = 'j',
+ [DSO__ORIG_BUILD_ID_CACHE] = 'B',
[DSO__ORIG_FEDORA] = 'f',
[DSO__ORIG_UBUNTU] = 'u',
[DSO__ORIG_BUILDID] = 'b',
@@ -1209,6 +1211,7 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
int size = PATH_MAX;
char *name;
u8 build_id[BUILD_ID_SIZE];
+ char build_id_hex[BUILD_ID_SIZE * 2 + 1];
int ret = -1;
int fd;

@@ -1230,8 +1233,16 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
return ret;
}

- self->origin = DSO__ORIG_FEDORA - 1;
+ self->origin = DSO__ORIG_BUILD_ID_CACHE;

+ if (self->has_build_id) {
+ build_id__sprintf(self->build_id, sizeof(self->build_id),
+ build_id_hex);
+ snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
+ getenv("HOME"), DEBUG_CACHE_DIR,
+ build_id_hex, build_id_hex + 2);
+ goto open_file;
+ }
more:
do {
self->origin++;
@@ -1247,8 +1258,6 @@ more:
case DSO__ORIG_BUILDID:
if (filename__read_build_id(self->long_name, build_id,
sizeof(build_id))) {
- char build_id_hex[BUILD_ID_SIZE * 2 + 1];
-
build_id__sprintf(build_id, sizeof(build_id),
build_id_hex);
snprintf(name, size,
@@ -1276,7 +1285,7 @@ compare_build_id:
if (!dso__build_id_equal(self, build_id))
goto more;
}
-
+open_file:
fd = open(name, O_RDONLY);
} while (fd < 0);

diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 9eabd60..f27e158 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -8,6 +8,8 @@
#include <linux/rbtree.h>
#include "event.h"

+#define DEBUG_CACHE_DIR ".debug"
+
#ifdef HAVE_CPLUS_DEMANGLE
extern char *cplus_demangle(const char *, int);

diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
new file mode 100644
index 0000000..f3c0798
--- /dev/null
+++ b/tools/perf/util/util.c
@@ -0,0 +1,69 @@
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include "util.h"
+
+int mkdir_p(char *path, mode_t mode)
+{
+ struct stat st;
+ int err;
+ char *d = path;
+
+ if (*d != '/')
+ return -1;
+
+ if (stat(path, &st) == 0)
+ return 0;
+
+ while (*++d == '/');
+
+ while ((d = strchr(d, '/'))) {
+ *d = '\0';
+ err = stat(path, &st) && mkdir(path, mode);
+ *d++ = '/';
+ if (err)
+ return -1;
+ while (*d == '/')
+ ++d;
+ }
+ return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
+}
+
+int copyfile(const char *from, const char *to)
+{
+ int fromfd, tofd;
+ struct stat st;
+ void *addr;
+ int err = -1;
+
+ if (stat(from, &st))
+ goto out;
+
+ fromfd = open(from, O_RDONLY);
+ if (fromfd < 0)
+ goto out;
+
+ tofd = creat(to, 0755);
+ if (tofd < 0)
+ goto out_close_from;
+
+ addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
+ if (addr == MAP_FAILED)
+ goto out_close_to;
+
+ if (write(tofd, addr, st.st_size) == st.st_size)
+ err = 0;
+
+ munmap(addr, st.st_size);
+out_close_to:
+ close(tofd);
+ if (err)
+ unlink(to);
+out_close_from:
+ close(fromfd);
+out:
+ return err;
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c673d88..0f5b2a6 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -403,4 +403,7 @@ void git_qsort(void *base, size_t nmemb, size_t size,
#endif
#endif

+int mkdir_p(char *path, mode_t mode);
+int copyfile(const char *from, const char *to);
+
#endif
--
1.6.2.5

2009-12-27 23:40:30

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 10/10] perf record: Introduce a symtab cache

Em Sun, Dec 27, 2009 at 09:37:06PM -0200, Arnaldo Carvalho de Melo escreveu:
> From: Arnaldo Carvalho de Melo <[email protected]>
>
> Now a cache will be created in a ~/.debug debuginfo like hierarchy, so
> that at the end of a 'perf record' session all the binaries (with
> build-ids) involved get collected and indexed by their build-ids, so
> that perf record can find them.

Gack, 'so that perf report' (and new tools, hopefully) can find them, of
course :-\ If you notice this, please fix it up.

- Arnaldo

2009-12-28 08:05:07

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 10/10] perf record: Introduce a symtab cache


* Arnaldo Carvalho de Melo <[email protected]> wrote:

> Em Sun, Dec 27, 2009 at 09:37:06PM -0200, Arnaldo Carvalho de Melo escreveu:
> > From: Arnaldo Carvalho de Melo <[email protected]>
> >
> > Now a cache will be created in a ~/.debug debuginfo like hierarchy, so
> > that at the end of a 'perf record' session all the binaries (with
> > build-ids) involved get collected and indexed by their build-ids, so
> > that perf record can find them.
>
> Gack, 'so that perf report' (and new tools, hopefully) can find them, of
> course :-\ If you notice this, please fix it up.

I fixed the log message - thanks Arnaldo.

Ingo

2009-12-28 08:05:53

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 01/10] perf record: We should fork only if a program was specified to run


Note, i moved the first two patches into perf/urgent (as they are fixes), the
others into perf/core.

Ingo