* [GIT PULL 00/18] perf/core improvements and fixes
@ 2014-11-06 21:04 Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 01/18] perf tools: Add a thread stack for synthesizing call chains Arnaldo Carvalho de Melo
` (18 more replies)
0 siblings, 19 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Arnaldo Carvalho de Melo, Adrian Hunter,
Corey Ashford, David Ahern, Frederic Weisbecker, Jiri Olsa,
Namhyung Kim, Paul Mackerras, Peter Zijlstra, Stephane Eranian,
Steven Rostedt, Arnaldo Carvalho de Melo
Hi Ingo,
Please consider pulling,
- Arnaldo
The following changes since commit daa01794a4a36a1da1b09a529adec0c8c0b94ab2:
perf evsel: Do not call pevent_free_format when deleting tracepoint (2014-11-06 17:47:14 -0300)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo
for you to fetch changes up to daa01794a4a36a1da1b09a529adec0c8c0b94ab2:
perf evsel: Do not call pevent_free_format when deleting tracepoint (2014-11-06 17:47:14 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:
Infrastructure:
o Add gzip decompression support for kernel modules (Namhyung Kim)
o More prep patches for Intel PT, including a a thread stack and
more stuff made available via the database export mechanism (Adrian Hunter)
o Optimize checking that tracepoint events are defined in perf script perl/python (Jiri Olsa)
o Do not free pevent when deleting tracepoint evsel (Jiri Olsa)
o Fix build-id matching for vmlinux (Namhyung Kim)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
----------------------------------------------------------------
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 01/18] perf tools: Add a thread stack for synthesizing call chains
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 02/18] perf tools: Enhance the thread stack to output call/return data Arnaldo Carvalho de Melo
` (17 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Adrian Hunter, David Ahern, Frederic Weisbecker,
Jiri Olsa, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
Stephane Eranian, Arnaldo Carvalho de Melo
From: Adrian Hunter <adrian.hunter@intel.com>
Add a thread stack for synthesizing call chains from call and return
events.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1414678188-14946-2-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/Makefile.perf | 2 +
tools/perf/util/event.h | 26 +++++++
tools/perf/util/thread-stack.c | 172 +++++++++++++++++++++++++++++++++++++++++
tools/perf/util/thread-stack.h | 32 ++++++++
tools/perf/util/thread.c | 3 +
tools/perf/util/thread.h | 3 +
6 files changed, 238 insertions(+)
create mode 100644 tools/perf/util/thread-stack.c
create mode 100644 tools/perf/util/thread-stack.h
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 3caf7dab50e8..0ebcc4ad0244 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -317,6 +317,7 @@ LIB_H += ui/util.h
LIB_H += ui/ui.h
LIB_H += util/data.h
LIB_H += util/kvm-stat.h
+LIB_H += util/thread-stack.h
LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o
@@ -394,6 +395,7 @@ LIB_OBJS += $(OUTPUT)util/srcline.o
LIB_OBJS += $(OUTPUT)util/data.o
LIB_OBJS += $(OUTPUT)util/tsc.o
LIB_OBJS += $(OUTPUT)util/cloexec.o
+LIB_OBJS += $(OUTPUT)util/thread-stack.o
LIB_OBJS += $(OUTPUT)ui/setup.o
LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 8c7fe9d64e79..7be389735402 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -143,6 +143,32 @@ struct branch_stack {
struct branch_entry entries[0];
};
+enum {
+ PERF_IP_FLAG_BRANCH = 1ULL << 0,
+ PERF_IP_FLAG_CALL = 1ULL << 1,
+ PERF_IP_FLAG_RETURN = 1ULL << 2,
+ PERF_IP_FLAG_CONDITIONAL = 1ULL << 3,
+ PERF_IP_FLAG_SYSCALLRET = 1ULL << 4,
+ PERF_IP_FLAG_ASYNC = 1ULL << 5,
+ PERF_IP_FLAG_INTERRUPT = 1ULL << 6,
+ PERF_IP_FLAG_TX_ABORT = 1ULL << 7,
+ PERF_IP_FLAG_TRACE_BEGIN = 1ULL << 8,
+ PERF_IP_FLAG_TRACE_END = 1ULL << 9,
+ PERF_IP_FLAG_IN_TX = 1ULL << 10,
+};
+
+#define PERF_BRANCH_MASK (\
+ PERF_IP_FLAG_BRANCH |\
+ PERF_IP_FLAG_CALL |\
+ PERF_IP_FLAG_RETURN |\
+ PERF_IP_FLAG_CONDITIONAL |\
+ PERF_IP_FLAG_SYSCALLRET |\
+ PERF_IP_FLAG_ASYNC |\
+ PERF_IP_FLAG_INTERRUPT |\
+ PERF_IP_FLAG_TX_ABORT |\
+ PERF_IP_FLAG_TRACE_BEGIN |\
+ PERF_IP_FLAG_TRACE_END)
+
struct perf_sample {
u64 ip;
u32 pid, tid;
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
new file mode 100644
index 000000000000..85b60d2e738f
--- /dev/null
+++ b/tools/perf/util/thread-stack.c
@@ -0,0 +1,172 @@
+/*
+ * thread-stack.c: Synthesize a thread's stack using call / return events
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include "thread.h"
+#include "event.h"
+#include "util.h"
+#include "debug.h"
+#include "thread-stack.h"
+
+#define STACK_GROWTH 4096
+
+struct thread_stack_entry {
+ u64 ret_addr;
+};
+
+struct thread_stack {
+ struct thread_stack_entry *stack;
+ size_t cnt;
+ size_t sz;
+ u64 trace_nr;
+};
+
+static int thread_stack__grow(struct thread_stack *ts)
+{
+ struct thread_stack_entry *new_stack;
+ size_t sz, new_sz;
+
+ new_sz = ts->sz + STACK_GROWTH;
+ sz = new_sz * sizeof(struct thread_stack_entry);
+
+ new_stack = realloc(ts->stack, sz);
+ if (!new_stack)
+ return -ENOMEM;
+
+ ts->stack = new_stack;
+ ts->sz = new_sz;
+
+ return 0;
+}
+
+static struct thread_stack *thread_stack__new(void)
+{
+ struct thread_stack *ts;
+
+ ts = zalloc(sizeof(struct thread_stack));
+ if (!ts)
+ return NULL;
+
+ if (thread_stack__grow(ts)) {
+ free(ts);
+ return NULL;
+ }
+
+ return ts;
+}
+
+static int thread_stack__push(struct thread_stack *ts, u64 ret_addr)
+{
+ int err = 0;
+
+ if (ts->cnt == ts->sz) {
+ err = thread_stack__grow(ts);
+ if (err) {
+ pr_warning("Out of memory: discarding thread stack\n");
+ ts->cnt = 0;
+ }
+ }
+
+ ts->stack[ts->cnt++].ret_addr = ret_addr;
+
+ return err;
+}
+
+static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr)
+{
+ size_t i;
+
+ /*
+ * In some cases there may be functions which are not seen to return.
+ * For example when setjmp / longjmp has been used. Or the perf context
+ * switch in the kernel which doesn't stop and start tracing in exactly
+ * the same code path. When that happens the return address will be
+ * further down the stack. If the return address is not found at all,
+ * we assume the opposite (i.e. this is a return for a call that wasn't
+ * seen for some reason) and leave the stack alone.
+ */
+ for (i = ts->cnt; i; ) {
+ if (ts->stack[--i].ret_addr == ret_addr) {
+ ts->cnt = i;
+ return;
+ }
+ }
+}
+
+int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
+ u64 to_ip, u16 insn_len, u64 trace_nr)
+{
+ if (!thread)
+ return -EINVAL;
+
+ if (!thread->ts) {
+ thread->ts = thread_stack__new();
+ if (!thread->ts) {
+ pr_warning("Out of memory: no thread stack\n");
+ return -ENOMEM;
+ }
+ thread->ts->trace_nr = trace_nr;
+ }
+
+ /*
+ * When the trace is discontinuous, the trace_nr changes. In that case
+ * the stack might be completely invalid. Better to report nothing than
+ * to report something misleading, so reset the stack count to zero.
+ */
+ if (trace_nr != thread->ts->trace_nr) {
+ thread->ts->trace_nr = trace_nr;
+ thread->ts->cnt = 0;
+ }
+
+ if (flags & PERF_IP_FLAG_CALL) {
+ u64 ret_addr;
+
+ if (!to_ip)
+ return 0;
+ ret_addr = from_ip + insn_len;
+ if (ret_addr == to_ip)
+ return 0; /* Zero-length calls are excluded */
+ return thread_stack__push(thread->ts, ret_addr);
+ } else if (flags & PERF_IP_FLAG_RETURN) {
+ if (!from_ip)
+ return 0;
+ thread_stack__pop(thread->ts, to_ip);
+ }
+
+ return 0;
+}
+
+void thread_stack__free(struct thread *thread)
+{
+ if (thread->ts) {
+ zfree(&thread->ts->stack);
+ zfree(&thread->ts);
+ }
+}
+
+void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
+ size_t sz, u64 ip)
+{
+ size_t i;
+
+ if (!thread || !thread->ts)
+ chain->nr = 1;
+ else
+ chain->nr = min(sz, thread->ts->cnt + 1);
+
+ chain->ips[0] = ip;
+
+ for (i = 1; i < chain->nr; i++)
+ chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr;
+}
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h
new file mode 100644
index 000000000000..7c41579aec74
--- /dev/null
+++ b/tools/perf/util/thread-stack.h
@@ -0,0 +1,32 @@
+/*
+ * thread-stack.h: Synthesize a thread's stack using call / return events
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __PERF_THREAD_STACK_H
+#define __PERF_THREAD_STACK_H
+
+#include <sys/types.h>
+
+#include <linux/types.h>
+
+struct thread;
+struct ip_callchain;
+
+int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
+ u64 to_ip, u16 insn_len, u64 trace_nr);
+void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
+ size_t sz, u64 ip);
+void thread_stack__free(struct thread *thread);
+
+#endif
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index bf5bf858b7f6..a2157f0ef1df 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -4,6 +4,7 @@
#include <string.h>
#include "session.h"
#include "thread.h"
+#include "thread-stack.h"
#include "util.h"
#include "debug.h"
#include "comm.h"
@@ -66,6 +67,8 @@ void thread__delete(struct thread *thread)
{
struct comm *comm, *tmp;
+ thread_stack__free(thread);
+
if (thread->mg) {
map_groups__put(thread->mg);
thread->mg = NULL;
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index d34cf5c0d0d9..160fd066a7d1 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -8,6 +8,8 @@
#include "symbol.h"
#include <strlist.h>
+struct thread_stack;
+
struct thread {
union {
struct rb_node rb_node;
@@ -26,6 +28,7 @@ struct thread {
u64 db_id;
void *priv;
+ struct thread_stack *ts;
};
struct machine;
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 02/18] perf tools: Enhance the thread stack to output call/return data
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 01/18] perf tools: Add a thread stack for synthesizing call chains Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 03/18] perf tools: Add branch type to db export Arnaldo Carvalho de Melo
` (16 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Adrian Hunter, David Ahern, Frederic Weisbecker,
Jiri Olsa, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
Stephane Eranian, Arnaldo Carvalho de Melo
From: Adrian Hunter <adrian.hunter@intel.com>
Enhance the thread stack to output detailed information about paired
calls and returns.
The enhanced processing consumes sample information via
thread_stack__process() and outputs information about paired calls /
returns via a call-back.
While the call-back makes it possible for the facility to be used by
arbitrary tools, a subsequent patch will provide the information to
Python scripting via the db-export interface.
An important part of the call/return information is the
call path which provides a structure that defines a context
sensitive call graph.
Note that there are now two ways to use the thread stack.
For simply providing a call stack (like you would get from the perf
record -g option) the interface consists of thread_stack__event() and
thread_stack__sample().
Whereas the enhanced interface consists of call_return_processor__new()
and thread_stack__process().
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1414678188-14946-5-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/thread-stack.c | 585 ++++++++++++++++++++++++++++++++++++++++-
tools/perf/util/thread-stack.h | 79 ++++++
2 files changed, 659 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
index 85b60d2e738f..9ed59a452d1f 100644
--- a/tools/perf/util/thread-stack.c
+++ b/tools/perf/util/thread-stack.c
@@ -13,23 +13,96 @@
*
*/
+#include <linux/rbtree.h>
+#include <linux/list.h>
#include "thread.h"
#include "event.h"
+#include "machine.h"
#include "util.h"
#include "debug.h"
+#include "symbol.h"
+#include "comm.h"
#include "thread-stack.h"
-#define STACK_GROWTH 4096
+#define CALL_PATH_BLOCK_SHIFT 8
+#define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT)
+#define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1)
+struct call_path_block {
+ struct call_path cp[CALL_PATH_BLOCK_SIZE];
+ struct list_head node;
+};
+
+/**
+ * struct call_path_root - root of all call paths.
+ * @call_path: root call path
+ * @blocks: list of blocks to store call paths
+ * @next: next free space
+ * @sz: number of spaces
+ */
+struct call_path_root {
+ struct call_path call_path;
+ struct list_head blocks;
+ size_t next;
+ size_t sz;
+};
+
+/**
+ * struct call_return_processor - provides a call-back to consume call-return
+ * information.
+ * @cpr: call path root
+ * @process: call-back that accepts call/return information
+ * @data: anonymous data for call-back
+ */
+struct call_return_processor {
+ struct call_path_root *cpr;
+ int (*process)(struct call_return *cr, void *data);
+ void *data;
+};
+
+#define STACK_GROWTH 2048
+
+/**
+ * struct thread_stack_entry - thread stack entry.
+ * @ret_addr: return address
+ * @timestamp: timestamp (if known)
+ * @ref: external reference (e.g. db_id of sample)
+ * @branch_count: the branch count when the entry was created
+ * @cp: call path
+ * @no_call: a 'call' was not seen
+ */
struct thread_stack_entry {
u64 ret_addr;
+ u64 timestamp;
+ u64 ref;
+ u64 branch_count;
+ struct call_path *cp;
+ bool no_call;
};
+/**
+ * struct thread_stack - thread stack constructed from 'call' and 'return'
+ * branch samples.
+ * @stack: array that holds the stack
+ * @cnt: number of entries in the stack
+ * @sz: current maximum stack size
+ * @trace_nr: current trace number
+ * @branch_count: running branch count
+ * @kernel_start: kernel start address
+ * @last_time: last timestamp
+ * @crp: call/return processor
+ * @comm: current comm
+ */
struct thread_stack {
struct thread_stack_entry *stack;
size_t cnt;
size_t sz;
u64 trace_nr;
+ u64 branch_count;
+ u64 kernel_start;
+ u64 last_time;
+ struct call_return_processor *crp;
+ struct comm *comm;
};
static int thread_stack__grow(struct thread_stack *ts)
@@ -50,7 +123,8 @@ static int thread_stack__grow(struct thread_stack *ts)
return 0;
}
-static struct thread_stack *thread_stack__new(void)
+static struct thread_stack *thread_stack__new(struct thread *thread,
+ struct call_return_processor *crp)
{
struct thread_stack *ts;
@@ -63,6 +137,12 @@ static struct thread_stack *thread_stack__new(void)
return NULL;
}
+ if (thread->mg && thread->mg->machine)
+ ts->kernel_start = machine__kernel_start(thread->mg->machine);
+ else
+ ts->kernel_start = 1ULL << 63;
+ ts->crp = crp;
+
return ts;
}
@@ -104,6 +184,64 @@ static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr)
}
}
+static bool thread_stack__in_kernel(struct thread_stack *ts)
+{
+ if (!ts->cnt)
+ return false;
+
+ return ts->stack[ts->cnt - 1].cp->in_kernel;
+}
+
+static int thread_stack__call_return(struct thread *thread,
+ struct thread_stack *ts, size_t idx,
+ u64 timestamp, u64 ref, bool no_return)
+{
+ struct call_return_processor *crp = ts->crp;
+ struct thread_stack_entry *tse;
+ struct call_return cr = {
+ .thread = thread,
+ .comm = ts->comm,
+ .db_id = 0,
+ };
+
+ tse = &ts->stack[idx];
+ cr.cp = tse->cp;
+ cr.call_time = tse->timestamp;
+ cr.return_time = timestamp;
+ cr.branch_count = ts->branch_count - tse->branch_count;
+ cr.call_ref = tse->ref;
+ cr.return_ref = ref;
+ if (tse->no_call)
+ cr.flags |= CALL_RETURN_NO_CALL;
+ if (no_return)
+ cr.flags |= CALL_RETURN_NO_RETURN;
+
+ return crp->process(&cr, crp->data);
+}
+
+static int thread_stack__flush(struct thread *thread, struct thread_stack *ts)
+{
+ struct call_return_processor *crp = ts->crp;
+ int err;
+
+ if (!crp) {
+ ts->cnt = 0;
+ return 0;
+ }
+
+ while (ts->cnt) {
+ err = thread_stack__call_return(thread, ts, --ts->cnt,
+ ts->last_time, 0, true);
+ if (err) {
+ pr_err("Error flushing thread stack!\n");
+ ts->cnt = 0;
+ return err;
+ }
+ }
+
+ return 0;
+}
+
int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
u64 to_ip, u16 insn_len, u64 trace_nr)
{
@@ -111,7 +249,7 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
return -EINVAL;
if (!thread->ts) {
- thread->ts = thread_stack__new();
+ thread->ts = thread_stack__new(thread, NULL);
if (!thread->ts) {
pr_warning("Out of memory: no thread stack\n");
return -ENOMEM;
@@ -122,13 +260,18 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
/*
* When the trace is discontinuous, the trace_nr changes. In that case
* the stack might be completely invalid. Better to report nothing than
- * to report something misleading, so reset the stack count to zero.
+ * to report something misleading, so flush the stack.
*/
if (trace_nr != thread->ts->trace_nr) {
+ if (thread->ts->trace_nr)
+ thread_stack__flush(thread, thread->ts);
thread->ts->trace_nr = trace_nr;
- thread->ts->cnt = 0;
}
+ /* Stop here if thread_stack__process() is in use */
+ if (thread->ts->crp)
+ return 0;
+
if (flags & PERF_IP_FLAG_CALL) {
u64 ret_addr;
@@ -147,9 +290,22 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
return 0;
}
+void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr)
+{
+ if (!thread || !thread->ts)
+ return;
+
+ if (trace_nr != thread->ts->trace_nr) {
+ if (thread->ts->trace_nr)
+ thread_stack__flush(thread, thread->ts);
+ thread->ts->trace_nr = trace_nr;
+ }
+}
+
void thread_stack__free(struct thread *thread)
{
if (thread->ts) {
+ thread_stack__flush(thread, thread->ts);
zfree(&thread->ts->stack);
zfree(&thread->ts);
}
@@ -170,3 +326,422 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
for (i = 1; i < chain->nr; i++)
chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr;
}
+
+static void call_path__init(struct call_path *cp, struct call_path *parent,
+ struct symbol *sym, u64 ip, bool in_kernel)
+{
+ cp->parent = parent;
+ cp->sym = sym;
+ cp->ip = sym ? 0 : ip;
+ cp->db_id = 0;
+ cp->in_kernel = in_kernel;
+ RB_CLEAR_NODE(&cp->rb_node);
+ cp->children = RB_ROOT;
+}
+
+static struct call_path_root *call_path_root__new(void)
+{
+ struct call_path_root *cpr;
+
+ cpr = zalloc(sizeof(struct call_path_root));
+ if (!cpr)
+ return NULL;
+ call_path__init(&cpr->call_path, NULL, NULL, 0, false);
+ INIT_LIST_HEAD(&cpr->blocks);
+ return cpr;
+}
+
+static void call_path_root__free(struct call_path_root *cpr)
+{
+ struct call_path_block *pos, *n;
+
+ list_for_each_entry_safe(pos, n, &cpr->blocks, node) {
+ list_del(&pos->node);
+ free(pos);
+ }
+ free(cpr);
+}
+
+static struct call_path *call_path__new(struct call_path_root *cpr,
+ struct call_path *parent,
+ struct symbol *sym, u64 ip,
+ bool in_kernel)
+{
+ struct call_path_block *cpb;
+ struct call_path *cp;
+ size_t n;
+
+ if (cpr->next < cpr->sz) {
+ cpb = list_last_entry(&cpr->blocks, struct call_path_block,
+ node);
+ } else {
+ cpb = zalloc(sizeof(struct call_path_block));
+ if (!cpb)
+ return NULL;
+ list_add_tail(&cpb->node, &cpr->blocks);
+ cpr->sz += CALL_PATH_BLOCK_SIZE;
+ }
+
+ n = cpr->next++ & CALL_PATH_BLOCK_MASK;
+ cp = &cpb->cp[n];
+
+ call_path__init(cp, parent, sym, ip, in_kernel);
+
+ return cp;
+}
+
+static struct call_path *call_path__findnew(struct call_path_root *cpr,
+ struct call_path *parent,
+ struct symbol *sym, u64 ip, u64 ks)
+{
+ struct rb_node **p;
+ struct rb_node *node_parent = NULL;
+ struct call_path *cp;
+ bool in_kernel = ip >= ks;
+
+ if (sym)
+ ip = 0;
+
+ if (!parent)
+ return call_path__new(cpr, parent, sym, ip, in_kernel);
+
+ p = &parent->children.rb_node;
+ while (*p != NULL) {
+ node_parent = *p;
+ cp = rb_entry(node_parent, struct call_path, rb_node);
+
+ if (cp->sym == sym && cp->ip == ip)
+ return cp;
+
+ if (sym < cp->sym || (sym == cp->sym && ip < cp->ip))
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ cp = call_path__new(cpr, parent, sym, ip, in_kernel);
+ if (!cp)
+ return NULL;
+
+ rb_link_node(&cp->rb_node, node_parent, p);
+ rb_insert_color(&cp->rb_node, &parent->children);
+
+ return cp;
+}
+
+struct call_return_processor *
+call_return_processor__new(int (*process)(struct call_return *cr, void *data),
+ void *data)
+{
+ struct call_return_processor *crp;
+
+ crp = zalloc(sizeof(struct call_return_processor));
+ if (!crp)
+ return NULL;
+ crp->cpr = call_path_root__new();
+ if (!crp->cpr)
+ goto out_free;
+ crp->process = process;
+ crp->data = data;
+ return crp;
+
+out_free:
+ free(crp);
+ return NULL;
+}
+
+void call_return_processor__free(struct call_return_processor *crp)
+{
+ if (crp) {
+ call_path_root__free(crp->cpr);
+ free(crp);
+ }
+}
+
+static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
+ u64 timestamp, u64 ref, struct call_path *cp,
+ bool no_call)
+{
+ struct thread_stack_entry *tse;
+ int err;
+
+ if (ts->cnt == ts->sz) {
+ err = thread_stack__grow(ts);
+ if (err)
+ return err;
+ }
+
+ tse = &ts->stack[ts->cnt++];
+ tse->ret_addr = ret_addr;
+ tse->timestamp = timestamp;
+ tse->ref = ref;
+ tse->branch_count = ts->branch_count;
+ tse->cp = cp;
+ tse->no_call = no_call;
+
+ return 0;
+}
+
+static int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
+ u64 ret_addr, u64 timestamp, u64 ref,
+ struct symbol *sym)
+{
+ int err;
+
+ if (!ts->cnt)
+ return 1;
+
+ if (ts->cnt == 1) {
+ struct thread_stack_entry *tse = &ts->stack[0];
+
+ if (tse->cp->sym == sym)
+ return thread_stack__call_return(thread, ts, --ts->cnt,
+ timestamp, ref, false);
+ }
+
+ if (ts->stack[ts->cnt - 1].ret_addr == ret_addr) {
+ return thread_stack__call_return(thread, ts, --ts->cnt,
+ timestamp, ref, false);
+ } else {
+ size_t i = ts->cnt - 1;
+
+ while (i--) {
+ if (ts->stack[i].ret_addr != ret_addr)
+ continue;
+ i += 1;
+ while (ts->cnt > i) {
+ err = thread_stack__call_return(thread, ts,
+ --ts->cnt,
+ timestamp, ref,
+ true);
+ if (err)
+ return err;
+ }
+ return thread_stack__call_return(thread, ts, --ts->cnt,
+ timestamp, ref, false);
+ }
+ }
+
+ return 1;
+}
+
+static int thread_stack__bottom(struct thread *thread, struct thread_stack *ts,
+ struct perf_sample *sample,
+ struct addr_location *from_al,
+ struct addr_location *to_al, u64 ref)
+{
+ struct call_path_root *cpr = ts->crp->cpr;
+ struct call_path *cp;
+ struct symbol *sym;
+ u64 ip;
+
+ if (sample->ip) {
+ ip = sample->ip;
+ sym = from_al->sym;
+ } else if (sample->addr) {
+ ip = sample->addr;
+ sym = to_al->sym;
+ } else {
+ return 0;
+ }
+
+ cp = call_path__findnew(cpr, &cpr->call_path, sym, ip,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+
+ return thread_stack__push_cp(thread->ts, ip, sample->time, ref, cp,
+ true);
+}
+
+static int thread_stack__no_call_return(struct thread *thread,
+ struct thread_stack *ts,
+ struct perf_sample *sample,
+ struct addr_location *from_al,
+ struct addr_location *to_al, u64 ref)
+{
+ struct call_path_root *cpr = ts->crp->cpr;
+ struct call_path *cp, *parent;
+ u64 ks = ts->kernel_start;
+ int err;
+
+ if (sample->ip >= ks && sample->addr < ks) {
+ /* Return to userspace, so pop all kernel addresses */
+ while (thread_stack__in_kernel(ts)) {
+ err = thread_stack__call_return(thread, ts, --ts->cnt,
+ sample->time, ref,
+ true);
+ if (err)
+ return err;
+ }
+
+ /* If the stack is empty, push the userspace address */
+ if (!ts->cnt) {
+ cp = call_path__findnew(cpr, &cpr->call_path,
+ to_al->sym, sample->addr,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+ return thread_stack__push_cp(ts, 0, sample->time, ref,
+ cp, true);
+ }
+ } else if (thread_stack__in_kernel(ts) && sample->ip < ks) {
+ /* Return to userspace, so pop all kernel addresses */
+ while (thread_stack__in_kernel(ts)) {
+ err = thread_stack__call_return(thread, ts, --ts->cnt,
+ sample->time, ref,
+ true);
+ if (err)
+ return err;
+ }
+ }
+
+ if (ts->cnt)
+ parent = ts->stack[ts->cnt - 1].cp;
+ else
+ parent = &cpr->call_path;
+
+ /* This 'return' had no 'call', so push and pop top of stack */
+ cp = call_path__findnew(cpr, parent, from_al->sym, sample->ip,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+
+ err = thread_stack__push_cp(ts, sample->addr, sample->time, ref, cp,
+ true);
+ if (err)
+ return err;
+
+ return thread_stack__pop_cp(thread, ts, sample->addr, sample->time, ref,
+ to_al->sym);
+}
+
+static int thread_stack__trace_begin(struct thread *thread,
+ struct thread_stack *ts, u64 timestamp,
+ u64 ref)
+{
+ struct thread_stack_entry *tse;
+ int err;
+
+ if (!ts->cnt)
+ return 0;
+
+ /* Pop trace end */
+ tse = &ts->stack[ts->cnt - 1];
+ if (tse->cp->sym == NULL && tse->cp->ip == 0) {
+ err = thread_stack__call_return(thread, ts, --ts->cnt,
+ timestamp, ref, false);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int thread_stack__trace_end(struct thread_stack *ts,
+ struct perf_sample *sample, u64 ref)
+{
+ struct call_path_root *cpr = ts->crp->cpr;
+ struct call_path *cp;
+ u64 ret_addr;
+
+ /* No point having 'trace end' on the bottom of the stack */
+ if (!ts->cnt || (ts->cnt == 1 && ts->stack[0].ref == ref))
+ return 0;
+
+ cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp, NULL, 0,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+
+ ret_addr = sample->ip + sample->insn_len;
+
+ return thread_stack__push_cp(ts, ret_addr, sample->time, ref, cp,
+ false);
+}
+
+int thread_stack__process(struct thread *thread, struct comm *comm,
+ struct perf_sample *sample,
+ struct addr_location *from_al,
+ struct addr_location *to_al, u64 ref,
+ struct call_return_processor *crp)
+{
+ struct thread_stack *ts = thread->ts;
+ int err = 0;
+
+ if (ts) {
+ if (!ts->crp) {
+ /* Supersede thread_stack__event() */
+ thread_stack__free(thread);
+ thread->ts = thread_stack__new(thread, crp);
+ if (!thread->ts)
+ return -ENOMEM;
+ ts = thread->ts;
+ ts->comm = comm;
+ }
+ } else {
+ thread->ts = thread_stack__new(thread, crp);
+ if (!thread->ts)
+ return -ENOMEM;
+ ts = thread->ts;
+ ts->comm = comm;
+ }
+
+ /* Flush stack on exec */
+ if (ts->comm != comm && thread->pid_ == thread->tid) {
+ err = thread_stack__flush(thread, ts);
+ if (err)
+ return err;
+ ts->comm = comm;
+ }
+
+ /* If the stack is empty, put the current symbol on the stack */
+ if (!ts->cnt) {
+ err = thread_stack__bottom(thread, ts, sample, from_al, to_al,
+ ref);
+ if (err)
+ return err;
+ }
+
+ ts->branch_count += 1;
+ ts->last_time = sample->time;
+
+ if (sample->flags & PERF_IP_FLAG_CALL) {
+ struct call_path_root *cpr = ts->crp->cpr;
+ struct call_path *cp;
+ u64 ret_addr;
+
+ if (!sample->ip || !sample->addr)
+ return 0;
+
+ ret_addr = sample->ip + sample->insn_len;
+ if (ret_addr == sample->addr)
+ return 0; /* Zero-length calls are excluded */
+
+ cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp,
+ to_al->sym, sample->addr,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+ err = thread_stack__push_cp(ts, ret_addr, sample->time, ref,
+ cp, false);
+ } else if (sample->flags & PERF_IP_FLAG_RETURN) {
+ if (!sample->ip || !sample->addr)
+ return 0;
+
+ err = thread_stack__pop_cp(thread, ts, sample->addr,
+ sample->time, ref, from_al->sym);
+ if (err) {
+ if (err < 0)
+ return err;
+ err = thread_stack__no_call_return(thread, ts, sample,
+ from_al, to_al, ref);
+ }
+ } else if (sample->flags & PERF_IP_FLAG_TRACE_BEGIN) {
+ err = thread_stack__trace_begin(thread, ts, sample->time, ref);
+ } else if (sample->flags & PERF_IP_FLAG_TRACE_END) {
+ err = thread_stack__trace_end(ts, sample, ref);
+ }
+
+ return err;
+}
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h
index 7c41579aec74..b843bbef8ba2 100644
--- a/tools/perf/util/thread-stack.h
+++ b/tools/perf/util/thread-stack.h
@@ -19,14 +19,93 @@
#include <sys/types.h>
#include <linux/types.h>
+#include <linux/rbtree.h>
struct thread;
+struct comm;
struct ip_callchain;
+struct symbol;
+struct dso;
+struct call_return_processor;
+struct comm;
+struct perf_sample;
+struct addr_location;
+
+/*
+ * Call/Return flags.
+ *
+ * CALL_RETURN_NO_CALL: 'return' but no matching 'call'
+ * CALL_RETURN_NO_RETURN: 'call' but no matching 'return'
+ */
+enum {
+ CALL_RETURN_NO_CALL = 1 << 0,
+ CALL_RETURN_NO_RETURN = 1 << 1,
+};
+
+/**
+ * struct call_return - paired call/return information.
+ * @thread: thread in which call/return occurred
+ * @comm: comm in which call/return occurred
+ * @cp: call path
+ * @call_time: timestamp of call (if known)
+ * @return_time: timestamp of return (if known)
+ * @branch_count: number of branches seen between call and return
+ * @call_ref: external reference to 'call' sample (e.g. db_id)
+ * @return_ref: external reference to 'return' sample (e.g. db_id)
+ * @db_id: id used for db-export
+ * @flags: Call/Return flags
+ */
+struct call_return {
+ struct thread *thread;
+ struct comm *comm;
+ struct call_path *cp;
+ u64 call_time;
+ u64 return_time;
+ u64 branch_count;
+ u64 call_ref;
+ u64 return_ref;
+ u64 db_id;
+ u32 flags;
+};
+
+/**
+ * struct call_path - node in list of calls leading to a function call.
+ * @parent: call path to the parent function call
+ * @sym: symbol of function called
+ * @ip: only if sym is null, the ip of the function
+ * @db_id: id used for db-export
+ * @in_kernel: whether function is a in the kernel
+ * @rb_node: node in parent's tree of called functions
+ * @children: tree of call paths of functions called
+ *
+ * In combination with the call_return structure, the call_path structure
+ * defines a context-sensitve call-graph.
+ */
+struct call_path {
+ struct call_path *parent;
+ struct symbol *sym;
+ u64 ip;
+ u64 db_id;
+ bool in_kernel;
+ struct rb_node rb_node;
+ struct rb_root children;
+};
int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
u64 to_ip, u16 insn_len, u64 trace_nr);
+void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr);
void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
size_t sz, u64 ip);
void thread_stack__free(struct thread *thread);
+struct call_return_processor *
+call_return_processor__new(int (*process)(struct call_return *cr, void *data),
+ void *data);
+void call_return_processor__free(struct call_return_processor *crp);
+int thread_stack__process(struct thread *thread, struct comm *comm,
+ struct perf_sample *sample,
+ struct addr_location *from_al,
+ struct addr_location *to_al, u64 ref,
+ struct call_return_processor *crp);
+
#endif
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 03/18] perf tools: Add branch type to db export
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 01/18] perf tools: Add a thread stack for synthesizing call chains Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 02/18] perf tools: Enhance the thread stack to output call/return data Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 04/18] perf tools: Add branch_type and in_tx to Python export Arnaldo Carvalho de Melo
` (15 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Adrian Hunter, David Ahern, Frederic Weisbecker,
Jiri Olsa, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
Stephane Eranian, Arnaldo Carvalho de Melo
From: Adrian Hunter <adrian.hunter@intel.com>
Add the ability to export branch types through the database export
facility.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1414678188-14946-3-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/db-export.c | 48 +++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/db-export.h | 6 ++++++
2 files changed, 54 insertions(+)
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index be128b075a32..bccb83120971 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -208,6 +208,15 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
return 0;
}
+int db_export__branch_type(struct db_export *dbe, u32 branch_type,
+ const char *name)
+{
+ if (dbe->export_branch_type)
+ return dbe->export_branch_type(dbe, branch_type, name);
+
+ return 0;
+}
+
int db_export__sample(struct db_export *dbe, union perf_event *event,
struct perf_sample *sample, struct perf_evsel *evsel,
struct thread *thread, struct addr_location *al)
@@ -268,3 +277,42 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
return 0;
}
+
+static struct {
+ u32 branch_type;
+ const char *name;
+} branch_types[] = {
+ {0, "no branch"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
+ {PERF_IP_FLAG_BRANCH, "unconditional jump"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
+ "software interrupt"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
+ "return from interrupt"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
+ "system call"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
+ "return from system call"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
+ PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
+ {0, NULL}
+};
+
+int db_export__branch_types(struct db_export *dbe)
+{
+ int i, err = 0;
+
+ for (i = 0; branch_types[i].name ; i++) {
+ err = db_export__branch_type(dbe, branch_types[i].branch_type,
+ branch_types[i].name);
+ if (err)
+ break;
+ }
+ return err;
+}
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
index b3643e8e5750..e4baa45ead70 100644
--- a/tools/perf/util/db-export.h
+++ b/tools/perf/util/db-export.h
@@ -54,6 +54,8 @@ struct db_export {
struct machine *machine);
int (*export_symbol)(struct db_export *dbe, struct symbol *sym,
struct dso *dso);
+ int (*export_branch_type)(struct db_export *dbe, u32 branch_type,
+ const char *name);
int (*export_sample)(struct db_export *dbe, struct export_sample *es);
u64 evsel_last_db_id;
u64 machine_last_db_id;
@@ -79,8 +81,12 @@ int db_export__dso(struct db_export *dbe, struct dso *dso,
struct machine *machine);
int db_export__symbol(struct db_export *dbe, struct symbol *sym,
struct dso *dso);
+int db_export__branch_type(struct db_export *dbe, u32 branch_type,
+ const char *name);
int db_export__sample(struct db_export *dbe, union perf_event *event,
struct perf_sample *sample, struct perf_evsel *evsel,
struct thread *thread, struct addr_location *al);
+int db_export__branch_types(struct db_export *dbe);
+
#endif
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 04/18] perf tools: Add branch_type and in_tx to Python export
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (2 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 03/18] perf tools: Add branch type to db export Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 05/18] perf tools: Add call information to the database export API Arnaldo Carvalho de Melo
` (14 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Adrian Hunter, David Ahern, Frederic Weisbecker,
Jiri Olsa, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
Stephane Eranian, Arnaldo Carvalho de Melo
From: Adrian Hunter <adrian.hunter@intel.com>
Add branch_type and in_tx to Python db export and the
export-to-postgresql.py script.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1414678188-14946-4-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/scripts/python/export-to-postgresql.py | 32 ++++++++++++++++++----
.../util/scripting-engines/trace-event-python.c | 30 +++++++++++++++++++-
2 files changed, 55 insertions(+), 7 deletions(-)
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
index d8f6df0093d6..bb79aecccf58 100644
--- a/tools/perf/scripts/python/export-to-postgresql.py
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -123,6 +123,10 @@ do_query(query, 'CREATE TABLE symbols ('
'sym_end bigint,'
'binding integer,'
'name varchar(2048))')
+do_query(query, 'CREATE TABLE branch_types ('
+ 'id integer NOT NULL,'
+ 'name varchar(80))')
+
if branches:
do_query(query, 'CREATE TABLE samples ('
'id bigint NOT NULL,'
@@ -139,7 +143,9 @@ if branches:
'to_dso_id bigint,'
'to_symbol_id bigint,'
'to_sym_offset bigint,'
- 'to_ip bigint)')
+ 'to_ip bigint,'
+ 'branch_type integer,'
+ 'in_tx boolean)')
else:
do_query(query, 'CREATE TABLE samples ('
'id bigint NOT NULL,'
@@ -160,7 +166,9 @@ else:
'period bigint,'
'weight bigint,'
'transaction bigint,'
- 'data_src bigint)')
+ 'data_src bigint,'
+ 'branch_type integer,'
+ 'in_tx boolean)')
do_query(query, 'CREATE VIEW samples_view AS '
'SELECT '
@@ -178,7 +186,9 @@ do_query(query, 'CREATE VIEW samples_view AS '
'to_hex(to_ip) AS to_ip_hex,'
'(SELECT name FROM symbols WHERE id = to_symbol_id) AS to_symbol,'
'to_sym_offset,'
- '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name'
+ '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,'
+ '(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,'
+ 'in_tx'
' FROM samples')
@@ -234,6 +244,7 @@ comm_file = open_output_file("comm_table.bin")
comm_thread_file = open_output_file("comm_thread_table.bin")
dso_file = open_output_file("dso_table.bin")
symbol_file = open_output_file("symbol_table.bin")
+branch_type_file = open_output_file("branch_type_table.bin")
sample_file = open_output_file("sample_table.bin")
def trace_begin():
@@ -257,6 +268,7 @@ def trace_end():
copy_output_file(comm_thread_file, "comm_threads")
copy_output_file(dso_file, "dsos")
copy_output_file(symbol_file, "symbols")
+ copy_output_file(branch_type_file, "branch_types")
copy_output_file(sample_file, "samples")
print datetime.datetime.today(), "Removing intermediate files..."
@@ -267,6 +279,7 @@ def trace_end():
remove_output_file(comm_thread_file)
remove_output_file(dso_file)
remove_output_file(symbol_file)
+ remove_output_file(branch_type_file)
remove_output_file(sample_file)
os.rmdir(output_dir_name)
print datetime.datetime.today(), "Adding primary keys"
@@ -277,6 +290,7 @@ def trace_end():
do_query(query, 'ALTER TABLE comm_threads ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE dsos ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)')
print datetime.datetime.today(), "Adding foreign keys"
@@ -352,9 +366,15 @@ def symbol_table(symbol_id, dso_id, sym_start, sym_end, binding, symbol_name, *x
value = struct.pack(fmt, 6, 8, symbol_id, 8, dso_id, 8, sym_start, 8, sym_end, 4, binding, n, symbol_name)
symbol_file.write(value)
-def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, *x):
+def branch_type_table(branch_type, name, *x):
+ n = len(name)
+ fmt = "!hiii" + str(n) + "s"
+ value = struct.pack(fmt, 2, 4, branch_type, n, name)
+ branch_type_file.write(value)
+
+def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, *x):
if branches:
- value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiq", 15, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip)
+ value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiB", 17, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx)
else:
- value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiq", 19, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src)
+ value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx)
sample_file.write(value)
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 2fd7ee8f18c7..f3ca7798b3d0 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -66,6 +66,7 @@ struct tables {
PyObject *comm_thread_handler;
PyObject *dso_handler;
PyObject *symbol_handler;
+ PyObject *branch_type_handler;
PyObject *sample_handler;
bool db_export_mode;
};
@@ -664,13 +665,31 @@ static int python_export_symbol(struct db_export *dbe, struct symbol *sym,
return 0;
}
+static int python_export_branch_type(struct db_export *dbe, u32 branch_type,
+ const char *name)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+
+ t = tuple_new(2);
+
+ tuple_set_s32(t, 0, branch_type);
+ tuple_set_string(t, 1, name);
+
+ call_object(tables->branch_type_handler, t, "branch_type_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
static int python_export_sample(struct db_export *dbe,
struct export_sample *es)
{
struct tables *tables = container_of(dbe, struct tables, dbe);
PyObject *t;
- t = tuple_new(19);
+ t = tuple_new(21);
tuple_set_u64(t, 0, es->db_id);
tuple_set_u64(t, 1, es->evsel->db_id);
@@ -691,6 +710,8 @@ static int python_export_sample(struct db_export *dbe,
tuple_set_u64(t, 16, es->sample->weight);
tuple_set_u64(t, 17, es->sample->transaction);
tuple_set_u64(t, 18, es->sample->data_src);
+ tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK);
+ tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX));
call_object(tables->sample_handler, t, "sample_table");
@@ -861,6 +882,7 @@ static void set_table_handlers(struct tables *tables)
SET_TABLE_HANDLER(comm_thread);
SET_TABLE_HANDLER(dso);
SET_TABLE_HANDLER(symbol);
+ SET_TABLE_HANDLER(branch_type);
SET_TABLE_HANDLER(sample);
}
@@ -910,6 +932,12 @@ static int python_start_script(const char *script, int argc, const char **argv)
set_table_handlers(tables);
+ if (tables->db_export_mode) {
+ err = db_export__branch_types(&tables->dbe);
+ if (err)
+ goto error;
+ }
+
return err;
error:
Py_Finalize();
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 05/18] perf tools: Add call information to the database export API
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (3 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 04/18] perf tools: Add branch_type and in_tx to Python export Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 06/18] perf tools: Add call information to Python export Arnaldo Carvalho de Melo
` (13 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Adrian Hunter, David Ahern, Frederic Weisbecker,
Jiri Olsa, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
Stephane Eranian, Arnaldo Carvalho de Melo
From: Adrian Hunter <adrian.hunter@intel.com>
Make it possible for the database export API to use the enhanced thread
stack and export detailed information about paired calls and returns.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1414678188-14946-6-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/db-export.c | 52 ++++++++++++++++++++++++++++++++++++++++++++-
tools/perf/util/db-export.h | 12 +++++++++++
2 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index bccb83120971..017ecbb0ec05 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -21,6 +21,7 @@
#include "comm.h"
#include "symbol.h"
#include "event.h"
+#include "thread-stack.h"
#include "db-export.h"
int db_export__init(struct db_export *dbe)
@@ -29,8 +30,10 @@ int db_export__init(struct db_export *dbe)
return 0;
}
-void db_export__exit(struct db_export *dbe __maybe_unused)
+void db_export__exit(struct db_export *dbe)
{
+ call_return_processor__free(dbe->crp);
+ dbe->crp = NULL;
}
int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel)
@@ -270,6 +273,13 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
&es.addr_sym_db_id, &es.addr_offset);
if (err)
return err;
+ if (dbe->crp) {
+ err = thread_stack__process(thread, comm, sample, al,
+ &addr_al, es.db_id,
+ dbe->crp);
+ if (err)
+ return err;
+ }
}
if (dbe->export_sample)
@@ -316,3 +326,43 @@ int db_export__branch_types(struct db_export *dbe)
}
return err;
}
+
+int db_export__call_path(struct db_export *dbe, struct call_path *cp)
+{
+ int err;
+
+ if (cp->db_id)
+ return 0;
+
+ if (cp->parent) {
+ err = db_export__call_path(dbe, cp->parent);
+ if (err)
+ return err;
+ }
+
+ cp->db_id = ++dbe->call_path_last_db_id;
+
+ if (dbe->export_call_path)
+ return dbe->export_call_path(dbe, cp);
+
+ return 0;
+}
+
+int db_export__call_return(struct db_export *dbe, struct call_return *cr)
+{
+ int err;
+
+ if (cr->db_id)
+ return 0;
+
+ err = db_export__call_path(dbe, cr->cp);
+ if (err)
+ return err;
+
+ cr->db_id = ++dbe->call_return_last_db_id;
+
+ if (dbe->export_call_return)
+ return dbe->export_call_return(dbe, cr);
+
+ return 0;
+}
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
index e4baa45ead70..dd5ac2ae97d4 100644
--- a/tools/perf/util/db-export.h
+++ b/tools/perf/util/db-export.h
@@ -25,6 +25,9 @@ struct comm;
struct dso;
struct perf_sample;
struct addr_location;
+struct call_return_processor;
+struct call_path;
+struct call_return;
struct export_sample {
union perf_event *event;
@@ -57,6 +60,10 @@ struct db_export {
int (*export_branch_type)(struct db_export *dbe, u32 branch_type,
const char *name);
int (*export_sample)(struct db_export *dbe, struct export_sample *es);
+ int (*export_call_path)(struct db_export *dbe, struct call_path *cp);
+ int (*export_call_return)(struct db_export *dbe,
+ struct call_return *cr);
+ struct call_return_processor *crp;
u64 evsel_last_db_id;
u64 machine_last_db_id;
u64 thread_last_db_id;
@@ -65,6 +72,8 @@ struct db_export {
u64 dso_last_db_id;
u64 symbol_last_db_id;
u64 sample_last_db_id;
+ u64 call_path_last_db_id;
+ u64 call_return_last_db_id;
};
int db_export__init(struct db_export *dbe);
@@ -89,4 +98,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
int db_export__branch_types(struct db_export *dbe);
+int db_export__call_path(struct db_export *dbe, struct call_path *cp);
+int db_export__call_return(struct db_export *dbe, struct call_return *cr);
+
#endif
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 06/18] perf tools: Add call information to Python export
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (4 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 05/18] perf tools: Add call information to the database export API Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 07/18] perf tools: Defer export of comms that were not 'set' Arnaldo Carvalho de Melo
` (12 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Adrian Hunter, David Ahern, Frederic Weisbecker,
Jiri Olsa, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
Stephane Eranian, Arnaldo Carvalho de Melo
From: Adrian Hunter <adrian.hunter@intel.com>
Add the ability to export detailed information about paired calls and
returns to Python db export and the export-to-postgresql.py script.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1414678188-14946-7-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
.../scripts/python/bin/export-to-postgresql-report | 15 ++--
tools/perf/scripts/python/export-to-postgresql.py | 66 ++++++++++++++++-
.../util/scripting-engines/trace-event-python.c | 84 +++++++++++++++++++++-
3 files changed, 158 insertions(+), 7 deletions(-)
diff --git a/tools/perf/scripts/python/bin/export-to-postgresql-report b/tools/perf/scripts/python/bin/export-to-postgresql-report
index a8fdd15f85bf..cd335b6e2a01 100644
--- a/tools/perf/scripts/python/bin/export-to-postgresql-report
+++ b/tools/perf/scripts/python/bin/export-to-postgresql-report
@@ -1,6 +1,6 @@
#!/bin/bash
# description: export perf data to a postgresql database
-# args: [database name] [columns]
+# args: [database name] [columns] [calls]
n_args=0
for i in "$@"
do
@@ -9,11 +9,16 @@ do
fi
n_args=$(( $n_args + 1 ))
done
-if [ "$n_args" -gt 2 ] ; then
- echo "usage: export-to-postgresql-report [database name] [columns]"
+if [ "$n_args" -gt 3 ] ; then
+ echo "usage: export-to-postgresql-report [database name] [columns] [calls]"
exit
fi
-if [ "$n_args" -gt 1 ] ; then
+if [ "$n_args" -gt 2 ] ; then
+ dbname=$1
+ columns=$2
+ calls=$3
+ shift 3
+elif [ "$n_args" -gt 1 ] ; then
dbname=$1
columns=$2
shift 2
@@ -21,4 +26,4 @@ elif [ "$n_args" -gt 0 ] ; then
dbname=$1
shift
fi
-perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns
+perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns $calls
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
index bb79aecccf58..4cdafd880074 100644
--- a/tools/perf/scripts/python/export-to-postgresql.py
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -40,10 +40,12 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
#from Core import *
perf_db_export_mode = True
+perf_db_export_calls = False
def usage():
- print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>]"
+ print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>]"
print >> sys.stderr, "where: columns 'all' or 'branches'"
+ print >> sys.stderr, " calls 'calls' => create calls table"
raise Exception("Too few arguments")
if (len(sys.argv) < 2):
@@ -61,6 +63,12 @@ if columns not in ("all", "branches"):
branches = (columns == "branches")
+if (len(sys.argv) >= 4):
+ if (sys.argv[3] == "calls"):
+ perf_db_export_calls = True
+ else:
+ usage()
+
output_dir_name = os.getcwd() + "/" + dbname + "-perf-data"
os.mkdir(output_dir_name)
@@ -170,6 +178,25 @@ else:
'branch_type integer,'
'in_tx boolean)')
+if perf_db_export_calls:
+ do_query(query, 'CREATE TABLE call_paths ('
+ 'id bigint NOT NULL,'
+ 'parent_id bigint,'
+ 'symbol_id bigint,'
+ 'ip bigint)')
+ do_query(query, 'CREATE TABLE calls ('
+ 'id bigint NOT NULL,'
+ 'thread_id bigint,'
+ 'comm_id bigint,'
+ 'call_path_id bigint,'
+ 'call_time bigint,'
+ 'return_time bigint,'
+ 'branch_count bigint,'
+ 'call_id bigint,'
+ 'return_id bigint,'
+ 'parent_call_path_id bigint,'
+ 'flags integer)')
+
do_query(query, 'CREATE VIEW samples_view AS '
'SELECT '
'id,'
@@ -246,6 +273,9 @@ dso_file = open_output_file("dso_table.bin")
symbol_file = open_output_file("symbol_table.bin")
branch_type_file = open_output_file("branch_type_table.bin")
sample_file = open_output_file("sample_table.bin")
+if perf_db_export_calls:
+ call_path_file = open_output_file("call_path_table.bin")
+ call_file = open_output_file("call_table.bin")
def trace_begin():
print datetime.datetime.today(), "Writing to intermediate files..."
@@ -256,6 +286,9 @@ def trace_begin():
comm_table(0, "unknown")
dso_table(0, 0, "unknown", "unknown", "")
symbol_table(0, 0, 0, 0, 0, "unknown")
+ sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ if perf_db_export_calls:
+ call_path_table(0, 0, 0, 0)
unhandled_count = 0
@@ -270,6 +303,9 @@ def trace_end():
copy_output_file(symbol_file, "symbols")
copy_output_file(branch_type_file, "branch_types")
copy_output_file(sample_file, "samples")
+ if perf_db_export_calls:
+ copy_output_file(call_path_file, "call_paths")
+ copy_output_file(call_file, "calls")
print datetime.datetime.today(), "Removing intermediate files..."
remove_output_file(evsel_file)
@@ -281,6 +317,9 @@ def trace_end():
remove_output_file(symbol_file)
remove_output_file(branch_type_file)
remove_output_file(sample_file)
+ if perf_db_export_calls:
+ remove_output_file(call_path_file)
+ remove_output_file(call_file)
os.rmdir(output_dir_name)
print datetime.datetime.today(), "Adding primary keys"
do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)')
@@ -292,6 +331,9 @@ def trace_end():
do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)')
+ if perf_db_export_calls:
+ do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)')
print datetime.datetime.today(), "Adding foreign keys"
do_query(query, 'ALTER TABLE threads '
@@ -313,6 +355,18 @@ def trace_end():
'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),'
'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),'
'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)')
+ if perf_db_export_calls:
+ do_query(query, 'ALTER TABLE call_paths '
+ 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),'
+ 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)')
+ do_query(query, 'ALTER TABLE calls '
+ 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),'
+ 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
+ 'ADD CONSTRAINT call_pathfk FOREIGN KEY (call_path_id) REFERENCES call_paths (id),'
+ 'ADD CONSTRAINT callfk FOREIGN KEY (call_id) REFERENCES samples (id),'
+ 'ADD CONSTRAINT returnfk FOREIGN KEY (return_id) REFERENCES samples (id),'
+ 'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)')
+ do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
if (unhandled_count):
print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events"
@@ -378,3 +432,13 @@ def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, sy
else:
value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx)
sample_file.write(value)
+
+def call_path_table(cp_id, parent_id, symbol_id, ip, *x):
+ fmt = "!hiqiqiqiq"
+ value = struct.pack(fmt, 4, 8, cp_id, 8, parent_id, 8, symbol_id, 8, ip)
+ call_path_file.write(value)
+
+def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return_time, branch_count, call_id, return_id, parent_call_path_id, flags, *x):
+ fmt = "!hiqiqiqiqiqiqiqiqiqiqii"
+ value = struct.pack(fmt, 11, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags)
+ call_file.write(value)
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index f3ca7798b3d0..cb1d9602f418 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -37,6 +37,7 @@
#include "../comm.h"
#include "../machine.h"
#include "../db-export.h"
+#include "../thread-stack.h"
#include "../trace-event.h"
#include "../machine.h"
@@ -68,6 +69,8 @@ struct tables {
PyObject *symbol_handler;
PyObject *branch_type_handler;
PyObject *sample_handler;
+ PyObject *call_path_handler;
+ PyObject *call_return_handler;
bool db_export_mode;
};
@@ -720,6 +723,64 @@ static int python_export_sample(struct db_export *dbe,
return 0;
}
+static int python_export_call_path(struct db_export *dbe, struct call_path *cp)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+ u64 parent_db_id, sym_db_id;
+
+ parent_db_id = cp->parent ? cp->parent->db_id : 0;
+ sym_db_id = cp->sym ? *(u64 *)symbol__priv(cp->sym) : 0;
+
+ t = tuple_new(4);
+
+ tuple_set_u64(t, 0, cp->db_id);
+ tuple_set_u64(t, 1, parent_db_id);
+ tuple_set_u64(t, 2, sym_db_id);
+ tuple_set_u64(t, 3, cp->ip);
+
+ call_object(tables->call_path_handler, t, "call_path_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_call_return(struct db_export *dbe,
+ struct call_return *cr)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ u64 comm_db_id = cr->comm ? cr->comm->db_id : 0;
+ PyObject *t;
+
+ t = tuple_new(11);
+
+ tuple_set_u64(t, 0, cr->db_id);
+ tuple_set_u64(t, 1, cr->thread->db_id);
+ tuple_set_u64(t, 2, comm_db_id);
+ tuple_set_u64(t, 3, cr->cp->db_id);
+ tuple_set_u64(t, 4, cr->call_time);
+ tuple_set_u64(t, 5, cr->return_time);
+ tuple_set_u64(t, 6, cr->branch_count);
+ tuple_set_u64(t, 7, cr->call_ref);
+ tuple_set_u64(t, 8, cr->return_ref);
+ tuple_set_u64(t, 9, cr->cp->parent->db_id);
+ tuple_set_s32(t, 10, cr->flags);
+
+ call_object(tables->call_return_handler, t, "call_return_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_process_call_return(struct call_return *cr, void *data)
+{
+ struct db_export *dbe = data;
+
+ return db_export__call_return(dbe, cr);
+}
+
static void python_process_general_event(struct perf_sample *sample,
struct perf_evsel *evsel,
struct thread *thread,
@@ -852,7 +913,9 @@ error:
static void set_table_handlers(struct tables *tables)
{
const char *perf_db_export_mode = "perf_db_export_mode";
- PyObject *db_export_mode;
+ const char *perf_db_export_calls = "perf_db_export_calls";
+ PyObject *db_export_mode, *db_export_calls;
+ bool export_calls = false;
int ret;
memset(tables, 0, sizeof(struct tables));
@@ -869,6 +932,23 @@ static void set_table_handlers(struct tables *tables)
if (!ret)
return;
+ tables->dbe.crp = NULL;
+ db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls);
+ if (db_export_calls) {
+ ret = PyObject_IsTrue(db_export_calls);
+ if (ret == -1)
+ handler_call_die(perf_db_export_calls);
+ export_calls = !!ret;
+ }
+
+ if (export_calls) {
+ tables->dbe.crp =
+ call_return_processor__new(python_process_call_return,
+ &tables->dbe);
+ if (!tables->dbe.crp)
+ Py_FatalError("failed to create calls processor");
+ }
+
tables->db_export_mode = true;
/*
* Reserve per symbol space for symbol->db_id via symbol__priv()
@@ -884,6 +964,8 @@ static void set_table_handlers(struct tables *tables)
SET_TABLE_HANDLER(symbol);
SET_TABLE_HANDLER(branch_type);
SET_TABLE_HANDLER(sample);
+ SET_TABLE_HANDLER(call_path);
+ SET_TABLE_HANDLER(call_return);
}
/*
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 07/18] perf tools: Defer export of comms that were not 'set'
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (5 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 06/18] perf tools: Add call information to Python export Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 08/18] perf symbols: Preparation for compressed kernel module support Arnaldo Carvalho de Melo
` (11 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Adrian Hunter, David Ahern, Frederic Weisbecker,
Jiri Olsa, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
Stephane Eranian, Arnaldo Carvalho de Melo
From: Adrian Hunter <adrian.hunter@intel.com>
Tracing for a workload begins before the comm event is seen, which
results in the initial comm having a string of the form ":<pid>" (e.g.
":12345").
In order to export the correct string, defer the export until the new
script 'flush' callback.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1414678188-14946-8-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/db-export.c | 62 +++++++++++++++++++++-
tools/perf/util/db-export.h | 3 ++
.../util/scripting-engines/trace-event-python.c | 4 +-
3 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index 017ecbb0ec05..c81dae399763 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -21,17 +21,74 @@
#include "comm.h"
#include "symbol.h"
#include "event.h"
+#include "util.h"
#include "thread-stack.h"
#include "db-export.h"
+struct deferred_export {
+ struct list_head node;
+ struct comm *comm;
+};
+
+static int db_export__deferred(struct db_export *dbe)
+{
+ struct deferred_export *de;
+ int err;
+
+ while (!list_empty(&dbe->deferred)) {
+ de = list_entry(dbe->deferred.next, struct deferred_export,
+ node);
+ err = dbe->export_comm(dbe, de->comm);
+ list_del(&de->node);
+ free(de);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static void db_export__free_deferred(struct db_export *dbe)
+{
+ struct deferred_export *de;
+
+ while (!list_empty(&dbe->deferred)) {
+ de = list_entry(dbe->deferred.next, struct deferred_export,
+ node);
+ list_del(&de->node);
+ free(de);
+ }
+}
+
+static int db_export__defer_comm(struct db_export *dbe, struct comm *comm)
+{
+ struct deferred_export *de;
+
+ de = zalloc(sizeof(struct deferred_export));
+ if (!de)
+ return -ENOMEM;
+
+ de->comm = comm;
+ list_add_tail(&de->node, &dbe->deferred);
+
+ return 0;
+}
+
int db_export__init(struct db_export *dbe)
{
memset(dbe, 0, sizeof(struct db_export));
+ INIT_LIST_HEAD(&dbe->deferred);
return 0;
}
+int db_export__flush(struct db_export *dbe)
+{
+ return db_export__deferred(dbe);
+}
+
void db_export__exit(struct db_export *dbe)
{
+ db_export__free_deferred(dbe);
call_return_processor__free(dbe->crp);
dbe->crp = NULL;
}
@@ -115,7 +172,10 @@ int db_export__comm(struct db_export *dbe, struct comm *comm,
comm->db_id = ++dbe->comm_last_db_id;
if (dbe->export_comm) {
- err = dbe->export_comm(dbe, comm);
+ if (main_thread->comm_set)
+ err = dbe->export_comm(dbe, comm);
+ else
+ err = db_export__defer_comm(dbe, comm);
if (err)
return err;
}
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
index dd5ac2ae97d4..adbd22d66798 100644
--- a/tools/perf/util/db-export.h
+++ b/tools/perf/util/db-export.h
@@ -17,6 +17,7 @@
#define __PERF_DB_EXPORT_H
#include <linux/types.h>
+#include <linux/list.h>
struct perf_evsel;
struct machine;
@@ -74,9 +75,11 @@ struct db_export {
u64 sample_last_db_id;
u64 call_path_last_db_id;
u64 call_return_last_db_id;
+ struct list_head deferred;
};
int db_export__init(struct db_export *dbe);
+int db_export__flush(struct db_export *dbe);
void db_export__exit(struct db_export *dbe);
int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel);
int db_export__machine(struct db_export *dbe, struct machine *machine);
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index cb1d9602f418..118bc62850a8 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -1030,7 +1030,9 @@ error:
static int python_flush_script(void)
{
- return 0;
+ struct tables *tables = &tables_global;
+
+ return db_export__flush(&tables->dbe);
}
/*
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 08/18] perf symbols: Preparation for compressed kernel module support
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (6 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 07/18] perf tools: Defer export of comms that were not 'set' Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 09/18] perf tools: Add gzip decompression support for kernel module Arnaldo Carvalho de Melo
` (10 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Namhyung Kim, Adrian Hunter, David Ahern, Jiri Olsa,
Namhyung Kim, Paul Mackerras, Peter Zijlstra, Stephane Eranian,
Arnaldo Carvalho de Melo
From: Namhyung Kim <namhyung@kernel.org>
This patch adds basic support to handle compressed kernel module as some
distro (such as Archlinux) carries on it now. The actual work using
compression library will be added later.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-2-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/dso.c | 75 ++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/dso.h | 7 +++++
tools/perf/util/machine.c | 19 ++++++++++-
tools/perf/util/symbol-elf.c | 35 ++++++++++++++++++++-
tools/perf/util/symbol.c | 8 ++++-
5 files changed, 141 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 0247acfdfaca..36a607cf8f50 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -21,8 +21,10 @@ char dso__symtab_origin(const struct dso *dso)
[DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
[DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
+ [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP] = 'm',
[DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
[DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
+ [DSO_BINARY_TYPE__GUEST_KMODULE_COMP] = 'M',
[DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
};
@@ -112,11 +114,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
break;
case DSO_BINARY_TYPE__GUEST_KMODULE:
+ case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
path__join3(filename, size, symbol_conf.symfs,
root_dir, dso->long_name);
break;
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+ case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
__symbol__join_symfs(filename, size, dso->long_name);
break;
@@ -137,6 +141,77 @@ int dso__read_binary_type_filename(const struct dso *dso,
return ret;
}
+static int decompress_dummy(const char *input __maybe_unused,
+ int output __maybe_unused)
+{
+ return -1;
+}
+
+static const struct {
+ const char *fmt;
+ int (*decompress)(const char *input, int output);
+} compressions[] = {
+ { "gz", decompress_dummy },
+ { NULL, },
+};
+
+bool is_supported_compression(const char *ext)
+{
+ unsigned i;
+
+ for (i = 0; compressions[i].fmt; i++) {
+ if (!strcmp(ext, compressions[i].fmt))
+ return true;
+ }
+ return false;
+}
+
+bool is_kmodule_extension(const char *ext)
+{
+ if (strncmp(ext, "ko", 2))
+ return false;
+
+ if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3)))
+ return true;
+
+ return false;
+}
+
+bool is_kernel_module(const char *pathname, bool *compressed)
+{
+ const char *ext = strrchr(pathname, '.');
+
+ if (ext == NULL)
+ return false;
+
+ if (is_supported_compression(ext + 1)) {
+ if (compressed)
+ *compressed = true;
+ ext -= 3;
+ } else if (compressed)
+ *compressed = false;
+
+ return is_kmodule_extension(ext + 1);
+}
+
+bool decompress_to_file(const char *ext, const char *filename, int output_fd)
+{
+ unsigned i;
+
+ for (i = 0; compressions[i].fmt; i++) {
+ if (!strcmp(ext, compressions[i].fmt))
+ return !compressions[i].decompress(filename,
+ output_fd);
+ }
+ return false;
+}
+
+bool dso__needs_decompress(struct dso *dso)
+{
+ return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+ dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+}
+
/*
* Global list of open DSOs and the counter.
*/
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index a316e4af321f..3782c82c6e44 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -22,7 +22,9 @@ enum dso_binary_type {
DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
DSO_BINARY_TYPE__GUEST_KMODULE,
+ DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+ DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
DSO_BINARY_TYPE__KCORE,
DSO_BINARY_TYPE__GUEST_KCORE,
DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
@@ -185,6 +187,11 @@ int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
char dso__symtab_origin(const struct dso *dso);
int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
char *root_dir, char *filename, size_t size);
+bool is_supported_compression(const char *ext);
+bool is_kmodule_extension(const char *ext);
+bool is_kernel_module(const char *pathname, bool *compressed);
+bool decompress_to_file(const char *ext, const char *filename, int output_fd);
+bool dso__needs_decompress(struct dso *dso);
/*
* The dso__data_* external interface provides following functions:
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 51a630301afa..946c7d62cb6e 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -464,6 +464,7 @@ struct map *machine__new_module(struct machine *machine, u64 start,
{
struct map *map;
struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
+ bool compressed;
if (dso == NULL)
return NULL;
@@ -476,6 +477,11 @@ struct map *machine__new_module(struct machine *machine, u64 start,
dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
else
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+
+ /* _KMODULE_COMP should be next to _KMODULE */
+ if (is_kernel_module(filename, &compressed) && compressed)
+ dso->symtab_type++;
+
map_groups__insert(&machine->kmaps, map);
return map;
}
@@ -861,8 +867,14 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
struct map *map;
char *long_name;
- if (dot == NULL || strcmp(dot, ".ko"))
+ if (dot == NULL)
continue;
+
+ /* On some system, modules are compressed like .ko.gz */
+ if (is_supported_compression(dot + 1) &&
+ is_kmodule_extension(dot - 2))
+ dot -= 3;
+
snprintf(dso_name, sizeof(dso_name), "[%.*s]",
(int)(dot - dent->d_name), dent->d_name);
@@ -1044,6 +1056,11 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
dot = strrchr(name, '.');
if (dot == NULL)
goto out_problem;
+ /* On some system, modules are compressed like .ko.gz */
+ if (is_supported_compression(dot + 1))
+ dot -= 3;
+ if (!is_kmodule_extension(dot + 1))
+ goto out_problem;
snprintf(short_module_name, sizeof(short_module_name),
"[%.*s]", (int)(dot - name), name);
strxfrchar(short_module_name, '-', '_');
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 1e23a5bfb044..efc7eb6b8f0f 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -546,6 +546,35 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
return 0;
}
+static int decompress_kmodule(struct dso *dso, const char *name,
+ enum dso_binary_type type)
+{
+ int fd;
+ const char *ext = strrchr(name, '.');
+ char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
+
+ if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
+ type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) ||
+ type != dso->symtab_type)
+ return -1;
+
+ if (!ext || !is_supported_compression(ext + 1))
+ return -1;
+
+ fd = mkstemp(tmpbuf);
+ if (fd < 0)
+ return -1;
+
+ if (!decompress_to_file(ext + 1, name, fd)) {
+ close(fd);
+ fd = -1;
+ }
+
+ unlink(tmpbuf);
+
+ return fd;
+}
+
bool symsrc__possibly_runtime(struct symsrc *ss)
{
return ss->dynsym || ss->opdsec;
@@ -571,7 +600,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
Elf *elf;
int fd;
- fd = open(name, O_RDONLY);
+ if (dso__needs_decompress(dso))
+ fd = decompress_kmodule(dso, name, type);
+ else
+ fd = open(name, O_RDONLY);
+
if (fd < 0)
return -1;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 078331140d8c..c69915c9d5bc 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -51,7 +51,9 @@ static enum dso_binary_type binary_type_symtab[] = {
DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
DSO_BINARY_TYPE__GUEST_KMODULE,
+ DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+ DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
DSO_BINARY_TYPE__NOT_FOUND,
};
@@ -1300,7 +1302,9 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
return dso->kernel == DSO_TYPE_GUEST_KERNEL;
case DSO_BINARY_TYPE__GUEST_KMODULE:
+ case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+ case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
/*
* kernel modules know their symtab type - it's set when
* creating a module dso in machine__new_module().
@@ -1368,7 +1372,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
return -1;
kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
- dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+ dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+ dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+ dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
/*
* Iterate over candidate debug images.
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 09/18] perf tools: Add gzip decompression support for kernel module
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (7 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 08/18] perf symbols: Preparation for compressed kernel module support Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 10/18] perf build-id: Rename dsos__write_buildid_table() Arnaldo Carvalho de Melo
` (9 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Namhyung Kim, Jiri Olsa, Peter Zijlstra,
Paul Mackerras, Namhyung Kim, Adrian Hunter, David Ahern,
Stephane Eranian, Arnaldo Carvalho de Melo
From: Namhyung Kim <namhyung@kernel.org>
Now my Archlinux box shows module symbols correctly.
Before:
$ perf report --stdio
Failed to open /tmp/perf-3477.map, continuing without symbols
no symbols found in /usr/bin/date, maybe install a debug package?
No kallsyms or vmlinux with build-id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 was found
[drm] with build id 7b4ea0a49ae2111925857099aaf05c3246ff33e0 not found, continuing without symbols
No kallsyms or vmlinux with build-id edd931629094b660ca9dec09a1b635c8d87aa2ee was found
[jbd2] with build id edd931629094b660ca9dec09a1b635c8d87aa2ee not found, continuing without symbols
No kallsyms or vmlinux with build-id a7b1eada671c34933e5610bb920b2ca4945a82c3 was found
[ext4] with build id a7b1eada671c34933e5610bb920b2ca4945a82c3 not found, continuing without symbols
No kallsyms or vmlinux with build-id d69511fa3e5840e770336ef45b06c83fef8d74e3 was found
[scsi_mod] with build id d69511fa3e5840e770336ef45b06c83fef8d74e3 not found, continuing without symbols
No kallsyms or vmlinux with build-id af0430af13461af058770ee9b87afc07922c2e77 was found
[libata] with build id af0430af13461af058770ee9b87afc07922c2e77 not found, continuing without symbols
No kallsyms or vmlinux with build-id aaeedff8160ce631a5f0333591c6ff291201d29f was found
[libahci] with build id aaeedff8160ce631a5f0333591c6ff291201d29f not found, continuing without symbols
No kallsyms or vmlinux with build-id c57907712becaf662dc4981824bb372c0441d605 was found
[mac80211] with build id c57907712becaf662dc4981824bb372c0441d605 not found, continuing without symbols
No kallsyms or vmlinux with build-id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f was found
[iwldvm] with build id e0589077cc0ec8c3e4c40eb9f2d9e69d236bee8f not found, continuing without symbols
No kallsyms or vmlinux with build-id 2d86086bf136bf374a2f029cf85a48194f9b950b was found
[cfg80211] with build id 2d86086bf136bf374a2f029cf85a48194f9b950b not found, continuing without symbols
No kallsyms or vmlinux with build-id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 was found
[iwlwifi] with build id 4493c48599bdb3d91d0f8db5150e0be33fdd9221 not found, continuing without symbols
...
#
# Overhead Command Shared Object Symbol
# ........ ............... ....................... ........................................................
#
0.03% swapper [ext4] [k] 0x000000000000fe2e
0.03% swapper [kernel.kallsyms] [k] account_entity_enqueue
0.03% swapper [ext4] [k] 0x000000000000fc2b
0.03% irq/50-iwlwifi [iwlwifi] [k] 0x000000000000200b
0.03% swapper [kernel.kallsyms] [k] ktime_add_safe
0.03% swapper [kernel.kallsyms] [k] elv_completed_request
0.03% swapper [libata] [k] 0x0000000000003997
0.03% swapper [libahci] [k] 0x0000000000001f25
0.03% swapper [kernel.kallsyms] [k] rb_next
0.03% swapper [kernel.kallsyms] [k] blk_finish_request
0.03% swapper [ext4] [k] 0x0000000000010248
0.00% perf [kernel.kallsyms] [k] native_write_msr_safe
After:
$ perf report --stdio
Failed to open /tmp/perf-3477.map, continuing without symbols
no symbols found in /usr/bin/tr, maybe install a debug package?
...
#
# Overhead Command Shared Object Symbol
# ........ ............... ........................... ......................................................
#
0.04% kworker/u16:3 [ext4] [k] ext4_read_block_bitmap
0.03% kworker/u16:0 [mac80211] [k] ieee80211_sta_reset_beacon_monitor
0.02% irq/50-iwlwifi [mac80211] [k] ieee80211_get_bssid
0.02% firefox [e1000e] [k] __ew32_prepare
0.02% swapper [libahci] [k] ahci_handle_port_interrupt
0.02% emacs libglib-2.0.so.0.4000.0 [.] g_mutex_unlock
0.02% swapper [e1000e] [k] e1000_clean_tx_irq
0.02% dwm [kernel.kallsyms] [k] __schedule
0.02% gnome-terminal- [vdso] [.] __vdso_clock_gettime
0.02% swapper [e1000e] [k] e1000_alloc_rx_buffers
0.02% irq/50-iwlwifi [mac80211] [k] ieee80211_rx
0.01% firefox [vdso] [.] __vdso_gettimeofday
0.01% irq/50-iwlwifi [iwlwifi] [k] iwl_pcie_rxq_restock.part.13
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/87h9yexshi.fsf@sejong.aot.lge.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/Makefile.perf | 7 +++
tools/perf/config/Makefile | 15 +++++-
tools/perf/config/feature-checks/Makefile | 8 ++-
tools/perf/config/feature-checks/test-all.c | 5 ++
tools/perf/config/feature-checks/test-zlib.c | 9 ++++
tools/perf/util/dso.c | 12 ++---
tools/perf/util/util.h | 5 ++
tools/perf/util/zlib.c | 78 ++++++++++++++++++++++++++++
8 files changed, 127 insertions(+), 12 deletions(-)
create mode 100644 tools/perf/config/feature-checks/test-zlib.c
create mode 100644 tools/perf/util/zlib.c
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 0ebcc4ad0244..aecf61dcd754 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -66,6 +66,9 @@ include config/utilities.mak
#
# Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
# for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_ZLIB if you do not want to support compressed kernel modules
+
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -584,6 +587,10 @@ ifndef NO_LIBNUMA
BUILTIN_OBJS += $(OUTPUT)bench/numa.o
endif
+ifndef NO_ZLIB
+ LIB_OBJS += $(OUTPUT)util/zlib.o
+endif
+
ifdef ASCIIDOC8
export ASCIIDOC8
endif
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 71264e41fa85..79f906c7124e 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -200,7 +200,8 @@ CORE_FEATURE_TESTS = \
libunwind \
stackprotector-all \
timerfd \
- libdw-dwarf-unwind
+ libdw-dwarf-unwind \
+ zlib
LIB_FEATURE_TESTS = \
dwarf \
@@ -214,7 +215,8 @@ LIB_FEATURE_TESTS = \
libpython \
libslang \
libunwind \
- libdw-dwarf-unwind
+ libdw-dwarf-unwind \
+ zlib
VF_FEATURE_TESTS = \
backtrace \
@@ -604,6 +606,15 @@ ifneq ($(filter -lbfd,$(EXTLIBS)),)
CFLAGS += -DHAVE_LIBBFD_SUPPORT
endif
+ifndef NO_ZLIB
+ ifeq ($(feature-zlib), 1)
+ CFLAGS += -DHAVE_ZLIB_SUPPORT
+ EXTLIBS += -lz
+ else
+ NO_ZLIB := 1
+ endif
+endif
+
ifndef NO_BACKTRACE
ifeq ($(feature-backtrace), 1)
CFLAGS += -DHAVE_BACKTRACE_SUPPORT
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 7c68ec74a808..53f19b5dbc37 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -29,7 +29,8 @@ FILES= \
test-timerfd.bin \
test-libdw-dwarf-unwind.bin \
test-compile-32.bin \
- test-compile-x32.bin
+ test-compile-x32.bin \
+ test-zlib.bin
CC := $(CROSS_COMPILE)gcc -MD
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -41,7 +42,7 @@ BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
###############################
test-all.bin:
- $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
+ $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz
test-hello.bin:
$(BUILD)
@@ -139,6 +140,9 @@ test-compile-32.bin:
test-compile-x32.bin:
$(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
+test-zlib.bin:
+ $(BUILD) -lz
+
-include *.d
###############################
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index a7d022e161c0..652e0098eba6 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -93,6 +93,10 @@
# include "test-sync-compare-and-swap.c"
#undef main
+#define main main_test_zlib
+# include "test-zlib.c"
+#undef main
+
int main(int argc, char *argv[])
{
main_test_libpython();
@@ -116,6 +120,7 @@ int main(int argc, char *argv[])
main_test_stackprotector_all();
main_test_libdw_dwarf_unwind();
main_test_sync_compare_and_swap(argc, argv);
+ main_test_zlib();
return 0;
}
diff --git a/tools/perf/config/feature-checks/test-zlib.c b/tools/perf/config/feature-checks/test-zlib.c
new file mode 100644
index 000000000000..e111fff6240e
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-zlib.c
@@ -0,0 +1,9 @@
+#include <zlib.h>
+
+int main(void)
+{
+ z_stream zs;
+
+ inflateInit(&zs);
+ return 0;
+}
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 36a607cf8f50..45be944d450a 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -141,18 +141,14 @@ int dso__read_binary_type_filename(const struct dso *dso,
return ret;
}
-static int decompress_dummy(const char *input __maybe_unused,
- int output __maybe_unused)
-{
- return -1;
-}
-
static const struct {
const char *fmt;
int (*decompress)(const char *input, int output);
} compressions[] = {
- { "gz", decompress_dummy },
- { NULL, },
+#ifdef HAVE_ZLIB_SUPPORT
+ { "gz", gzip_decompress_to_file },
+#endif
+ { NULL, NULL },
};
bool is_supported_compression(const char *ext)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 80bfdaa0e2a4..7dc44cfe25b3 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -351,4 +351,9 @@ void mem_bswap_32(void *src, int byte_size);
const char *get_filename_for_perf_kvm(void);
bool find_process(const char *name);
+
+#ifdef HAVE_ZLIB_SUPPORT
+int gzip_decompress_to_file(const char *input, int output_fd);
+#endif
+
#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c
new file mode 100644
index 000000000000..495a449fc25c
--- /dev/null
+++ b/tools/perf/util/zlib.c
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <zlib.h>
+
+#include "util/util.h"
+#include "util/debug.h"
+
+
+#define CHUNK_SIZE 16384
+
+int gzip_decompress_to_file(const char *input, int output_fd)
+{
+ int ret = Z_STREAM_ERROR;
+ int input_fd;
+ void *ptr;
+ int len;
+ struct stat stbuf;
+ unsigned char buf[CHUNK_SIZE];
+ z_stream zs = {
+ .zalloc = Z_NULL,
+ .zfree = Z_NULL,
+ .opaque = Z_NULL,
+ .avail_in = 0,
+ .next_in = Z_NULL,
+ };
+
+ input_fd = open(input, O_RDONLY);
+ if (input_fd < 0)
+ return -1;
+
+ if (fstat(input_fd, &stbuf) < 0)
+ goto out_close;
+
+ ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
+ if (ptr == MAP_FAILED)
+ goto out_close;
+
+ if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK)
+ goto out_unmap;
+
+ zs.next_in = ptr;
+ zs.avail_in = stbuf.st_size;
+
+ do {
+ zs.next_out = buf;
+ zs.avail_out = CHUNK_SIZE;
+
+ ret = inflate(&zs, Z_NO_FLUSH);
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ /* fall through */
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ goto out;
+ default:
+ break;
+ }
+
+ len = CHUNK_SIZE - zs.avail_out;
+ if (writen(output_fd, buf, len) != len) {
+ ret = Z_DATA_ERROR;
+ goto out;
+ }
+
+ } while (ret != Z_STREAM_END);
+
+out:
+ inflateEnd(&zs);
+out_unmap:
+ munmap(ptr, stbuf.st_size);
+out_close:
+ close(input_fd);
+
+ return ret == Z_STREAM_END ? 0 : -1;
+}
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 10/18] perf build-id: Rename dsos__write_buildid_table()
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (8 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 09/18] perf tools: Add gzip decompression support for kernel module Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 11/18] perf build-id: Move build-id related functions to util/build-id.c Arnaldo Carvalho de Melo
` (8 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Namhyung Kim, Adrian Hunter, David Ahern, Jiri Olsa,
Namhyung Kim, Paul Mackerras, Peter Zijlstra, Stephane Eranian,
Arnaldo Carvalho de Melo
From: Namhyung Kim <namhyung@kernel.org>
The dsos__write_buildid_table() is not use struct dso and it mostly
uses perf_session struct.
So rename it to perf_session__write_buildid_ table() so that it
corresponds to other related functions such as
perf_session__read_build_ids() and perf_session__cache_build_ids().
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-4-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
| 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 0ecf4a304cbc..be8d02eb97e9 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -297,10 +297,8 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
return err;
}
-static int dsos__write_buildid_table(struct perf_header *header, int fd)
+static int perf_session__write_buildid_table(struct perf_session *session, int fd)
{
- struct perf_session *session = container_of(header,
- struct perf_session, header);
struct rb_node *nd;
int err = machine__write_buildid_table(&session->machines.host, fd);
@@ -523,7 +521,7 @@ static int write_build_id(int fd, struct perf_header *h,
if (!perf_session__read_build_ids(session, true))
return -1;
- err = dsos__write_buildid_table(h, fd);
+ err = perf_session__write_buildid_table(session, fd);
if (err < 0) {
pr_debug("failed to write buildid table\n");
return err;
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 11/18] perf build-id: Move build-id related functions to util/build-id.c
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (9 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 10/18] perf build-id: Rename dsos__write_buildid_table() Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 12/18] perf record: Do not save pathname in ./debug/.build-id directory for vmlinux Arnaldo Carvalho de Melo
` (7 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Namhyung Kim, Adrian Hunter, David Ahern, Jiri Olsa,
Namhyung Kim, Paul Mackerras, Peter Zijlstra, Stephane Eranian,
Arnaldo Carvalho de Melo
From: Namhyung Kim <namhyung@kernel.org>
It'd be better managing those functions in a separate place as
util/header.c file is already big.
It now exports following 3 functions to others:
bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
int perf_session__write_buildid_table(struct perf_session *session, int fd);
int perf_session__cache_build_ids(struct perf_session *session);
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Link: http://lkml.kernel.org/r/545733E7.6010105@intel.com
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-5-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/build-id.c | 334 ++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/build-id.h | 11 ++
| 337 +--------------------------------------------
| 8 +-
4 files changed, 349 insertions(+), 341 deletions(-)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 2e7c68e39330..dd2a3e52ada1 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -15,6 +15,8 @@
#include "debug.h"
#include "session.h"
#include "tool.h"
+#include "header.h"
+#include "vdso.h"
int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
union perf_event *event,
@@ -105,3 +107,335 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
build_id_hex, build_id_hex + 2);
return bf;
}
+
+#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 write_buildid(const char *name, size_t name_len, u8 *build_id,
+ pid_t pid, u16 misc, int fd)
+{
+ int err;
+ struct build_id_event b;
+ size_t len;
+
+ len = name_len + 1;
+ len = PERF_ALIGN(len, NAME_ALIGN);
+
+ memset(&b, 0, sizeof(b));
+ memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
+ b.pid = pid;
+ b.header.misc = misc;
+ b.header.size = sizeof(b) + len;
+
+ err = writen(fd, &b, sizeof(b));
+ if (err < 0)
+ return err;
+
+ return write_padded(fd, name, name_len + 1, len);
+}
+
+static int __dsos__write_buildid_table(struct list_head *head,
+ struct machine *machine,
+ pid_t pid, u16 misc, int fd)
+{
+ char nm[PATH_MAX];
+ struct dso *pos;
+
+ dsos__for_each_with_build_id(pos, head) {
+ int err;
+ const char *name;
+ size_t name_len;
+
+ if (!pos->hit)
+ continue;
+
+ if (dso__is_vdso(pos)) {
+ name = pos->short_name;
+ name_len = pos->short_name_len + 1;
+ } else if (dso__is_kcore(pos)) {
+ machine__mmap_name(machine, nm, sizeof(nm));
+ name = nm;
+ name_len = strlen(nm) + 1;
+ } else {
+ name = pos->long_name;
+ name_len = pos->long_name_len + 1;
+ }
+
+ err = write_buildid(name, name_len, pos->build_id,
+ pid, misc, fd);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int machine__write_buildid_table(struct machine *machine, int fd)
+{
+ int err;
+ u16 kmisc = PERF_RECORD_MISC_KERNEL,
+ umisc = PERF_RECORD_MISC_USER;
+
+ if (!machine__is_host(machine)) {
+ kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
+ umisc = PERF_RECORD_MISC_GUEST_USER;
+ }
+
+ err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
+ machine->pid, kmisc, fd);
+ if (err == 0)
+ err = __dsos__write_buildid_table(&machine->user_dsos.head,
+ machine, machine->pid, umisc,
+ fd);
+ return err;
+}
+
+int perf_session__write_buildid_table(struct perf_session *session, int fd)
+{
+ struct rb_node *nd;
+ int err = machine__write_buildid_table(&session->machines.host, fd);
+
+ if (err)
+ return err;
+
+ for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
+ err = machine__write_buildid_table(pos, fd);
+ if (err)
+ break;
+ }
+ return err;
+}
+
+static int __dsos__hit_all(struct list_head *head)
+{
+ struct dso *pos;
+
+ list_for_each_entry(pos, head, node)
+ pos->hit = true;
+
+ return 0;
+}
+
+static int machine__hit_all_dsos(struct machine *machine)
+{
+ int err;
+
+ err = __dsos__hit_all(&machine->kernel_dsos.head);
+ if (err)
+ return err;
+
+ return __dsos__hit_all(&machine->user_dsos.head);
+}
+
+int dsos__hit_all(struct perf_session *session)
+{
+ struct rb_node *nd;
+ int err;
+
+ err = machine__hit_all_dsos(&session->machines.host);
+ if (err)
+ return err;
+
+ for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
+
+ err = machine__hit_all_dsos(pos);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+ const char *name, bool is_kallsyms, bool is_vdso)
+{
+ const size_t size = PATH_MAX;
+ char *realname, *filename = zalloc(size),
+ *linkname = zalloc(size), *targetname;
+ int len, err = -1;
+ bool slash = is_kallsyms || is_vdso;
+
+ if (is_kallsyms) {
+ if (symbol_conf.kptr_restrict) {
+ pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
+ err = 0;
+ goto out_free;
+ }
+ realname = (char *) name;
+ } else
+ realname = realpath(name, NULL);
+
+ if (realname == NULL || filename == NULL || linkname == NULL)
+ goto out_free;
+
+ len = scnprintf(filename, size, "%s%s%s",
+ debugdir, slash ? "/" : "",
+ is_vdso ? DSO__NAME_VDSO : realname);
+ if (mkdir_p(filename, 0755))
+ goto out_free;
+
+ snprintf(filename + len, size - len, "/%s", sbuild_id);
+
+ if (access(filename, F_OK)) {
+ if (is_kallsyms) {
+ if (copyfile("/proc/kallsyms", filename))
+ goto out_free;
+ } else if (link(realname, filename) && copyfile(name, filename))
+ goto out_free;
+ }
+
+ len = scnprintf(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:
+ if (!is_kallsyms)
+ free(realname);
+ free(filename);
+ free(linkname);
+ return err;
+}
+
+static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
+ const char *name, const char *debugdir,
+ bool is_kallsyms, bool is_vdso)
+{
+ char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+ build_id__sprintf(build_id, build_id_size, sbuild_id);
+
+ return build_id_cache__add_s(sbuild_id, debugdir, name,
+ is_kallsyms, is_vdso);
+}
+
+int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
+{
+ const size_t size = PATH_MAX;
+ char *filename = zalloc(size),
+ *linkname = zalloc(size);
+ int err = -1;
+
+ if (filename == NULL || linkname == NULL)
+ goto out_free;
+
+ snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+ debugdir, sbuild_id, sbuild_id + 2);
+
+ if (access(linkname, F_OK))
+ goto out_free;
+
+ if (readlink(linkname, filename, size - 1) < 0)
+ goto out_free;
+
+ if (unlink(linkname))
+ goto out_free;
+
+ /*
+ * Since the link is relative, we must make it absolute:
+ */
+ snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+ debugdir, sbuild_id, filename);
+
+ if (unlink(linkname))
+ goto out_free;
+
+ err = 0;
+out_free:
+ free(filename);
+ free(linkname);
+ return err;
+}
+
+static int dso__cache_build_id(struct dso *dso, struct machine *machine,
+ const char *debugdir)
+{
+ bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
+ bool is_vdso = dso__is_vdso(dso);
+ const char *name = dso->long_name;
+ char nm[PATH_MAX];
+
+ if (dso__is_kcore(dso)) {
+ is_kallsyms = true;
+ machine__mmap_name(machine, nm, sizeof(nm));
+ name = nm;
+ }
+ return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
+ debugdir, is_kallsyms, is_vdso);
+}
+
+static int __dsos__cache_build_ids(struct list_head *head,
+ struct machine *machine, const char *debugdir)
+{
+ struct dso *pos;
+ int err = 0;
+
+ dsos__for_each_with_build_id(pos, head)
+ if (dso__cache_build_id(pos, machine, debugdir))
+ err = -1;
+
+ return err;
+}
+
+static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
+{
+ int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
+ debugdir);
+ ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
+ debugdir);
+ return ret;
+}
+
+int perf_session__cache_build_ids(struct perf_session *session)
+{
+ struct rb_node *nd;
+ int ret;
+ char debugdir[PATH_MAX];
+
+ snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
+
+ if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
+ return -1;
+
+ ret = machine__cache_build_ids(&session->machines.host, debugdir);
+
+ for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
+ ret |= machine__cache_build_ids(pos, debugdir);
+ }
+ return ret ? -1 : 0;
+}
+
+static bool machine__read_build_ids(struct machine *machine, bool with_hits)
+{
+ bool ret;
+
+ ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
+ ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
+ return ret;
+}
+
+bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
+{
+ struct rb_node *nd;
+ bool ret = machine__read_build_ids(&session->machines.host, with_hits);
+
+ for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
+ ret |= machine__read_build_ids(pos, with_hits);
+ }
+
+ return ret;
+}
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index ae392561470b..666a3bd4f64e 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -15,4 +15,15 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
struct perf_sample *sample, struct perf_evsel *evsel,
struct machine *machine);
+
+int dsos__hit_all(struct perf_session *session);
+
+bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
+int perf_session__write_buildid_table(struct perf_session *session, int fd);
+int perf_session__cache_build_ids(struct perf_session *session);
+
+int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+ const char *name, bool is_kallsyms, bool is_vdso);
+int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
+
#endif
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index be8d02eb97e9..3e2c156d9c64 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -79,10 +79,7 @@ static int do_write(int fd, const void *buf, size_t size)
return 0;
}
-#define NAME_ALIGN 64
-
-static int write_padded(int fd, const void *bf, size_t count,
- size_t count_aligned)
+int write_padded(int fd, const void *bf, size_t count, size_t count_aligned)
{
static const char zero_buf[NAME_ALIGN];
int err = do_write(fd, bf, count);
@@ -171,338 +168,6 @@ perf_header__set_cmdline(int argc, const char **argv)
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 write_buildid(const char *name, size_t name_len, u8 *build_id,
- pid_t pid, u16 misc, int fd)
-{
- int err;
- struct build_id_event b;
- size_t len;
-
- len = name_len + 1;
- len = PERF_ALIGN(len, NAME_ALIGN);
-
- memset(&b, 0, sizeof(b));
- memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
- b.pid = pid;
- b.header.misc = misc;
- b.header.size = sizeof(b) + len;
-
- err = do_write(fd, &b, sizeof(b));
- if (err < 0)
- return err;
-
- return write_padded(fd, name, name_len + 1, len);
-}
-
-static int __dsos__hit_all(struct list_head *head)
-{
- struct dso *pos;
-
- list_for_each_entry(pos, head, node)
- pos->hit = true;
-
- return 0;
-}
-
-static int machine__hit_all_dsos(struct machine *machine)
-{
- int err;
-
- err = __dsos__hit_all(&machine->kernel_dsos.head);
- if (err)
- return err;
-
- return __dsos__hit_all(&machine->user_dsos.head);
-}
-
-int dsos__hit_all(struct perf_session *session)
-{
- struct rb_node *nd;
- int err;
-
- err = machine__hit_all_dsos(&session->machines.host);
- if (err)
- return err;
-
- for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
-
- err = machine__hit_all_dsos(pos);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int __dsos__write_buildid_table(struct list_head *head,
- struct machine *machine,
- pid_t pid, u16 misc, int fd)
-{
- char nm[PATH_MAX];
- struct dso *pos;
-
- dsos__for_each_with_build_id(pos, head) {
- int err;
- const char *name;
- size_t name_len;
-
- if (!pos->hit)
- continue;
-
- if (dso__is_vdso(pos)) {
- name = pos->short_name;
- name_len = pos->short_name_len + 1;
- } else if (dso__is_kcore(pos)) {
- machine__mmap_name(machine, nm, sizeof(nm));
- name = nm;
- name_len = strlen(nm) + 1;
- } else {
- name = pos->long_name;
- name_len = pos->long_name_len + 1;
- }
-
- err = write_buildid(name, name_len, pos->build_id,
- pid, misc, fd);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int machine__write_buildid_table(struct machine *machine, int fd)
-{
- int err;
- u16 kmisc = PERF_RECORD_MISC_KERNEL,
- umisc = PERF_RECORD_MISC_USER;
-
- if (!machine__is_host(machine)) {
- kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
- umisc = PERF_RECORD_MISC_GUEST_USER;
- }
-
- err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
- machine->pid, kmisc, fd);
- if (err == 0)
- err = __dsos__write_buildid_table(&machine->user_dsos.head,
- machine, machine->pid, umisc,
- fd);
- return err;
-}
-
-static int perf_session__write_buildid_table(struct perf_session *session, int fd)
-{
- struct rb_node *nd;
- int err = machine__write_buildid_table(&session->machines.host, fd);
-
- if (err)
- return err;
-
- for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
- err = machine__write_buildid_table(pos, fd);
- if (err)
- break;
- }
- return err;
-}
-
-int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
- const char *name, bool is_kallsyms, bool is_vdso)
-{
- const size_t size = PATH_MAX;
- char *realname, *filename = zalloc(size),
- *linkname = zalloc(size), *targetname;
- int len, err = -1;
- bool slash = is_kallsyms || is_vdso;
-
- if (is_kallsyms) {
- if (symbol_conf.kptr_restrict) {
- pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
- err = 0;
- goto out_free;
- }
- realname = (char *) name;
- } else
- realname = realpath(name, NULL);
-
- if (realname == NULL || filename == NULL || linkname == NULL)
- goto out_free;
-
- len = scnprintf(filename, size, "%s%s%s",
- debugdir, slash ? "/" : "",
- is_vdso ? DSO__NAME_VDSO : realname);
- if (mkdir_p(filename, 0755))
- goto out_free;
-
- snprintf(filename + len, size - len, "/%s", sbuild_id);
-
- if (access(filename, F_OK)) {
- if (is_kallsyms) {
- if (copyfile("/proc/kallsyms", filename))
- goto out_free;
- } else if (link(realname, filename) && copyfile(name, filename))
- goto out_free;
- }
-
- len = scnprintf(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:
- if (!is_kallsyms)
- free(realname);
- free(filename);
- free(linkname);
- return err;
-}
-
-static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
- const char *name, const char *debugdir,
- bool is_kallsyms, bool is_vdso)
-{
- char sbuild_id[BUILD_ID_SIZE * 2 + 1];
-
- build_id__sprintf(build_id, build_id_size, sbuild_id);
-
- return build_id_cache__add_s(sbuild_id, debugdir, name,
- is_kallsyms, is_vdso);
-}
-
-int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
-{
- const size_t size = PATH_MAX;
- char *filename = zalloc(size),
- *linkname = zalloc(size);
- int err = -1;
-
- if (filename == NULL || linkname == NULL)
- goto out_free;
-
- snprintf(linkname, size, "%s/.build-id/%.2s/%s",
- debugdir, sbuild_id, sbuild_id + 2);
-
- if (access(linkname, F_OK))
- goto out_free;
-
- if (readlink(linkname, filename, size - 1) < 0)
- goto out_free;
-
- if (unlink(linkname))
- goto out_free;
-
- /*
- * Since the link is relative, we must make it absolute:
- */
- snprintf(linkname, size, "%s/.build-id/%.2s/%s",
- debugdir, sbuild_id, filename);
-
- if (unlink(linkname))
- goto out_free;
-
- err = 0;
-out_free:
- free(filename);
- free(linkname);
- return err;
-}
-
-static int dso__cache_build_id(struct dso *dso, struct machine *machine,
- const char *debugdir)
-{
- bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
- bool is_vdso = dso__is_vdso(dso);
- const char *name = dso->long_name;
- char nm[PATH_MAX];
-
- if (dso__is_kcore(dso)) {
- is_kallsyms = true;
- machine__mmap_name(machine, nm, sizeof(nm));
- name = nm;
- }
- return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
- debugdir, is_kallsyms, is_vdso);
-}
-
-static int __dsos__cache_build_ids(struct list_head *head,
- struct machine *machine, const char *debugdir)
-{
- struct dso *pos;
- int err = 0;
-
- dsos__for_each_with_build_id(pos, head)
- if (dso__cache_build_id(pos, machine, debugdir))
- err = -1;
-
- return err;
-}
-
-static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
-{
- int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
- debugdir);
- ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
- debugdir);
- return ret;
-}
-
-static int perf_session__cache_build_ids(struct perf_session *session)
-{
- struct rb_node *nd;
- int ret;
- char debugdir[PATH_MAX];
-
- snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
-
- if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
- return -1;
-
- ret = machine__cache_build_ids(&session->machines.host, debugdir);
-
- for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
- ret |= machine__cache_build_ids(pos, debugdir);
- }
- return ret ? -1 : 0;
-}
-
-static bool machine__read_build_ids(struct machine *machine, bool with_hits)
-{
- bool ret;
-
- ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
- ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
- return ret;
-}
-
-static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
-{
- struct rb_node *nd;
- bool ret = machine__read_build_ids(&session->machines.host, with_hits);
-
- for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
- ret |= machine__read_build_ids(pos, with_hits);
- }
-
- return ret;
-}
-
static int write_tracing_data(int fd, struct perf_header *h __maybe_unused,
struct perf_evlist *evlist)
{
--git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 8f5cbaea64a5..3bb90ac172a1 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -122,10 +122,6 @@ int perf_header__process_sections(struct perf_header *header, int fd,
int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
-int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
- const char *name, bool is_kallsyms, bool is_vdso);
-int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
-
int perf_event__synthesize_attr(struct perf_tool *tool,
struct perf_event_attr *attr, u32 ids, u64 *id,
perf_event__handler_t process);
@@ -151,7 +147,9 @@ int perf_event__process_build_id(struct perf_tool *tool,
struct perf_session *session);
bool is_perf_magic(u64 magic);
-int dsos__hit_all(struct perf_session *session);
+#define NAME_ALIGN 64
+
+int write_padded(int fd, const void *bf, size_t count, size_t count_aligned);
/*
* arch specific callback
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 12/18] perf record: Do not save pathname in ./debug/.build-id directory for vmlinux
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (10 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 11/18] perf build-id: Move build-id related functions to util/build-id.c Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 13/18] perf tools: Fix build-id matching on vmlinux Arnaldo Carvalho de Melo
` (6 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Namhyung Kim, Adrian Hunter, David Ahern, Jiri Olsa,
Namhyung Kim, Paul Mackerras, Peter Zijlstra, Stephane Eranian,
Arnaldo Carvalho de Melo
From: Namhyung Kim <namhyung@kernel.org>
When perf record finishes a session, it pre-processes samples in order
to write build-id info from DSOs that had samples.
During this process it'll call map__load() for the kernel map, and it
ends up calling dso__load_vmlinux_path() which replaces dso->long_name.
But this function checks kernel's build-id before searching vmlinux path
so it'll end up with a cryptic name, the pathname for the entry in the
~/.debug cache, which can be confusing to users.
This patch adds a flag to skip the build-id check during record, so
that it'll have the original vmlinux path for the kernel dso->long_name,
not the entry in the ~/.debug cache.
Before:
# perf record -va sleep 3
mmap size 528384B
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.196 MB perf.data (~8545 samples) ]
Looking at the vmlinux_path (7 entries long)
Using /home/namhyung/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551 for symbols
After:
# perf record -va sleep 3
mmap size 528384B
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.193 MB perf.data (~8432 samples) ]
Looking at the vmlinux_path (7 entries long)
Using /lib/modules/3.16.4-1-ARCH/build/vmlinux for symbols
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-7-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/builtin-record.c | 11 +++++++++++
tools/perf/util/symbol.c | 11 ++++++-----
tools/perf/util/symbol.h | 1 +
3 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 5091a27e6d28..582c4da155ea 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -200,6 +200,17 @@ static int process_buildids(struct record *rec)
if (size == 0)
return 0;
+ /*
+ * During this process, it'll load kernel map and replace the
+ * dso->long_name to a real pathname it found. In this case
+ * we prefer the vmlinux path like
+ * /lib/modules/3.16.4/build/vmlinux
+ *
+ * rather than build-id path (in debug directory).
+ * $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
+ */
+ symbol_conf.ignore_vmlinux_buildid = true;
+
return __perf_session__process_events(session, start,
size - start,
size, &build_id__mark_dso_hit_ops);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c69915c9d5bc..c24c5b83156c 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1511,12 +1511,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
symbol_filter_t filter)
{
int i, err = 0;
- char *filename;
+ char *filename = NULL;
- pr_debug("Looking at the vmlinux_path (%d entries long)\n",
- vmlinux_path__nr_entries + 1);
-
- filename = dso__build_id_filename(dso, NULL, 0);
+ if (!symbol_conf.ignore_vmlinux_buildid)
+ filename = dso__build_id_filename(dso, NULL, 0);
if (filename != NULL) {
err = dso__load_vmlinux(dso, map, filename, true, filter);
if (err > 0)
@@ -1524,6 +1522,9 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
free(filename);
}
+ pr_debug("Looking at the vmlinux_path (%d entries long)\n",
+ vmlinux_path__nr_entries + 1);
+
for (i = 0; i < vmlinux_path__nr_entries; ++i) {
err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
if (err > 0)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index eb2c19bf8d90..ded3ca7266de 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -105,6 +105,7 @@ struct symbol_conf {
unsigned short nr_events;
bool try_vmlinux_path,
ignore_vmlinux,
+ ignore_vmlinux_buildid,
show_kernel_path,
use_modules,
sort_by_name,
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 13/18] perf tools: Fix build-id matching on vmlinux
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (11 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 12/18] perf record: Do not save pathname in ./debug/.build-id directory for vmlinux Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 14/18] perf tools: Make vmlinux short name more like kallsyms short name Arnaldo Carvalho de Melo
` (5 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Namhyung Kim, Adrian Hunter, David Ahern, Jiri Olsa,
Namhyung Kim, Paul Mackerras, Peter Zijlstra, Stephane Eranian,
Arnaldo Carvalho de Melo
From: Namhyung Kim <namhyung@kernel.org>
There's a problem on finding correct kernel symbols when perf report
runs on a different kernel. Although a part of the problem was solved
by the prior commit 0a7e6d1b6844 ("perf tools: Check recorded kernel
version when finding vmlinux"), there's a remaining problem still.
When perf records samples, it synthesizes the kernel map using
machine__mmap_name() and ref_reloc_sym like "[kernel.kallsyms]_text".
You can easily see it using 'perf report -D' command.
After finishing record, it goes through the recorded events to find
maps/dsos actually used. And then record build-id info of them.
During this process, it needs to load symbols in a dso and it'd call
dso__load_vmlinux_path() since the default value of the symbol_conf.
try_vmlinux_path is true. However it changes dso->long_name to a real
path of the vmlinux file (e.g. /lib/modules/3.16.4/build/vmlinux) if one
is running on a custom kernel.
It resulted in that perf report reads the build-id of the vmlinux, but
cannot use it since it only knows about the [kernel.kallsyms] map. It
then falls back to possible vmlinux paths by using the recorded kernel
version (in case of a recent version) or a running kernel silently.
Even with the recent tools, this still has a possibility of breaking
the result. As the build directory is a symbolic link, if one built a
new kernel in the same directory with different source/config, the old
link to vmlinux will point the new file. So it's absolutely needed to
use build-id when finding a kernel image.
In this patch, it's now changed to try to search a kernel dso in the
existing dso list which was constructed during build-id table parsing
so it'll always have a build-id. If not found, search "[kernel.kallsyms]".
Before:
$ perf report
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ...............................
#
72.15% 0.00% swapper [kernel.kallsyms] [k] set_curr_task_rt
72.15% 0.00% swapper [kernel.kallsyms] [k] native_calibrate_tsc
72.15% 0.00% swapper [kernel.kallsyms] [k] tsc_refine_calibration_work
71.87% 71.87% swapper [kernel.kallsyms] [k] module_finalize
...
After (for the same perf.data):
72.15% 0.00% swapper vmlinux [k] cpu_startup_entry
72.15% 0.00% swapper vmlinux [k] arch_cpu_idle
72.15% 0.00% swapper vmlinux [k] default_idle
71.87% 71.87% swapper vmlinux [k] native_safe_halt
...
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
Link: http://lkml.kernel.org/r/20140924073356.GB1962@gmail.com
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-8-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
| 2 +-
tools/perf/util/machine.c | 16 ++++++++++++++--
2 files changed, 15 insertions(+), 3 deletions(-)
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 3e2c156d9c64..76442caca37e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1269,7 +1269,7 @@ static int __event_process_build_id(struct build_id_event *bev,
dso__set_build_id(dso, &bev->build_id);
- if (filename[0] == '[')
+ if (!is_kernel_module(filename, NULL))
dso->kernel = dso_type;
build_id__sprintf(dso->build_id, sizeof(dso->build_id),
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 946c7d62cb6e..53f90e9c65fe 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1085,8 +1085,20 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
* Should be there already, from the build-id table in
* the header.
*/
- struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
- kmmap_prefix);
+ struct dso *kernel = NULL;
+ struct dso *dso;
+
+ list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
+ if (is_kernel_module(dso->long_name, NULL))
+ continue;
+
+ kernel = dso;
+ break;
+ }
+
+ if (kernel == NULL)
+ kernel = __dsos__findnew(&machine->kernel_dsos,
+ kmmap_prefix);
if (kernel == NULL)
goto out_problem;
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 14/18] perf tools: Make vmlinux short name more like kallsyms short name
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (12 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 13/18] perf tools: Fix build-id matching on vmlinux Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-09 7:51 ` Jiri Olsa
2014-11-06 21:04 ` [PATCH 15/18] perf tools: Add test_and_set_bit function Arnaldo Carvalho de Melo
` (4 subsequent siblings)
18 siblings, 1 reply; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Namhyung Kim, Adrian Hunter, David Ahern, Jiri Olsa,
Namhyung Kim, Paul Mackerras, Peter Zijlstra, Stephane Eranian,
Arnaldo Carvalho de Melo
From: Namhyung Kim <namhyung@kernel.org>
The previous patch changed kernel dso name from '[kernel.kallsyms]' to
vmlinux. However it might add confusion to old users accustomed to the
old name. So change the short name to '[kernel.vmlinux]' to reduce such
confusion.
Before:
# Overhead Command Shared Object Symbol
# ........ .............. ....................... ...............................
#
9.83% swapper vmlinux [k] intel_idle
4.10% awk libc-2.20.so [.] __strcmp_sse2
1.86% sed libc-2.20.so [.] __strcmp_sse2
1.78% netctl-auto libc-2.20.so [.] __strcmp_sse2
1.23% netctl-auto libc-2.20.so [.] __mbrtowc
1.21% firefox libxul.so [.] 0x00000000024b62bd
1.20% swapper vmlinux [k] cpuidle_enter_state
1.03% sleep vmlinux [k] copy_user_generic_unrolled
After:
# Overhead Command Shared Object Symbol
# ........ .............. ....................... ...............................
#
9.83% swapper [kernel.vmlinux] [k] intel_idle
4.10% awk libc-2.20.so [.] __strcmp_sse2
1.86% sed libc-2.20.so [.] __strcmp_sse2
1.78% netctl-auto libc-2.20.so [.] __strcmp_sse2
1.23% netctl-auto libc-2.20.so [.] __mbrtowc
1.21% firefox libxul.so [.] 0x00000000024b62bd
1.20% swapper [kernel.vmlinux] [k] cpuidle_enter_state
1.03% sleep [kernel.vmlinux] [k] copy_user_generic_unrolled
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-9-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/machine.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 53f90e9c65fe..52e94902afb1 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1106,6 +1106,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
if (__machine__create_kernel_maps(machine, kernel) < 0)
goto out_problem;
+ if (strstr(dso->long_name, "vmlinux"))
+ dso__set_short_name(dso, "[kernel.vmlinux]", false);
+
machine__set_kernel_mmap_len(machine, event);
/*
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 15/18] perf tools: Add test_and_set_bit function
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (13 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 14/18] perf tools: Make vmlinux short name more like kallsyms short name Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 16/18] perf script perl: Removing event cache as it's no longer needed Arnaldo Carvalho de Melo
` (3 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Jiri Olsa, Adrian Hunter, David Ahern,
Frederic Weisbecker, Ingo Molnar, Namhyung Kim, Paul Mackerras,
Peter Zijlstra, Arnaldo Carvalho de Melo
From: Jiri Olsa <jolsa@kernel.org>
Set a bit and return its old value. Stolen from kernel sources, will be
used in next patches.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Namhyung Kim <namhyung@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1414363445-22370-1-git-send-email-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/include/linux/bitmap.h | 17 +++++++++++++++++
tools/perf/util/include/linux/bitops.h | 2 ++
2 files changed, 19 insertions(+)
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index 01ffd12dc791..40bd21488032 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -46,4 +46,21 @@ static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
__bitmap_or(dst, src1, src2, nbits);
}
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ */
+static inline int test_and_set_bit(int nr, unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+ unsigned long old;
+
+ old = *p;
+ *p = old | mask;
+
+ return (old & mask) != 0;
+}
+
#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index dadfa7e54287..c3294163de17 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -15,6 +15,8 @@
#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE)
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define for_each_set_bit(bit, addr, size) \
for ((bit) = find_first_bit((addr), (size)); \
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 16/18] perf script perl: Removing event cache as it's no longer needed
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (14 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 15/18] perf tools: Add test_and_set_bit function Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 17/18] perf script python: " Arnaldo Carvalho de Melo
` (2 subsequent siblings)
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Jiri Olsa, Adrian Hunter, David Ahern,
Frederic Weisbecker, Ingo Molnar, Namhyung Kim, Paul Mackerras,
Peter Zijlstra, Arnaldo Carvalho de Melo
From: Jiri Olsa <jolsa@kernel.org>
We don't need to maintain cache of 'struct event_format' objects.
Currently the 'struct perf_evsel' holds this reference already.
Adding events_defined bitmap to keep track of defined events, which is
much cheaper than array of pointers.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Namhyung Kim <namhyung@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1414363445-22370-2-git-send-email-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
.../perf/util/scripting-engines/trace-event-perl.c | 29 +++++-----------------
1 file changed, 6 insertions(+), 23 deletions(-)
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 0a01bac4ce02..22ebc46226e7 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <ctype.h>
#include <errno.h>
+#include <linux/bitmap.h>
#include "../util.h"
#include <EXTERN.h>
@@ -57,7 +58,7 @@ INTERP my_perl;
#define FTRACE_MAX_EVENT \
((1 << (sizeof(unsigned short) * 8)) - 1)
-struct event_format *events[FTRACE_MAX_EVENT];
+static DECLARE_BITMAP(events_defined, FTRACE_MAX_EVENT);
extern struct scripting_context *scripting_context;
@@ -238,35 +239,15 @@ static void define_event_symbols(struct event_format *event,
define_event_symbols(event, ev_name, args->next);
}
-static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
-{
- static char ev_name[256];
- struct event_format *event;
- int type = evsel->attr.config;
-
- if (events[type])
- return events[type];
-
- events[type] = event = evsel->tp_format;
- if (!event)
- return NULL;
-
- sprintf(ev_name, "%s::%s", event->system, event->name);
-
- define_event_symbols(event, ev_name, event->print_fmt.args);
-
- return event;
-}
-
static void perl_process_tracepoint(struct perf_sample *sample,
struct perf_evsel *evsel,
struct thread *thread)
{
+ struct event_format *event = evsel->tp_format;
struct format_field *field;
static char handler[256];
unsigned long long val;
unsigned long s, ns;
- struct event_format *event;
int pid;
int cpu = sample->cpu;
void *data = sample->raw_data;
@@ -278,7 +259,6 @@ static void perl_process_tracepoint(struct perf_sample *sample,
if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
return;
- event = find_cache_event(evsel);
if (!event)
die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config);
@@ -286,6 +266,9 @@ static void perl_process_tracepoint(struct perf_sample *sample,
sprintf(handler, "%s::%s", event->system, event->name);
+ if (!test_and_set_bit(event->id, events_defined))
+ define_event_symbols(event, handler, event->print_fmt.args);
+
s = nsecs / NSECS_PER_SEC;
ns = nsecs - s * NSECS_PER_SEC;
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 17/18] perf script python: Removing event cache as it's no longer needed
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (15 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 16/18] perf script perl: Removing event cache as it's no longer needed Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 18/18] perf evsel: Do not call pevent_free_format when deleting tracepoint Arnaldo Carvalho de Melo
2014-11-07 5:24 ` [GIT PULL 00/18] perf/core improvements and fixes Ingo Molnar
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Jiri Olsa, Adrian Hunter, David Ahern,
Frederic Weisbecker, Ingo Molnar, Namhyung Kim, Paul Mackerras,
Peter Zijlstra, Arnaldo Carvalho de Melo
From: Jiri Olsa <jolsa@kernel.org>
We don't need to maintain cache of 'struct event_format' objects.
Currently the 'struct perf_evsel' holds this reference already.
Adding events_defined bitmap to keep track of defined events, which is
much cheaper than array of pointers.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Namhyung Kim <namhyung@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1414363445-22370-3-git-send-email-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
.../util/scripting-engines/trace-event-python.c | 34 ++++------------------
1 file changed, 6 insertions(+), 28 deletions(-)
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 118bc62850a8..d808a328f4dc 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -26,6 +26,7 @@
#include <string.h>
#include <stdbool.h>
#include <errno.h>
+#include <linux/bitmap.h>
#include "../../perf.h"
#include "../debug.h"
@@ -46,7 +47,7 @@ PyMODINIT_FUNC initperf_trace_context(void);
#define FTRACE_MAX_EVENT \
((1 << (sizeof(unsigned short) * 8)) - 1)
-struct event_format *events[FTRACE_MAX_EVENT];
+static DECLARE_BITMAP(events_defined, FTRACE_MAX_EVENT);
#define MAX_FIELDS 64
#define N_COMMON_FIELDS 7
@@ -255,31 +256,6 @@ static void define_event_symbols(struct event_format *event,
define_event_symbols(event, ev_name, args->next);
}
-static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
-{
- static char ev_name[256];
- struct event_format *event;
- int type = evsel->attr.config;
-
- /*
- * XXX: Do we really need to cache this since now we have evsel->tp_format
- * cached already? Need to re-read this "cache" routine that as well calls
- * define_event_symbols() :-\
- */
- if (events[type])
- return events[type];
-
- events[type] = event = evsel->tp_format;
- if (!event)
- return NULL;
-
- sprintf(ev_name, "%s__%s", event->system, event->name);
-
- define_event_symbols(event, ev_name, event->print_fmt.args);
-
- return event;
-}
-
static PyObject *get_field_numeric_entry(struct event_format *event,
struct format_field *field, void *data)
{
@@ -403,12 +379,12 @@ static void python_process_tracepoint(struct perf_sample *sample,
struct thread *thread,
struct addr_location *al)
{
+ struct event_format *event = evsel->tp_format;
PyObject *handler, *context, *t, *obj, *callchain;
PyObject *dict = NULL;
static char handler_name[256];
struct format_field *field;
unsigned long s, ns;
- struct event_format *event;
unsigned n = 0;
int pid;
int cpu = sample->cpu;
@@ -420,7 +396,6 @@ static void python_process_tracepoint(struct perf_sample *sample,
if (!t)
Py_FatalError("couldn't create Python tuple");
- event = find_cache_event(evsel);
if (!event)
die("ug! no event found for type %d", (int)evsel->attr.config);
@@ -428,6 +403,9 @@ static void python_process_tracepoint(struct perf_sample *sample,
sprintf(handler_name, "%s__%s", event->system, event->name);
+ if (!test_and_set_bit(event->id, events_defined))
+ define_event_symbols(event, handler_name, event->print_fmt.args);
+
handler = get_handler(handler_name);
if (!handler) {
dict = PyDict_New();
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 18/18] perf evsel: Do not call pevent_free_format when deleting tracepoint
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (16 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 17/18] perf script python: " Arnaldo Carvalho de Melo
@ 2014-11-06 21:04 ` Arnaldo Carvalho de Melo
2014-11-07 5:24 ` [GIT PULL 00/18] perf/core improvements and fixes Ingo Molnar
18 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-11-06 21:04 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-kernel, Jiri Olsa, Corey Ashford, David Ahern,
Frederic Weisbecker, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
Steven Rostedt, Arnaldo Carvalho de Melo
From: Jiri Olsa <jolsa@kernel.org>
The libtraceevent library's main handle 'struct pevent' holds pointers
of every event that was added to it via functions:
pevent_parse_format
pevent_parse_event
We can't release struct event_format (call pevent_free_format)
separately, because that breaks that pointers array mentioned above and
another add_event call could end up with segfault.
All added events are released within the handle cleanup in pevent_free.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/1415098538-1512-1-git-send-email-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/evsel.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2f9e68025ede..12b4396c7175 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -853,8 +853,6 @@ void perf_evsel__exit(struct perf_evsel *evsel)
perf_evsel__free_id(evsel);
close_cgroup(evsel->cgrp);
zfree(&evsel->group_name);
- if (evsel->tp_format)
- pevent_free_format(evsel->tp_format);
zfree(&evsel->name);
perf_evsel__object.fini(evsel);
}
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [GIT PULL 00/18] perf/core improvements and fixes
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
` (17 preceding siblings ...)
2014-11-06 21:04 ` [PATCH 18/18] perf evsel: Do not call pevent_free_format when deleting tracepoint Arnaldo Carvalho de Melo
@ 2014-11-07 5:24 ` Ingo Molnar
18 siblings, 0 replies; 23+ messages in thread
From: Ingo Molnar @ 2014-11-07 5:24 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel, Adrian Hunter, Corey Ashford, David Ahern,
Frederic Weisbecker, Jiri Olsa, Namhyung Kim, Paul Mackerras,
Peter Zijlstra, Stephane Eranian, Steven Rostedt,
Arnaldo Carvalho de Melo
* Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> Hi Ingo,
>
> Please consider pulling,
>
> - Arnaldo
>
> The following changes since commit daa01794a4a36a1da1b09a529adec0c8c0b94ab2:
>
> perf evsel: Do not call pevent_free_format when deleting tracepoint (2014-11-06 17:47:14 -0300)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo
>
> for you to fetch changes up to daa01794a4a36a1da1b09a529adec0c8c0b94ab2:
>
> perf evsel: Do not call pevent_free_format when deleting tracepoint (2014-11-06 17:47:14 -0300)
>
> ----------------------------------------------------------------
> perf/core improvements and fixes:
>
> Infrastructure:
>
> o Add gzip decompression support for kernel modules (Namhyung Kim)
>
> o More prep patches for Intel PT, including a a thread stack and
> more stuff made available via the database export mechanism (Adrian Hunter)
>
> o Optimize checking that tracepoint events are defined in perf script perl/python (Jiri Olsa)
>
> o Do not free pevent when deleting tracepoint evsel (Jiri Olsa)
>
> o Fix build-id matching for vmlinux (Namhyung Kim)
>
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> ----------------------------------------------------------------
Pulled, thanks a lot Arnaldo!
Ingo
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 14/18] perf tools: Make vmlinux short name more like kallsyms short name
2014-11-06 21:04 ` [PATCH 14/18] perf tools: Make vmlinux short name more like kallsyms short name Arnaldo Carvalho de Melo
@ 2014-11-09 7:51 ` Jiri Olsa
2014-11-10 6:13 ` Namhyung Kim
0 siblings, 1 reply; 23+ messages in thread
From: Jiri Olsa @ 2014-11-09 7:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Ingo Molnar, linux-kernel, Namhyung Kim, Adrian Hunter,
David Ahern, Namhyung Kim, Paul Mackerras, Peter Zijlstra,
Stephane Eranian, Arnaldo Carvalho de Melo
On Thu, Nov 06, 2014 at 06:04:35PM -0300, Arnaldo Carvalho de Melo wrote:
> From: Namhyung Kim <namhyung@kernel.org>
>
> The previous patch changed kernel dso name from '[kernel.kallsyms]' to
> vmlinux. However it might add confusion to old users accustomed to the
> old name. So change the short name to '[kernel.vmlinux]' to reduce such
> confusion.
>
SNIP
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> ---
> tools/perf/util/machine.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
> index 53f90e9c65fe..52e94902afb1 100644
> --- a/tools/perf/util/machine.c
> +++ b/tools/perf/util/machine.c
> @@ -1106,6 +1106,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
> if (__machine__create_kernel_maps(machine, kernel) < 0)
> goto out_problem;
>
> + if (strstr(dso->long_name, "vmlinux"))
> + dso__set_short_name(dso, "[kernel.vmlinux]", false);
> +
heya,
I've got attached segfault in perf script because of this,
if I revert it's ok..
jirka
[jolsa@krava perf]$ ./perf record -e instructions -c 100000000 yes > /dev/null
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.013 MB perf.data (~576 samples) ]
[jolsa@krava perf]$ gdb ./perf
GNU gdb (GDB) Fedora 7.7.1-21.fc20
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./perf...done.
(gdb) r script
Starting program: /home/jolsa/kernel.org/linux-perf/tools/perf/perf script
warning: section not found in /usr/lib/debug/lib/modules/3.16.6-203.fc20.x86_64/vdso/vdso64.so.debug
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Detaching after fork from child process 6849.
Program received signal SIGSEGV, Segmentation fault.
__strstr_sse42 (s1=0x0, s2=0x5db702 "vmlinux") at ../sysdeps/x86_64/multiarch/strstr.c:175
175 if (__builtin_expect (p1[0] == '\0', 0))
Missing separate debuginfos, use: debuginfo-install audit-libs-2.4-2.fc20.x86_64 elfutils-libelf-0.160-1.fc20.x86_64 elfutils-libs-0.160-1.fc20.x86_64 libunwind-1.1-3.fc20.x86_64 nss-softokn-freebl-3.17.2-1.fc20.x86_64 numactl-libs-2.0.9-2.fc20.x86_64 perl-libs-5.18.4-290.fc20.x86_64 python-libs-2.7.5-14.fc20.x86_64 slang-2.2.4-11.fc20.x86_64 xz-libs-5.1.2-12alpha.fc20.x86_64 zlib-1.2.8-3.fc20.x86_64
(gdb) bt
#0 __strstr_sse42 (s1=0x0, s2=0x5db702 "vmlinux") at ../sysdeps/x86_64/multiarch/strstr.c:175
#1 0x00000000004a881d in machine__process_kernel_mmap_event (machine=0x8d3e80, event=0x7ffff7ff50d8)
at util/machine.c:1109
#2 0x00000000004a8b4f in machine__process_mmap_event (machine=0x8d3e80, event=0x7ffff7ff50d8,
sample=0x7fffffffd280) at util/machine.c:1203
#3 0x0000000000470e7e in perf_event__process_mmap (tool=0x7fffffffd650, event=0x7ffff7ff50d8,
sample=0x7fffffffd280, machine=0x8d3e80) at util/event.c:666
#4 0x00000000004af2fa in perf_session__deliver_event (session=0x8d3dc0, event=0x7ffff7ff50d8,
sample=0x7fffffffd280, tool=0x7fffffffd650, file_offset=216) at util/session.c:845
#5 0x00000000004afa96 in perf_session__process_event (session=0x8d3dc0, event=0x7ffff7ff50d8,
tool=0x7fffffffd650, file_offset=216) at util/session.c:1020
#6 0x00000000004b0451 in __perf_session__process_events (session=0x8d3dc0, data_offset=216, data_size=16240,
file_size=16456, tool=0x7fffffffd650) at util/session.c:1292
#7 0x00000000004b061e in perf_session__process_events (session=0x8d3dc0, tool=0x7fffffffd650)
at util/session.c:1337
#8 0x00000000004453d4 in __cmd_script (script=0x7fffffffd650) at builtin-script.c:803
#9 0x0000000000448858 in cmd_script (argc=0, argv=0x7fffffffe2e0, prefix=0x0) at builtin-script.c:1835
#10 0x000000000041c88c in run_builtin (p=0x856f70 <commands+336>, argc=1, argv=0x7fffffffe2e0) at perf.c:331
#11 0x000000000041caeb in handle_internal_command (argc=1, argv=0x7fffffffe2e0) at perf.c:390
#12 0x000000000041cc37 in run_argv (argcp=0x7fffffffe13c, argv=0x7fffffffe130) at perf.c:434
#13 0x000000000041cf8e in main (argc=1, argv=0x7fffffffe2e0) at perf.c:549
(gdb) q
A debugging session is active.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 14/18] perf tools: Make vmlinux short name more like kallsyms short name
2014-11-09 7:51 ` Jiri Olsa
@ 2014-11-10 6:13 ` Namhyung Kim
2014-11-10 15:29 ` Jiri Olsa
0 siblings, 1 reply; 23+ messages in thread
From: Namhyung Kim @ 2014-11-10 6:13 UTC (permalink / raw)
To: Jiri Olsa
Cc: Arnaldo Carvalho de Melo, Ingo Molnar, linux-kernel,
Adrian Hunter, David Ahern, Namhyung Kim, Paul Mackerras,
Peter Zijlstra, Stephane Eranian, Arnaldo Carvalho de Melo
Hi Jiri,
On Sun, 9 Nov 2014 08:51:26 +0100, Jiri Olsa wrote:
> On Thu, Nov 06, 2014 at 06:04:35PM -0300, Arnaldo Carvalho de Melo wrote:
>> From: Namhyung Kim <namhyung@kernel.org>
>>
>> The previous patch changed kernel dso name from '[kernel.kallsyms]' to
>> vmlinux. However it might add confusion to old users accustomed to the
>> old name. So change the short name to '[kernel.vmlinux]' to reduce such
>> confusion.
>>
>
> SNIP
>
>> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
>> ---
>> tools/perf/util/machine.c | 3 +++
>> 1 file changed, 3 insertions(+)
>>
>> diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
>> index 53f90e9c65fe..52e94902afb1 100644
>> --- a/tools/perf/util/machine.c
>> +++ b/tools/perf/util/machine.c
>> @@ -1106,6 +1106,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
>> if (__machine__create_kernel_maps(machine, kernel) < 0)
>> goto out_problem;
>>
>> + if (strstr(dso->long_name, "vmlinux"))
>> + dso__set_short_name(dso, "[kernel.vmlinux]", false);
>> +
>
> heya,
> I've got attached segfault in perf script because of this,
> if I revert it's ok..
Oops, sorry. It seems somehow to fail to find a matching kernel dso
from the build-id table.. anyway we need to access 'kernel' instead of
'dso' since it might be invalid at this time.
Could you please check below patch?
>From e28ec815465721b81669c47eb00d8307f4b424cd Mon Sep 17 00:00:00 2001
From: Namhyung Kim <namhyung@kernel.org>
Date: Mon, 10 Nov 2014 15:05:26 +0900
Subject: [PATCH] perf tools: Fix segfault due to invalid kernel dso access
When processing kernel mmap event, it should access the 'kernel'
variable as sometimes it cannot find a matching dso from build-id
table so 'dso' might be invalid.
Reported-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/util/machine.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 52e94902afb1..85033d80fd6a 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1106,8 +1106,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
if (__machine__create_kernel_maps(machine, kernel) < 0)
goto out_problem;
- if (strstr(dso->long_name, "vmlinux"))
- dso__set_short_name(dso, "[kernel.vmlinux]", false);
+ if (strstr(kernel->long_name, "vmlinux"))
+ dso__set_short_name(kernel, "[kernel.vmlinux]", false);
machine__set_kernel_mmap_len(machine, event);
--
2.1.2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH 14/18] perf tools: Make vmlinux short name more like kallsyms short name
2014-11-10 6:13 ` Namhyung Kim
@ 2014-11-10 15:29 ` Jiri Olsa
0 siblings, 0 replies; 23+ messages in thread
From: Jiri Olsa @ 2014-11-10 15:29 UTC (permalink / raw)
To: Namhyung Kim
Cc: Arnaldo Carvalho de Melo, Ingo Molnar, linux-kernel,
Adrian Hunter, David Ahern, Namhyung Kim, Paul Mackerras,
Peter Zijlstra, Stephane Eranian, Arnaldo Carvalho de Melo
On Mon, Nov 10, 2014 at 03:13:46PM +0900, Namhyung Kim wrote:
SNIP
> >> + dso__set_short_name(dso, "[kernel.vmlinux]", false);
> >> +
> >
> > heya,
> > I've got attached segfault in perf script because of this,
> > if I revert it's ok..
>
> Oops, sorry. It seems somehow to fail to find a matching kernel dso
> from the build-id table.. anyway we need to access 'kernel' instead of
> 'dso' since it might be invalid at this time.
>
> Could you please check below patch?
>
>
> From e28ec815465721b81669c47eb00d8307f4b424cd Mon Sep 17 00:00:00 2001
> From: Namhyung Kim <namhyung@kernel.org>
> Date: Mon, 10 Nov 2014 15:05:26 +0900
> Subject: [PATCH] perf tools: Fix segfault due to invalid kernel dso access
>
> When processing kernel mmap event, it should access the 'kernel'
> variable as sometimes it cannot find a matching dso from build-id
> table so 'dso' might be invalid.
>
> Reported-by: Jiri Olsa <jolsa@redhat.com>
> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
yep, works nicely now
Tested-by: Jiri Olsa <jolsa@redhat.com>
thanks,
jirka
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2014-11-10 15:30 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-06 21:04 [GIT PULL 00/18] perf/core improvements and fixes Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 01/18] perf tools: Add a thread stack for synthesizing call chains Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 02/18] perf tools: Enhance the thread stack to output call/return data Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 03/18] perf tools: Add branch type to db export Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 04/18] perf tools: Add branch_type and in_tx to Python export Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 05/18] perf tools: Add call information to the database export API Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 06/18] perf tools: Add call information to Python export Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 07/18] perf tools: Defer export of comms that were not 'set' Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 08/18] perf symbols: Preparation for compressed kernel module support Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 09/18] perf tools: Add gzip decompression support for kernel module Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 10/18] perf build-id: Rename dsos__write_buildid_table() Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 11/18] perf build-id: Move build-id related functions to util/build-id.c Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 12/18] perf record: Do not save pathname in ./debug/.build-id directory for vmlinux Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 13/18] perf tools: Fix build-id matching on vmlinux Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 14/18] perf tools: Make vmlinux short name more like kallsyms short name Arnaldo Carvalho de Melo
2014-11-09 7:51 ` Jiri Olsa
2014-11-10 6:13 ` Namhyung Kim
2014-11-10 15:29 ` Jiri Olsa
2014-11-06 21:04 ` [PATCH 15/18] perf tools: Add test_and_set_bit function Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 16/18] perf script perl: Removing event cache as it's no longer needed Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 17/18] perf script python: " Arnaldo Carvalho de Melo
2014-11-06 21:04 ` [PATCH 18/18] perf evsel: Do not call pevent_free_format when deleting tracepoint Arnaldo Carvalho de Melo
2014-11-07 5:24 ` [GIT PULL 00/18] perf/core improvements and fixes Ingo Molnar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).