From: Alexander Shishkin <alexander.shishkin@linux.intel.com>
To: Peter Zijlstra <a.p.zijlstra@chello.nl>,
Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Ingo Molnar <mingo@redhat.com>,
linux-kernel@vger.kernel.org, David Ahern <dsahern@gmail.com>,
Frederic Weisbecker <fweisbec@gmail.com>,
Jiri Olsa <jolsa@redhat.com>, Mike Galbraith <efault@gmx.de>,
Namhyung Kim <namhyung@gmail.com>,
Paul Mackerras <paulus@samba.org>,
Stephane Eranian <eranian@google.com>,
Andi Kleen <ak@linux.intel.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>
Subject: [PATCH v0 04/71] itrace: Infrastructure for instruction flow tracing units
Date: Wed, 11 Dec 2013 14:36:16 +0200 [thread overview]
Message-ID: <1386765443-26966-5-git-send-email-alexander.shishkin@linux.intel.com> (raw)
In-Reply-To: <1386765443-26966-1-git-send-email-alexander.shishkin@linux.intel.com>
Instruction tracing PMUs are capable of recording a log of instruction
execution flow on a cpu core, which can be useful for profiling and crash
analysis. This patch adds itrace infrastructure for perf events and the
rest of the kernel to use.
Since such PMUs can produce copious amounts of trace data, it may be
impractical to process it inside the kernel in real time, but instead export
raw trace streams to userspace for subsequent analysis. Thus, itrace PMUs
may export their trace buffers, which can be mmap()ed to userspace from a
perf event fd with a PERF_EVENT_ITRACE_OFFSET offset. To that end, perf
is extended to work with multiple ring buffers per event, reusing the
ring_buffer code in an attempt to reduce complexity.
Also, trace data from such PMUs can be used to annotate other perf events
by including it in sample records when PERF_SAMPLE_ITRACE flag is set. In
this case, a PT kernel counter is created for each such event and trace data
is retrieved from it and stored in the perf data stream.
Finally, such per thread trace data can be included in process core dumps,
which is controlled via a new rlimit parameter RLIMIT_ITRACE. This again
is done by a per-thread kernel counter that is created when this RLIMIT_ITRACE
is set.
This infrastructure should also be useful for ARM ETM/PTM and other program
flow tracing units that can potentially generate a lot of trace data very
fast.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
---
fs/binfmt_elf.c | 6 +
fs/proc/base.c | 1 +
include/asm-generic/resource.h | 1 +
include/linux/itrace.h | 147 +++++++++
include/linux/perf_event.h | 33 +-
include/uapi/asm-generic/resource.h | 3 +-
include/uapi/linux/elf.h | 1 +
include/uapi/linux/perf_event.h | 25 +-
kernel/events/Makefile | 2 +-
kernel/events/core.c | 299 ++++++++++++------
kernel/events/internal.h | 7 +
kernel/events/itrace.c | 589 ++++++++++++++++++++++++++++++++++++
kernel/events/ring_buffer.c | 2 +-
kernel/exit.c | 3 +
kernel/sys.c | 5 +
15 files changed, 1020 insertions(+), 104 deletions(-)
create mode 100644 include/linux/itrace.h
create mode 100644 kernel/events/itrace.c
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 571a423..c7fcd49 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -34,6 +34,7 @@
#include <linux/utsname.h>
#include <linux/coredump.h>
#include <linux/sched.h>
+#include <linux/itrace.h>
#include <asm/uaccess.h>
#include <asm/param.h>
#include <asm/page.h>
@@ -1576,6 +1577,8 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
}
}
+ *total += itrace_elf_note_size(t->task);
+
return 1;
}
@@ -1608,6 +1611,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
for (i = 0; i < view->n; ++i)
if (view->regsets[i].core_note_type != 0)
++info->thread_notes;
+ info->thread_notes++; /* ITRACE */
/*
* Sanity check. We rely on regset 0 being in NT_PRSTATUS,
@@ -1710,6 +1714,8 @@ static int write_note_info(struct elf_note_info *info,
!writenote(&t->notes[i], cprm))
return 0;
+ itrace_elf_note_write(cprm, t->task);
+
first = 0;
t = t->next;
} while (t);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1485e38..41785ec 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -471,6 +471,7 @@ static const struct limit_names lnames[RLIM_NLIMITS] = {
[RLIMIT_NICE] = {"Max nice priority", NULL},
[RLIMIT_RTPRIO] = {"Max realtime priority", NULL},
[RLIMIT_RTTIME] = {"Max realtime timeout", "us"},
+ [RLIMIT_ITRACE] = {"Max ITRACE buffer size", "bytes"},
};
/* Display limits for a process */
diff --git a/include/asm-generic/resource.h b/include/asm-generic/resource.h
index b4ea8f5..e6e5657 100644
--- a/include/asm-generic/resource.h
+++ b/include/asm-generic/resource.h
@@ -25,6 +25,7 @@
[RLIMIT_NICE] = { 0, 0 }, \
[RLIMIT_RTPRIO] = { 0, 0 }, \
[RLIMIT_RTTIME] = { RLIM_INFINITY, RLIM_INFINITY }, \
+ [RLIMIT_ITRACE] = { 0, RLIM_INFINITY }, \
}
#endif
diff --git a/include/linux/itrace.h b/include/linux/itrace.h
new file mode 100644
index 0000000..c4175b3
--- /dev/null
+++ b/include/linux/itrace.h
@@ -0,0 +1,147 @@
+/*
+ * Instruction flow trace unit infrastructure
+ * Copyright (c) 2013, 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _LINUX_ITRACE_H
+#define _LINUX_ITRACE_H
+
+#include <linux/perf_event.h>
+#include <linux/coredump.h>
+
+extern struct ring_buffer_ops itrace_rb_ops;
+
+#define PERF_EVENT_ITRACE_PGOFF (PERF_EVENT_ITRACE_OFFSET >> PAGE_SHIFT)
+
+static inline bool is_itrace_vma(struct vm_area_struct *vma)
+{
+ return vma->vm_pgoff == PERF_EVENT_ITRACE_PGOFF;
+}
+
+void *itrace_priv(struct perf_event *event);
+
+void *itrace_event_get_priv(struct perf_event *event);
+void itrace_event_put(struct perf_event *event);
+
+struct itrace_pmu {
+ struct pmu pmu;
+ /*
+ * Allocate/free ring_buffer backing store
+ */
+ void *(*alloc_buffer)(int cpu, int nr_pages, bool overwrite,
+ void **pages,
+ struct perf_event_mmap_page **user_page);
+ void (*free_buffer)(void *buffer);
+
+ int (*event_init)(struct perf_event *event);
+
+ /*
+ * Calculate the size of a sample to be written out
+ */
+ unsigned long (*sample_trace)(struct perf_event *event,
+ struct perf_sample_data *data);
+
+ /*
+ * Write out a trace sample to the given output handle
+ */
+ void (*sample_output)(struct perf_event *event,
+ struct perf_output_handle *handle,
+ struct perf_sample_data *data);
+
+ /*
+ * Get the PMU-specific part of a core dump note
+ */
+ size_t (*core_size)(struct perf_event *event);
+
+ /*
+ * Write out the core dump note
+ */
+ void (*core_output)(struct coredump_params *cprm,
+ struct perf_event *event,
+ unsigned long len);
+ char *name;
+};
+
+#define to_itrace_pmu(x) container_of((x), struct itrace_pmu, pmu)
+
+#ifdef CONFIG_PERF_EVENTS
+
+extern void itrace_lost_data(struct perf_event *event, u64 offset);
+extern int itrace_pmu_register(struct itrace_pmu *ipmu);
+
+extern int itrace_event_installable(struct perf_event *event,
+ struct perf_event_context *ctx);
+
+extern void itrace_wake_up(struct perf_event *event);
+
+extern bool is_itrace_event(struct perf_event *event);
+
+extern int itrace_sampler_init(struct perf_event *event,
+ struct task_struct *task);
+extern void itrace_sampler_fini(struct perf_event *event);
+extern unsigned long itrace_sampler_trace(struct perf_event *event,
+ struct perf_sample_data *data);
+extern void itrace_sampler_output(struct perf_event *event,
+ struct perf_output_handle *handle,
+ struct perf_sample_data *data);
+
+extern int update_itrace_rlimit(struct task_struct *, unsigned long);
+extern void exit_itrace(struct task_struct *);
+
+struct itrace_note {
+ u64 itrace_config;
+};
+
+extern size_t itrace_elf_note_size(struct task_struct *tsk);
+extern void itrace_elf_note_write(struct coredump_params *cprm,
+ struct task_struct *task);
+#else
+static inline void
+itrace_lost_data(struct perf_event *event, u64 offset) {}
+static inline int itrace_pmu_register(struct itrace_pmu *ipmu) { return -EINVAL; }
+
+static inline int
+itrace_event_installable(struct perf_event *event,
+ struct perf_event_context *ctx) { return -EINVAL; }
+static inline void itrace_wake_up(struct perf_event *event) {}
+static inline bool is_itrace_event(struct perf_event *event) { return false; }
+
+static inline int itrace_sampler_init(struct perf_event *event,
+ struct task_struct *task) {}
+static inline void
+itrace_sampler_fini(struct perf_event *event) {}
+static inline unsigned long
+itrace_sampler_trace(struct perf_event *event,
+ struct perf_sample_data *data) { return 0; }
+static inline void
+itrace_sampler_output(struct perf_event *event,
+ struct perf_output_handle *handle,
+ struct perf_sample_data *data) {}
+
+static inline int
+update_itrace_rlimit(struct task_struct *, unsigned long) { return -EINVAL; }
+static inline void exit_itrace(struct task_struct *) {}
+
+static inline size_t
+itrace_elf_note_size(struct task_struct *tsk) { return 0; }
+static inline void
+itrace_elf_note_write(struct coredump_params *cprm,
+ struct task_struct *task) {}
+
+#endif
+
+#endif /* _LINUX_PERF_EVENT_H */
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 8f4a70f..b27cfc7 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -83,6 +83,12 @@ struct perf_regs_user {
struct pt_regs *regs;
};
+struct perf_trace_record {
+ u64 size;
+ unsigned long from;
+ unsigned long to;
+};
+
struct task_struct;
/*
@@ -97,6 +103,14 @@ struct hw_perf_event_extra {
struct event_constraint;
+enum perf_itrace_counter_type {
+ PERF_ITRACE_USER = BIT(1),
+ PERF_ITRACE_SAMPLING = BIT(2),
+ PERF_ITRACE_COREDUMP = BIT(3),
+ PERF_ITRACE_KERNEL = (PERF_ITRACE_SAMPLING | PERF_ITRACE_COREDUMP),
+ PERF_ITRACE_ANY = (PERF_ITRACE_KERNEL | PERF_ITRACE_USER),
+};
+
/**
* struct hw_perf_event - performance event hardware details:
*/
@@ -126,6 +140,10 @@ struct hw_perf_event {
/* for tp_event->class */
struct list_head tp_list;
};
+ struct { /* itrace */
+ struct task_struct *itrace_target;
+ unsigned int counter_type;
+ };
#ifdef CONFIG_HAVE_HW_BREAKPOINT
struct { /* breakpoint */
/*
@@ -289,6 +307,12 @@ struct swevent_hlist {
struct perf_cgroup;
struct ring_buffer;
+enum perf_event_rb {
+ PERF_RB_MAIN = 0,
+ PERF_RB_ITRACE,
+ PERF_NR_RB,
+};
+
/**
* struct perf_event - performance event kernel representation:
*/
@@ -400,10 +424,10 @@ struct perf_event {
/* mmap bits */
struct mutex mmap_mutex;
- atomic_t mmap_count;
+ atomic_t mmap_count[PERF_NR_RB];
- struct ring_buffer *rb;
- struct list_head rb_entry;
+ struct ring_buffer *rb[PERF_NR_RB];
+ struct list_head rb_entry[PERF_NR_RB];
/* poll related */
wait_queue_head_t waitq;
@@ -426,6 +450,7 @@ struct perf_event {
perf_overflow_handler_t overflow_handler;
void *overflow_handler_context;
+ struct perf_event *trace_event;
#ifdef CONFIG_EVENT_TRACING
struct ftrace_event_call *tp_event;
struct event_filter *filter;
@@ -583,6 +608,7 @@ struct perf_sample_data {
union perf_mem_data_src data_src;
struct perf_callchain_entry *callchain;
struct perf_raw_record *raw;
+ struct perf_trace_record trace;
struct perf_branch_stack *br_stack;
struct perf_regs_user regs_user;
u64 stack_user_size;
@@ -603,6 +629,7 @@ static inline void perf_sample_data_init(struct perf_sample_data *data,
data->period = period;
data->regs_user.abi = PERF_SAMPLE_REGS_ABI_NONE;
data->regs_user.regs = NULL;
+ data->trace.from = data->trace.to = data->trace.size = 0;
data->stack_user_size = 0;
data->weight = 0;
data->data_src.val = 0;
diff --git a/include/uapi/asm-generic/resource.h b/include/uapi/asm-generic/resource.h
index f863428..073f413 100644
--- a/include/uapi/asm-generic/resource.h
+++ b/include/uapi/asm-generic/resource.h
@@ -45,7 +45,8 @@
0-39 for nice level 19 .. -20 */
#define RLIMIT_RTPRIO 14 /* maximum realtime priority */
#define RLIMIT_RTTIME 15 /* timeout for RT tasks in us */
-#define RLIM_NLIMITS 16
+#define RLIMIT_ITRACE 16 /* max itrace size */
+#define RLIM_NLIMITS 17
/*
* SuS says limits have to be unsigned.
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index ef6103b..4bfbf66 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -369,6 +369,7 @@ typedef struct elf64_shdr {
#define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4
#define NT_AUXV 6
+#define NT_ITRACE 7
/*
* Note to userspace developers: size of NT_SIGINFO note may increase
* in the future to accomodate more fields, don't assume it is fixed!
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index e1802d6..9e3a890 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -137,8 +137,9 @@ enum perf_event_sample_format {
PERF_SAMPLE_DATA_SRC = 1U << 15,
PERF_SAMPLE_IDENTIFIER = 1U << 16,
PERF_SAMPLE_TRANSACTION = 1U << 17,
+ PERF_SAMPLE_ITRACE = 1U << 18,
- PERF_SAMPLE_MAX = 1U << 18, /* non-ABI */
+ PERF_SAMPLE_MAX = 1U << 19, /* non-ABI */
};
/*
@@ -237,6 +238,10 @@ enum perf_event_read_format {
#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
/* add: sample_stack_user */
+#define PERF_ATTR_SIZE_VER4 120 /* add: itrace_config */
+ /* add: itrace_watermark */
+ /* add: itrace_sample_type */
+ /* add: itrace_sample_size */
/*
* Hardware event_id to monitor via a performance monitoring event:
@@ -333,6 +338,11 @@ struct perf_event_attr {
/* Align to u64. */
__u32 __reserved_2;
+
+ __u64 itrace_config;
+ __u32 itrace_watermark; /* wakeup every n pages */
+ __u32 itrace_sample_type; /* pmu->type of the itrace PMU */
+ __u64 itrace_sample_size;
};
#define perf_flags(attr) (*(&(attr)->read_format + 1))
@@ -679,6 +689,8 @@ enum perf_event_type {
*
* { u64 weight; } && PERF_SAMPLE_WEIGHT
* { u64 data_src; } && PERF_SAMPLE_DATA_SRC
+ * { u64 size;
+ * char data[size]; } && PERF_SAMPLE_ITRACE
* };
*/
PERF_RECORD_SAMPLE = 9,
@@ -704,9 +716,20 @@ enum perf_event_type {
*/
PERF_RECORD_MMAP2 = 10,
+ /*
+ * struct {
+ * u64 offset;
+ * }
+ */
+ PERF_RECORD_ITRACE_LOST = 11,
+
PERF_RECORD_MAX, /* non-ABI */
};
+/* Architecture-specific data */
+
+#define PERF_EVENT_ITRACE_OFFSET 0x40000000
+
#define PERF_MAX_STACK_DEPTH 127
enum perf_callchain_context {
diff --git a/kernel/events/Makefile b/kernel/events/Makefile
index 103f5d1..46a3770 100644
--- a/kernel/events/Makefile
+++ b/kernel/events/Makefile
@@ -2,7 +2,7 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_core.o = -pg
endif
-obj-y := core.o ring_buffer.o callchain.o
+obj-y := core.o ring_buffer.o callchain.o itrace.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_UPROBES) += uprobes.o
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 7c3faf1..ca8a130 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -39,6 +39,7 @@
#include <linux/hw_breakpoint.h>
#include <linux/mm_types.h>
#include <linux/cgroup.h>
+#include <linux/itrace.h>
#include "internal.h"
@@ -1575,6 +1576,9 @@ void perf_event_disable(struct perf_event *event)
struct perf_event_context *ctx = event->ctx;
struct task_struct *task = ctx->task;
+ if (event->trace_event)
+ perf_event_disable(event->trace_event);
+
if (!task) {
/*
* Disable the event on the cpu that it's on
@@ -2071,6 +2075,8 @@ void perf_event_enable(struct perf_event *event)
struct perf_event_context *ctx = event->ctx;
struct task_struct *task = ctx->task;
+ if (event->trace_event)
+ perf_event_enable(event->trace_event);
if (!task) {
/*
* Enable the event on the cpu that it's on
@@ -3180,9 +3186,6 @@ static void free_event_rcu(struct rcu_head *head)
kfree(event);
}
-static void ring_buffer_put(struct ring_buffer *rb);
-static void ring_buffer_detach(struct perf_event *event, struct ring_buffer *rb);
-
static void unaccount_event_cpu(struct perf_event *event, int cpu)
{
if (event->parent)
@@ -3215,6 +3218,8 @@ static void unaccount_event(struct perf_event *event)
static_key_slow_dec_deferred(&perf_sched_events);
if (has_branch_stack(event))
static_key_slow_dec_deferred(&perf_sched_events);
+ if ((event->attr.sample_type & PERF_SAMPLE_ITRACE) && event->trace_event)
+ itrace_sampler_fini(event);
unaccount_event_cpu(event, event->cpu);
}
@@ -3236,28 +3241,31 @@ static void __free_event(struct perf_event *event)
}
static void free_event(struct perf_event *event)
{
+ int rbx;
+
irq_work_sync(&event->pending);
unaccount_event(event);
- if (event->rb) {
- struct ring_buffer *rb;
+ for (rbx = PERF_RB_MAIN; rbx < PERF_NR_RB; rbx++)
+ if (event->rb[rbx]) {
+ struct ring_buffer *rb;
- /*
- * Can happen when we close an event with re-directed output.
- *
- * Since we have a 0 refcount, perf_mmap_close() will skip
- * over us; possibly making our ring_buffer_put() the last.
- */
- mutex_lock(&event->mmap_mutex);
- rb = event->rb;
- if (rb) {
- rcu_assign_pointer(event->rb, NULL);
- ring_buffer_detach(event, rb);
- ring_buffer_put(rb); /* could be last */
+ /*
+ * Can happen when we close an event with re-directed output.
+ *
+ * Since we have a 0 refcount, perf_mmap_close() will skip
+ * over us; possibly making our ring_buffer_put() the last.
+ */
+ mutex_lock(&event->mmap_mutex);
+ rb = event->rb[rbx];
+ if (rb) {
+ rcu_assign_pointer(event->rb[rbx], NULL);
+ ring_buffer_detach(event, rb);
+ ring_buffer_put(rb); /* could be last */
+ }
+ mutex_unlock(&event->mmap_mutex);
}
- mutex_unlock(&event->mmap_mutex);
- }
if (is_cgroup_event(event))
perf_detach_cgroup(event);
@@ -3486,21 +3494,24 @@ static unsigned int perf_poll(struct file *file, poll_table *wait)
{
struct perf_event *event = file->private_data;
struct ring_buffer *rb;
- unsigned int events = POLL_HUP;
+ unsigned int events = 0;
+ int i;
/*
* Pin the event->rb by taking event->mmap_mutex; otherwise
* perf_event_set_output() can swizzle our rb and make us miss wakeups.
*/
mutex_lock(&event->mmap_mutex);
- rb = event->rb;
- if (rb)
- events = atomic_xchg(&rb->poll, 0);
+ for (i = PERF_RB_MAIN; i < PERF_NR_RB; i++) {
+ rb = event->rb[i];
+ if (rb)
+ events |= atomic_xchg(&rb->poll, 0);
+ }
mutex_unlock(&event->mmap_mutex);
poll_wait(file, &event->waitq, wait);
- return events;
+ return events ? events : POLL_HUP;
}
static void perf_event_reset(struct perf_event *event)
@@ -3717,7 +3728,7 @@ static void perf_event_init_userpage(struct perf_event *event)
struct ring_buffer *rb;
rcu_read_lock();
- rb = rcu_dereference(event->rb);
+ rb = rcu_dereference(event->rb[PERF_RB_MAIN]);
if (!rb)
goto unlock;
@@ -3747,7 +3758,7 @@ void perf_event_update_userpage(struct perf_event *event)
u64 enabled, running, now;
rcu_read_lock();
- rb = rcu_dereference(event->rb);
+ rb = rcu_dereference(event->rb[PERF_RB_MAIN]);
if (!rb)
goto unlock;
@@ -3794,23 +3805,29 @@ static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct perf_event *event = vma->vm_file->private_data;
struct ring_buffer *rb;
- int ret = VM_FAULT_SIGBUS;
+ unsigned long pgoff = vmf->pgoff;
+ int ret = VM_FAULT_SIGBUS, rbx = PERF_RB_MAIN;
+
+ if (is_itrace_event(event) && is_itrace_vma(vma)) {
+ rbx = PERF_RB_ITRACE;
+ pgoff -= PERF_EVENT_ITRACE_PGOFF;
+ }
if (vmf->flags & FAULT_FLAG_MKWRITE) {
- if (vmf->pgoff == 0)
+ if (pgoff == 0)
ret = 0;
return ret;
}
rcu_read_lock();
- rb = rcu_dereference(event->rb);
+ rb = rcu_dereference(event->rb[rbx]);
if (!rb)
goto unlock;
- if (vmf->pgoff && (vmf->flags & FAULT_FLAG_WRITE))
+ if (pgoff && (vmf->flags & FAULT_FLAG_WRITE))
goto unlock;
- vmf->page = perf_mmap_to_page(rb, vmf->pgoff);
+ vmf->page = perf_mmap_to_page(rb, pgoff);
if (!vmf->page)
goto unlock;
@@ -3825,29 +3842,33 @@ unlock:
return ret;
}
-static void ring_buffer_attach(struct perf_event *event,
- struct ring_buffer *rb)
+void ring_buffer_attach(struct perf_event *event,
+ struct ring_buffer *rb)
{
+ int rbx = rb->priv ? PERF_RB_ITRACE : PERF_RB_MAIN;
+ struct list_head *head = &event->rb_entry[rbx];
unsigned long flags;
- if (!list_empty(&event->rb_entry))
+ if (!list_empty(head))
return;
spin_lock_irqsave(&rb->event_lock, flags);
- if (list_empty(&event->rb_entry))
- list_add(&event->rb_entry, &rb->event_list);
+ if (list_empty(head))
+ list_add(head, &rb->event_list);
spin_unlock_irqrestore(&rb->event_lock, flags);
}
-static void ring_buffer_detach(struct perf_event *event, struct ring_buffer *rb)
+void ring_buffer_detach(struct perf_event *event, struct ring_buffer *rb)
{
+ int rbx = rb->priv ? PERF_RB_ITRACE : PERF_RB_MAIN;
+ struct list_head *head = &event->rb_entry[rbx];
unsigned long flags;
- if (list_empty(&event->rb_entry))
+ if (list_empty(head))
return;
spin_lock_irqsave(&rb->event_lock, flags);
- list_del_init(&event->rb_entry);
+ list_del_init(head);
wake_up_all(&event->waitq);
spin_unlock_irqrestore(&rb->event_lock, flags);
}
@@ -3855,12 +3876,16 @@ static void ring_buffer_detach(struct perf_event *event, struct ring_buffer *rb)
static void ring_buffer_wakeup(struct perf_event *event)
{
struct ring_buffer *rb;
+ struct perf_event *iter;
+ int rbx;
rcu_read_lock();
- rb = rcu_dereference(event->rb);
- if (rb) {
- list_for_each_entry_rcu(event, &rb->event_list, rb_entry)
- wake_up_all(&event->waitq);
+ for (rbx = PERF_RB_MAIN; rbx < PERF_NR_RB; rbx++) {
+ rb = rcu_dereference(event->rb[rbx]);
+ if (rb) {
+ list_for_each_entry_rcu(iter, &rb->event_list, rb_entry[rbx])
+ wake_up_all(&iter->waitq);
+ }
}
rcu_read_unlock();
}
@@ -3873,12 +3898,12 @@ static void rb_free_rcu(struct rcu_head *rcu_head)
rb_free(rb);
}
-static struct ring_buffer *ring_buffer_get(struct perf_event *event)
+struct ring_buffer *ring_buffer_get(struct perf_event *event, int rbx)
{
struct ring_buffer *rb;
rcu_read_lock();
- rb = rcu_dereference(event->rb);
+ rb = rcu_dereference(event->rb[rbx]);
if (rb) {
if (!atomic_inc_not_zero(&rb->refcount))
rb = NULL;
@@ -3888,7 +3913,7 @@ static struct ring_buffer *ring_buffer_get(struct perf_event *event)
return rb;
}
-static void ring_buffer_put(struct ring_buffer *rb)
+void ring_buffer_put(struct ring_buffer *rb)
{
if (!atomic_dec_and_test(&rb->refcount))
return;
@@ -3901,9 +3926,10 @@ static void ring_buffer_put(struct ring_buffer *rb)
static void perf_mmap_open(struct vm_area_struct *vma)
{
struct perf_event *event = vma->vm_file->private_data;
+ int rbx = is_itrace_vma(vma) ? PERF_RB_ITRACE : PERF_RB_MAIN;
- atomic_inc(&event->mmap_count);
- atomic_inc(&event->rb->mmap_count);
+ atomic_inc(&event->mmap_count[rbx]);
+ atomic_inc(&event->rb[rbx]->mmap_count);
}
/*
@@ -3917,19 +3943,19 @@ static void perf_mmap_open(struct vm_area_struct *vma)
static void perf_mmap_close(struct vm_area_struct *vma)
{
struct perf_event *event = vma->vm_file->private_data;
-
- struct ring_buffer *rb = event->rb;
+ int rbx = is_itrace_vma(vma) ? PERF_RB_ITRACE : PERF_RB_MAIN;
+ struct ring_buffer *rb = event->rb[rbx];
struct user_struct *mmap_user = rb->mmap_user;
int mmap_locked = rb->mmap_locked;
unsigned long size = perf_data_size(rb);
atomic_dec(&rb->mmap_count);
- if (!atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex))
+ if (!atomic_dec_and_mutex_lock(&event->mmap_count[rbx], &event->mmap_mutex))
return;
/* Detach current event from the buffer. */
- rcu_assign_pointer(event->rb, NULL);
+ rcu_assign_pointer(event->rb[rbx], NULL);
ring_buffer_detach(event, rb);
mutex_unlock(&event->mmap_mutex);
@@ -3946,7 +3972,7 @@ static void perf_mmap_close(struct vm_area_struct *vma)
*/
again:
rcu_read_lock();
- list_for_each_entry_rcu(event, &rb->event_list, rb_entry) {
+ list_for_each_entry_rcu(event, &rb->event_list, rb_entry[rbx]) {
if (!atomic_long_inc_not_zero(&event->refcount)) {
/*
* This event is en-route to free_event() which will
@@ -3967,8 +3993,8 @@ again:
* still restart the iteration to make sure we're not now
* iterating the wrong list.
*/
- if (event->rb == rb) {
- rcu_assign_pointer(event->rb, NULL);
+ if (event->rb[rbx] == rb) {
+ rcu_assign_pointer(event->rb[rbx], NULL);
ring_buffer_detach(event, rb);
ring_buffer_put(rb); /* can't be last, we still have one */
}
@@ -4017,6 +4043,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
unsigned long nr_pages;
long user_extra, extra;
int ret = 0, flags = 0;
+ int rbx = PERF_RB_MAIN;
/*
* Don't allow mmap() of inherited per-task counters. This would
@@ -4030,31 +4057,39 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
return -EINVAL;
vma_size = vma->vm_end - vma->vm_start;
+
+ if (is_itrace_event(event) && is_itrace_vma(vma))
+ rbx = PERF_RB_ITRACE;
+
nr_pages = (vma_size / PAGE_SIZE) - 1;
/*
* If we have rb pages ensure they're a power-of-two number, so we
* can do bitmasks instead of modulo.
*/
- if (nr_pages != 0 && !is_power_of_2(nr_pages))
- return -EINVAL;
+ if (!rbx) {
+ if (nr_pages != 0 && !is_power_of_2(nr_pages))
+ return -EINVAL;
+
+ if (vma->vm_pgoff != 0)
+ return -EINVAL;
+ }
if (vma_size != PAGE_SIZE * (1 + nr_pages))
return -EINVAL;
- if (vma->vm_pgoff != 0)
- return -EINVAL;
WARN_ON_ONCE(event->ctx->parent_ctx);
again:
mutex_lock(&event->mmap_mutex);
- if (event->rb) {
- if (event->rb->nr_pages != nr_pages) {
+ rb = event->rb[rbx];
+ if (rb) {
+ if (rb->nr_pages != nr_pages) {
ret = -EINVAL;
goto unlock;
}
- if (!atomic_inc_not_zero(&event->rb->mmap_count)) {
+ if (!atomic_inc_not_zero(&rb->mmap_count)) {
/*
* Raced against perf_mmap_close() through
* perf_event_set_output(). Try again, hope for better
@@ -4091,14 +4126,14 @@ again:
goto unlock;
}
- WARN_ON(event->rb);
+ WARN_ON(event->rb[rbx]);
if (vma->vm_flags & VM_WRITE)
flags |= RING_BUFFER_WRITABLE;
rb = rb_alloc(nr_pages,
event->attr.watermark ? event->attr.wakeup_watermark : 0,
- event->cpu, flags, NULL);
+ event->cpu, flags, rbx ? &itrace_rb_ops : NULL);
if (!rb) {
ret = -ENOMEM;
@@ -4113,14 +4148,14 @@ again:
vma->vm_mm->pinned_vm += extra;
ring_buffer_attach(event, rb);
- rcu_assign_pointer(event->rb, rb);
+ rcu_assign_pointer(event->rb[rbx], rb);
perf_event_init_userpage(event);
perf_event_update_userpage(event);
unlock:
if (!ret)
- atomic_inc(&event->mmap_count);
+ atomic_inc(&event->mmap_count[rbx]);
mutex_unlock(&event->mmap_mutex);
/*
@@ -4626,6 +4661,13 @@ void perf_output_sample(struct perf_output_handle *handle,
if (sample_type & PERF_SAMPLE_TRANSACTION)
perf_output_put(handle, data->txn);
+ if (sample_type & PERF_SAMPLE_ITRACE) {
+ perf_output_put(handle, data->trace.size);
+
+ if (data->trace.size)
+ itrace_sampler_output(event, handle, data);
+ }
+
if (!event->attr.watermark) {
int wakeup_events = event->attr.wakeup_events;
@@ -4733,6 +4775,14 @@ void perf_prepare_sample(struct perf_event_header *header,
data->stack_user_size = stack_size;
header->size += size;
}
+
+ if (sample_type & PERF_SAMPLE_ITRACE) {
+ u64 size = sizeof(u64);
+
+ size += itrace_sampler_trace(event, data);
+
+ header->size += size;
+ }
}
static void perf_event_output(struct perf_event *event,
@@ -6652,6 +6702,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
struct perf_event *event;
struct hw_perf_event *hwc;
long err = -EINVAL;
+ int rbx;
if ((unsigned)cpu >= nr_cpu_ids) {
if (!task || cpu != -1)
@@ -6675,7 +6726,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
INIT_LIST_HEAD(&event->group_entry);
INIT_LIST_HEAD(&event->event_entry);
INIT_LIST_HEAD(&event->sibling_list);
- INIT_LIST_HEAD(&event->rb_entry);
+ for (rbx = PERF_RB_MAIN; rbx < PERF_NR_RB; rbx++)
+ INIT_LIST_HEAD(&event->rb_entry[rbx]);
INIT_LIST_HEAD(&event->active_entry);
init_waitqueue_head(&event->waitq);
@@ -6702,6 +6754,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
if (attr->type == PERF_TYPE_TRACEPOINT)
event->hw.tp_target = task;
+ else if (is_itrace_event(event))
+ event->hw.itrace_target = task;
#ifdef CONFIG_HAVE_HW_BREAKPOINT
/*
* hw_breakpoint is a bit difficult here..
@@ -6751,6 +6805,15 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
if (err)
goto err_pmu;
}
+
+ if (event->attr.sample_type & PERF_SAMPLE_ITRACE) {
+ err = itrace_sampler_init(event, task);
+ if (err) {
+ /* XXX: either clean up callchain buffers too
+ or forbid them to go together */
+ goto err_pmu;
+ }
+ }
}
return event;
@@ -6901,8 +6964,7 @@ err_size:
static int
perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
{
- struct ring_buffer *rb = NULL, *old_rb = NULL;
- int ret = -EINVAL;
+ int ret = -EINVAL, rbx;
if (!output_event)
goto set;
@@ -6922,42 +6984,60 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
*/
if (output_event->cpu == -1 && output_event->ctx != event->ctx)
goto out;
+ /*
+ * XXX^2: that's all bollocks
+ * + for sampling events, both get to keep their ->trace_event
+ * + for normal itrace events, the rules:
+ * * no cross-cpu buffers (as any other event);
+ * * both must be itrace events
+ */
+ if (is_itrace_event(event)) {
+ if (!is_itrace_event(output_event))
+ goto out;
+
+ if (event->attr.type != output_event->attr.type)
+ goto out;
+ }
set:
mutex_lock(&event->mmap_mutex);
- /* Can't redirect output if we've got an active mmap() */
- if (atomic_read(&event->mmap_count))
- goto unlock;
- old_rb = event->rb;
+ for (rbx = PERF_RB_MAIN; rbx < PERF_NR_RB; rbx++) {
+ struct ring_buffer *rb = NULL, *old_rb = NULL;
- if (output_event) {
- /* get the rb we want to redirect to */
- rb = ring_buffer_get(output_event);
- if (!rb)
- goto unlock;
- }
+ /* Can't redirect output if we've got an active mmap() */
+ if (atomic_read(&event->mmap_count[rbx]))
+ continue;
- if (old_rb)
- ring_buffer_detach(event, old_rb);
+ old_rb = event->rb[rbx];
- if (rb)
- ring_buffer_attach(event, rb);
+ if (output_event) {
+ /* get the rb we want to redirect to */
+ rb = ring_buffer_get(output_event, rbx);
+ if (!rb)
+ continue;
+ }
- rcu_assign_pointer(event->rb, rb);
+ if (old_rb)
+ ring_buffer_detach(event, old_rb);
- if (old_rb) {
- ring_buffer_put(old_rb);
- /*
- * Since we detached before setting the new rb, so that we
- * could attach the new rb, we could have missed a wakeup.
- * Provide it now.
- */
- wake_up_all(&event->waitq);
+ if (rb)
+ ring_buffer_attach(event, rb);
+
+ rcu_assign_pointer(event->rb[rbx], rb);
+
+ if (old_rb) {
+ ring_buffer_put(old_rb);
+ /*
+ * Since we detached before setting the new rb, so that we
+ * could attach the new rb, we could have missed a wakeup.
+ * Provide it now.
+ */
+ wake_up_all(&event->waitq);
+ }
}
ret = 0;
-unlock:
mutex_unlock(&event->mmap_mutex);
out:
@@ -7095,6 +7175,10 @@ SYSCALL_DEFINE5(perf_event_open,
goto err_alloc;
}
+ err = itrace_event_installable(event, ctx);
+ if (err)
+ goto err_alloc;
+
if (task) {
put_task_struct(task);
task = NULL;
@@ -7223,6 +7307,9 @@ err_fd:
return err;
}
+/* XXX */
+int itrace_kernel_event(struct perf_event *event, struct task_struct *task);
+
/**
* perf_event_create_kernel_counter
*
@@ -7253,12 +7340,20 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
account_event(event);
+ err = itrace_kernel_event(event, task);
+ if (err)
+ goto err_free;
+
ctx = find_get_context(event->pmu, task, cpu);
if (IS_ERR(ctx)) {
err = PTR_ERR(ctx);
goto err_free;
}
+ err = itrace_event_installable(event, ctx);
+ if (err)
+ goto err_free;
+
WARN_ON_ONCE(ctx->parent_ctx);
mutex_lock(&ctx->mutex);
perf_install_in_context(ctx, event, cpu);
@@ -7536,6 +7631,8 @@ void perf_event_delayed_put(struct task_struct *task)
WARN_ON_ONCE(task->perf_event_ctxp[ctxn]);
}
+int itrace_inherit_event(struct perf_event *event, struct task_struct *task);
+
/*
* inherit a event from parent task to child task:
*/
@@ -7549,6 +7646,7 @@ inherit_event(struct perf_event *parent_event,
{
struct perf_event *child_event;
unsigned long flags;
+ int err;
/*
* Instead of creating recursive hierarchies of events,
@@ -7567,10 +7665,12 @@ inherit_event(struct perf_event *parent_event,
if (IS_ERR(child_event))
return child_event;
- if (!atomic_long_inc_not_zero(&parent_event->refcount)) {
- free_event(child_event);
- return NULL;
- }
+ err = itrace_inherit_event(child_event, child);
+ if (err)
+ goto err_alloc;
+
+ if (!atomic_long_inc_not_zero(&parent_event->refcount))
+ goto err_alloc;
get_ctx(child_ctx);
@@ -7621,6 +7721,11 @@ inherit_event(struct perf_event *parent_event,
mutex_unlock(&parent_event->child_mutex);
return child_event;
+
+err_alloc:
+ free_event(child_event);
+
+ return NULL;
}
static int inherit_group(struct perf_event *parent_event,
diff --git a/kernel/events/internal.h b/kernel/events/internal.h
index 8835f00..f183efe 100644
--- a/kernel/events/internal.h
+++ b/kernel/events/internal.h
@@ -45,6 +45,7 @@ struct ring_buffer {
atomic_t mmap_count;
unsigned long mmap_locked;
struct user_struct *mmap_user;
+ void *priv;
struct perf_event_mmap_page *user_page;
void *data_pages[0];
@@ -55,6 +56,12 @@ extern struct ring_buffer *
rb_alloc(int nr_pages, long watermark, int cpu, int flags,
struct ring_buffer_ops *rb_ops);
extern void perf_event_wakeup(struct perf_event *event);
+extern struct ring_buffer *ring_buffer_get(struct perf_event *event, int rbx);
+extern void ring_buffer_put(struct ring_buffer *rb);
+extern void ring_buffer_attach(struct perf_event *event,
+ struct ring_buffer *rb);
+extern void ring_buffer_detach(struct perf_event *event,
+ struct ring_buffer *rb);
extern void
perf_event_header__init_id(struct perf_event_header *header,
diff --git a/kernel/events/itrace.c b/kernel/events/itrace.c
new file mode 100644
index 0000000..3adba62
--- /dev/null
+++ b/kernel/events/itrace.c
@@ -0,0 +1,589 @@
+/*
+ * Instruction flow trace unit infrastructure
+ * Copyright (c) 2013, 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+#include <linux/itrace.h>
+#include <linux/sizes.h>
+#include <linux/elf.h>
+#include <linux/coredump.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+#define CORE_OWNER "ITRACE"
+
+/*
+ * for the sake of simplicity, we assume that for now we can
+ * only have one type of an itrace pmu in a system
+ */
+static struct itrace_pmu *itrace_pmu;
+
+struct static_key_deferred itrace_core_events __read_mostly;
+
+struct itrace_lost_record {
+ struct perf_event_header header;
+ u64 offset;
+};
+
+/*
+ * In the worst case, perf buffer might be full and we're not able to output
+ * this record, so the decoder won't know that the data was lost. However,
+ * it will still see inconsistency in the trace IP.
+ */
+void itrace_lost_data(struct perf_event *event, u64 offset)
+{
+ struct perf_output_handle handle;
+ struct perf_sample_data sample;
+ struct itrace_lost_record rec = {
+ .header = {
+ .type = PERF_RECORD_ITRACE_LOST,
+ .misc = 0,
+ .size = sizeof(rec),
+ },
+ .offset = offset
+ };
+ int ret;
+
+ perf_event_header__init_id(&rec.header, &sample, event);
+ ret = perf_output_begin(&handle, event, rec.header.size);
+
+ if (ret)
+ return;
+
+ perf_output_put(&handle, rec);
+ perf_event__output_id_sample(event, &handle, &sample);
+ perf_output_end(&handle);
+}
+
+static struct itrace_pmu *itrace_pmu_find(int type)
+{
+ if (itrace_pmu && itrace_pmu->pmu.type == type)
+ return itrace_pmu;
+
+ return NULL;
+}
+
+bool is_itrace_event(struct perf_event *event)
+{
+ return !!itrace_pmu_find(event->attr.type);
+}
+
+static void itrace_event_destroy(struct perf_event *event)
+{
+ struct task_struct *task = event->hw.itrace_target;
+ struct ring_buffer *rb = event->rb[PERF_RB_ITRACE];
+
+ if (task && event->hw.counter_type == PERF_ITRACE_COREDUMP)
+ static_key_slow_dec_deferred(&itrace_core_events);
+
+ if (!rb)
+ return;
+
+ if (event->hw.counter_type != PERF_ITRACE_USER) {
+ atomic_dec(&rb->mmap_count);
+ atomic_dec(&event->mmap_count[PERF_RB_ITRACE]);
+ ring_buffer_detach(event, rb);
+ rcu_assign_pointer(event->rb[PERF_RB_ITRACE], NULL);
+ ring_buffer_put(rb); /* should be last */
+ }
+}
+
+int itrace_event_installable(struct perf_event *event,
+ struct perf_event_context *ctx)
+{
+ struct perf_event *iter_event;
+
+ if (!is_itrace_event(event))
+ return 0;
+
+ /*
+ * the context is locked and pinned and won't change under us,
+ * also we don't care if it's a cpu or task context at this point
+ */
+ list_for_each_entry(iter_event, &ctx->event_list, event_entry) {
+ if (is_itrace_event(iter_event) &&
+ (iter_event->cpu == event->cpu ||
+ iter_event->cpu == -1 ||
+ event->cpu == -1))
+ return -EEXIST;
+ }
+
+ return 0;
+}
+
+static int itrace_event_init(struct perf_event *event)
+{
+ struct itrace_pmu *ipmu = to_itrace_pmu(event->pmu);
+ int ret;
+
+ ret = ipmu->event_init(event);
+ if (ret)
+ return ret;
+
+ event->destroy = itrace_event_destroy;
+ event->hw.counter_type = PERF_ITRACE_USER;
+
+ return 0;
+}
+
+static unsigned long itrace_rb_get_size(int nr_pages)
+{
+ return sizeof(struct ring_buffer) + sizeof(void *) * nr_pages;
+}
+
+static int itrace_alloc_data_pages(struct ring_buffer *rb, int cpu,
+ int nr_pages, int flags)
+{
+ struct itrace_pmu *ipmu = itrace_pmu;
+ bool overwrite = !(flags & RING_BUFFER_WRITABLE);
+
+ rb->priv = ipmu->alloc_buffer(cpu, nr_pages, overwrite,
+ rb->data_pages, &rb->user_page);
+ if (!rb->priv)
+ return -ENOMEM;
+ rb->nr_pages = nr_pages;
+
+ return 0;
+}
+
+static void itrace_free(struct ring_buffer *rb)
+{
+ struct itrace_pmu *ipmu = itrace_pmu;
+
+ if (rb->priv)
+ ipmu->free_buffer(rb->priv);
+}
+
+struct page *
+itrace_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff)
+{
+ if (pgoff > rb->nr_pages)
+ return NULL;
+
+ if (pgoff == 0)
+ return virt_to_page(rb->user_page);
+
+ return virt_to_page(rb->data_pages[pgoff - 1]);
+}
+
+struct ring_buffer_ops itrace_rb_ops = {
+ .get_size = itrace_rb_get_size,
+ .alloc_data_page = itrace_alloc_data_pages,
+ .free_buffer = itrace_free,
+ .mmap_to_page = itrace_mmap_to_page,
+};
+
+void *itrace_priv(struct perf_event *event)
+{
+ if (!event->rb[PERF_RB_ITRACE])
+ return NULL;
+
+ return event->rb[PERF_RB_ITRACE]->priv;
+}
+
+void *itrace_event_get_priv(struct perf_event *event)
+{
+ struct ring_buffer *rb = ring_buffer_get(event, PERF_RB_ITRACE);
+
+ return rb ? rb->priv : NULL;
+}
+
+void itrace_event_put(struct perf_event *event)
+{
+ struct ring_buffer *rb;
+
+ rcu_read_lock();
+ rb = rcu_dereference(event->rb[PERF_RB_ITRACE]);
+ if (rb)
+ ring_buffer_put(rb);
+ rcu_read_unlock();
+}
+
+static void itrace_set_output(struct perf_event *event,
+ struct perf_event *output_event)
+{
+ struct ring_buffer *rb;
+
+ mutex_lock(&event->mmap_mutex);
+
+ if (atomic_read(&event->mmap_count[PERF_RB_ITRACE]) ||
+ event->rb[PERF_RB_ITRACE])
+ goto out;
+
+ rb = ring_buffer_get(output_event, PERF_RB_ITRACE);
+ if (!rb)
+ goto out;
+
+ ring_buffer_attach(event, rb);
+ rcu_assign_pointer(event->rb[PERF_RB_ITRACE], rb);
+
+out:
+ mutex_unlock(&event->mmap_mutex);
+}
+
+static size_t roundup_buffer_size(u64 size)
+{
+ return 1ul << (__get_order(size) + PAGE_SHIFT);
+}
+
+int itrace_inherit_event(struct perf_event *event, struct task_struct *task)
+{
+ size_t size = event->attr.itrace_sample_size;
+ struct perf_event *parent = event->parent;
+ struct ring_buffer *rb;
+ struct itrace_pmu *ipmu;
+
+ if (!is_itrace_event(event))
+ return 0;
+
+ ipmu = to_itrace_pmu(event->pmu);
+
+ if (parent->hw.counter_type == PERF_ITRACE_USER) {
+ /*
+ * inherited user's counters should inherit buffers IF
+ * they aren't cpu==-1
+ */
+ if (parent->cpu == -1)
+ return -EINVAL;
+
+ itrace_set_output(event, parent);
+ return 0;
+ }
+
+ event->hw.counter_type = parent->hw.counter_type;
+ if (event->hw.counter_type == PERF_ITRACE_COREDUMP) {
+ static_key_slow_inc(&itrace_core_events.key);
+ size = task_rlimit(task, RLIMIT_ITRACE);
+ }
+
+ size = roundup_buffer_size(size);
+ rb = rb_alloc(size >> PAGE_SHIFT, 0, event->cpu, 0, &itrace_rb_ops);
+ if (!rb)
+ return -ENOMEM;
+
+ ring_buffer_attach(event, rb);
+ rcu_assign_pointer(event->rb[PERF_RB_ITRACE], rb);
+ atomic_set(&rb->mmap_count, 1);
+ atomic_set(&event->mmap_count[PERF_RB_ITRACE], 1);
+
+ return 0;
+}
+
+int itrace_kernel_event(struct perf_event *event, struct task_struct *task)
+{
+ struct itrace_pmu *ipmu;
+ struct ring_buffer *rb;
+ size_t size;
+
+ if (!is_itrace_event(event))
+ return 0;
+
+ ipmu = to_itrace_pmu(event->pmu);
+
+ if (event->attr.itrace_sample_size)
+ size = roundup_buffer_size(event->attr.itrace_sample_size);
+ else
+ size = task_rlimit(task, RLIMIT_ITRACE);
+
+ rb = rb_alloc(size >> PAGE_SHIFT, 0, event->cpu, 0, &itrace_rb_ops);
+ if (!rb)
+ return -ENOMEM;
+
+ ring_buffer_attach(event, rb);
+ rcu_assign_pointer(event->rb[PERF_RB_ITRACE], rb);
+ atomic_set(&rb->mmap_count, 1);
+ atomic_set(&event->mmap_count[PERF_RB_ITRACE], 1);
+
+ return 0;
+}
+
+void itrace_wake_up(struct perf_event *event)
+{
+ struct ring_buffer *rb;
+
+ rcu_read_lock();
+ rb = rcu_dereference(event->rb[PERF_RB_ITRACE]);
+ if (rb) {
+ atomic_set(&rb->poll, POLL_IN);
+ irq_work_queue(&event->pending);
+ }
+ rcu_read_unlock();
+}
+
+int itrace_pmu_register(struct itrace_pmu *ipmu)
+{
+ int ret;
+
+ if (itrace_pmu)
+ return -EBUSY;
+
+ if (!ipmu->sample_trace ||
+ !ipmu->sample_output ||
+ !ipmu->core_size ||
+ !ipmu->core_output)
+ return -EINVAL;
+
+ ipmu->event_init = ipmu->pmu.event_init;
+ ipmu->pmu.event_init = itrace_event_init;
+
+ ret = perf_pmu_register(&ipmu->pmu, ipmu->name, -1);
+ if (!ret)
+ itrace_pmu = ipmu;
+
+ return ret;
+}
+
+/*
+ * Trace sample annotation
+ * For events that have attr.sample_type & PERF_SAMPLE_ITRACE, perf calls here
+ * to configure and obtain itrace samples.
+ */
+
+int itrace_sampler_init(struct perf_event *event, struct task_struct *task)
+{
+ struct perf_event_attr attr;
+ struct perf_event *tevt;
+ struct itrace_pmu *ipmu;
+
+ ipmu = itrace_pmu_find(event->attr.itrace_sample_type);
+ if (!ipmu)
+ return -ENOTSUPP;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.type = ipmu->pmu.type;
+ attr.config = 0;
+ attr.sample_type = 0;
+ attr.exclude_user = event->attr.exclude_user;
+ attr.exclude_kernel = event->attr.exclude_kernel;
+ attr.itrace_sample_size = event->attr.itrace_sample_size;
+ attr.itrace_config = event->attr.itrace_config;
+
+ tevt = perf_event_create_kernel_counter(&attr, event->cpu, task, NULL, NULL);
+ if (IS_ERR(tevt))
+ return PTR_ERR(tevt);
+
+ if (!itrace_priv(tevt)) {
+ perf_event_release_kernel(tevt);
+ return -EINVAL;
+ }
+
+ event->trace_event = tevt;
+ tevt->hw.counter_type = PERF_ITRACE_SAMPLING;
+ if (event->state != PERF_EVENT_STATE_OFF)
+ perf_event_enable(event->trace_event);
+
+ return 0;
+}
+
+void itrace_sampler_fini(struct perf_event *event)
+{
+ struct perf_event *tevt = event->trace_event;
+
+ perf_event_release_kernel(tevt);
+ event->trace_event = NULL;
+}
+
+unsigned long itrace_sampler_trace(struct perf_event *event,
+ struct perf_sample_data *data)
+{
+ struct perf_event *tevt = event->trace_event;
+ struct itrace_pmu *ipmu;
+
+ if (!tevt)
+ return 0;
+
+ ipmu = to_itrace_pmu(tevt->pmu);
+ return ipmu->sample_trace(tevt, data);
+}
+
+void itrace_sampler_output(struct perf_event *event,
+ struct perf_output_handle *handle,
+ struct perf_sample_data *data)
+{
+ struct perf_event *tevt = event->trace_event;
+ struct itrace_pmu *ipmu;
+
+ if (!tevt || !data->trace.size)
+ return;
+
+ ipmu = to_itrace_pmu(tevt->pmu);
+ ipmu->sample_output(tevt, handle, data);
+}
+
+/*
+ * Core dump bits
+ *
+ * Various parts of the kernel will call here:
+ * + do_prlimit(): to tell us that the user is trying to set RLIMIT_ITRACE
+ * + various places in bitfmt_elf.c: to write out itrace notes
+ * + do_exit(): to destroy the first core dump counter
+ * + the rest (copy_process()/do_exit()) is taken care of by perf for us
+ */
+
+static struct perf_event *
+itrace_find_task_event(struct task_struct *task, unsigned type)
+{
+ struct perf_event_context *ctx;
+ struct perf_event *event = NULL;
+
+ rcu_read_lock();
+ ctx = rcu_dereference(task->perf_event_ctxp[perf_hw_context]);
+ if (!ctx)
+ goto out;
+
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
+ if (is_itrace_event(event) &&
+ event->cpu == -1 &&
+ !!(event->hw.counter_type & type))
+ goto out;
+ }
+
+ event = NULL;
+out:
+ rcu_read_unlock();
+
+ return event;
+}
+
+int update_itrace_rlimit(struct task_struct *task, unsigned long rlim)
+{
+ struct itrace_pmu *ipmu = itrace_pmu;
+ struct perf_event_attr attr;
+ struct perf_event *event;
+
+ event = itrace_find_task_event(task, PERF_ITRACE_ANY);
+ if (event) {
+ if (event->hw.counter_type != PERF_ITRACE_COREDUMP)
+ return -EINVAL;
+
+ perf_event_release_kernel(event);
+ static_key_slow_dec_deferred(&itrace_core_events);
+ }
+
+ if (!rlim)
+ return 0;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.type = ipmu->pmu.type;
+ attr.config = 0;
+ attr.sample_type = 0;
+ attr.exclude_kernel = 1;
+ attr.inherit = 1;
+
+ event = perf_event_create_kernel_counter(&attr, -1, task, NULL, NULL);
+ if (IS_ERR(event))
+ return PTR_ERR(event);
+
+ static_key_slow_inc(&itrace_core_events.key);
+
+ event->hw.counter_type = PERF_ITRACE_COREDUMP;
+ perf_event_enable(event);
+
+ return 0;
+}
+
+static void itrace_pmu_exit_task(struct task_struct *task)
+{
+ struct perf_event *event;
+
+ event = itrace_find_task_event(task, PERF_ITRACE_COREDUMP);
+
+ /*
+ * here we are only interested in kernel counters created by
+ * update_itrace_rlimit(), inherited ones should be taken care of by
+ * perf_event_exit_task(), sampling ones are taken care of by
+ * itrace_sampler_fini().
+ */
+ if (!event)
+ return;
+
+ if (!event->parent)
+ perf_event_release_kernel(event);
+}
+
+void exit_itrace(struct task_struct *task)
+{
+ if (static_key_false(&itrace_core_events.key))
+ itrace_pmu_exit_task(task);
+}
+
+size_t itrace_elf_note_size(struct task_struct *task)
+{
+ struct itrace_pmu *ipmu;
+ struct perf_event *event = NULL;
+ size_t size = 0;
+
+ event = itrace_find_task_event(task, PERF_ITRACE_COREDUMP);
+ if (event) {
+ perf_event_disable(event);
+
+ ipmu = to_itrace_pmu(event->pmu);
+ size = ipmu->core_size(event);
+ size += task_rlimit(task, RLIMIT_ITRACE);
+ size = roundup(size + strlen(ipmu->name) + 1, 4);
+ size += sizeof(struct itrace_note) + sizeof(struct elf_note);
+ size += roundup(sizeof(CORE_OWNER), 4);
+ }
+
+ return size;
+}
+
+void itrace_elf_note_write(struct coredump_params *cprm,
+ struct task_struct *task)
+{
+ struct perf_event *event;
+ struct itrace_note note;
+ struct itrace_pmu *ipmu;
+ struct elf_note en;
+ unsigned long rlim;
+ size_t pmu_len;
+
+ event = itrace_find_task_event(task, PERF_ITRACE_COREDUMP);
+ if (!event)
+ return;
+
+ ipmu = to_itrace_pmu(event->pmu);
+ pmu_len = strlen(ipmu->name) + 1;
+
+ rlim = task_rlimit(task, RLIMIT_ITRACE);
+
+ /* Elf note with name */
+ en.n_namesz = strlen(CORE_OWNER);
+ en.n_descsz = roundup(ipmu->core_size(event) + rlim + sizeof(note) +
+ pmu_len, 4);
+ en.n_type = NT_ITRACE;
+ dump_emit(cprm, &en, sizeof(en));
+ dump_align(cprm, 4);
+ dump_emit(cprm, CORE_OWNER, sizeof(CORE_OWNER));
+ dump_align(cprm, 4);
+
+ /* ITRACE header */
+ note.itrace_config = event->attr.itrace_config;
+ dump_emit(cprm, ¬e, sizeof(note));
+ dump_emit(cprm, ipmu->name, pmu_len);
+
+ /* ITRACE PMU header + payload */
+ ipmu->core_output(cprm, event, rlim);
+ dump_align(cprm, 4);
+}
+
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index d7ec426..0bee352 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -119,7 +119,7 @@ int perf_output_begin(struct perf_output_handle *handle,
if (event->parent)
event = event->parent;
- rb = rcu_dereference(event->rb);
+ rb = rcu_dereference(event->rb[PERF_RB_MAIN]);
if (unlikely(!rb))
goto out;
diff --git a/kernel/exit.c b/kernel/exit.c
index a949819..28138ef 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -48,6 +48,7 @@
#include <linux/fs_struct.h>
#include <linux/init_task.h>
#include <linux/perf_event.h>
+#include <linux/itrace.h>
#include <trace/events/sched.h>
#include <linux/hw_breakpoint.h>
#include <linux/oom.h>
@@ -788,6 +789,8 @@ void do_exit(long code)
check_stack_usage();
exit_thread();
+ exit_itrace(tsk);
+
/*
* Flush inherited counters to the parent - before the parent
* gets woken up by child-exit notifications.
diff --git a/kernel/sys.c b/kernel/sys.c
index c723113..7651d6f 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -14,6 +14,7 @@
#include <linux/fs.h>
#include <linux/kmod.h>
#include <linux/perf_event.h>
+#include <linux/itrace.h>
#include <linux/resource.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
@@ -1402,6 +1403,10 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource,
update_rlimit_cpu(tsk, new_rlim->rlim_cur);
out:
read_unlock(&tasklist_lock);
+
+ if (!retval && new_rlim && resource == RLIMIT_ITRACE)
+ retval = update_itrace_rlimit(tsk, new_rlim->rlim_cur);
+
return retval;
}
--
1.8.5.1
next prev parent reply other threads:[~2013-12-11 12:57 UTC|newest]
Thread overview: 163+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-11 12:36 [PATCH v0 00/71] perf: Add support for Intel Processor Trace Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 01/71] perf: Disable all pmus on unthrottling and rescheduling Alexander Shishkin
2013-12-11 20:53 ` Andi Kleen
2013-12-13 18:06 ` Peter Zijlstra
2013-12-16 11:00 ` Alexander Shishkin
2013-12-16 11:07 ` Peter Zijlstra
2013-12-11 12:36 ` [PATCH v0 02/71] x86: Add Intel Processor Trace (INTEL_PT) cpu feature detection Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 03/71] perf: Abstract ring_buffer backing store operations Alexander Shishkin
2013-12-11 12:36 ` Alexander Shishkin [this message]
2013-12-17 16:11 ` [PATCH v0 04/71] itrace: Infrastructure for instruction flow tracing units Peter Zijlstra
2013-12-18 13:23 ` Alexander Shishkin
2013-12-18 13:34 ` Peter Zijlstra
2013-12-18 14:01 ` Alexander Shishkin
2013-12-18 14:11 ` Peter Zijlstra
2013-12-18 14:22 ` Alexander Shishkin
2013-12-18 15:09 ` Peter Zijlstra
2013-12-19 7:53 ` Alexander Shishkin
2013-12-19 10:26 ` Peter Zijlstra
2013-12-19 11:14 ` Alexander Shishkin
2013-12-19 11:25 ` Peter Zijlstra
2013-12-19 11:57 ` Alexander Shishkin
2013-12-19 10:31 ` Peter Zijlstra
2013-12-19 11:17 ` Alexander Shishkin
2013-12-19 11:28 ` Peter Zijlstra
2013-12-19 11:57 ` Peter Zijlstra
2013-12-19 12:52 ` Peter Zijlstra
2013-12-19 12:57 ` Peter Zijlstra
2013-12-19 14:54 ` Alexander Shishkin
2013-12-19 15:14 ` Peter Zijlstra
2013-12-19 11:58 ` Alexander Shishkin
2013-12-19 12:39 ` Ingo Molnar
2013-12-19 14:30 ` Alexander Shishkin
2013-12-19 14:49 ` Frederic Weisbecker
2013-12-19 15:02 ` Peter Zijlstra
2013-12-19 15:10 ` Peter Zijlstra
2014-01-06 21:25 ` Andi Kleen
2014-01-06 22:05 ` Peter Zijlstra
2014-01-07 0:52 ` Andi Kleen
2014-01-07 1:01 ` Andi Kleen
2014-01-07 8:42 ` Peter Zijlstra
2014-01-07 15:48 ` Andi Kleen
2014-01-08 11:53 ` Alexander Shishkin
2014-01-06 22:15 ` Peter Zijlstra
2014-01-06 23:10 ` Andi Kleen
2014-01-07 8:38 ` Peter Zijlstra
2014-01-07 15:42 ` Andi Kleen
2014-01-07 20:51 ` Peter Zijlstra
2014-01-07 23:34 ` Andi Kleen
[not found] ` <20140107212322.GE20765@two.firstfloor.org>
[not found] ` <20140108082840.GH2480@laptop.programming.kicks-ass.net>
2014-01-08 8:31 ` Peter Zijlstra
2014-01-07 8:41 ` Peter Zijlstra
2014-01-07 15:46 ` Andi Kleen
2013-12-11 12:36 ` [PATCH v0 05/71] x86: perf: Intel PT PMU driver Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 06/71] perf: Allow set-output for task contexts of different types Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 07/71] perf tools: Record whether a dso is 64-bit Alexander Shishkin
2013-12-11 19:26 ` David Ahern
2013-12-11 19:54 ` Arnaldo Carvalho de Melo
2013-12-12 12:07 ` Adrian Hunter
2013-12-12 12:05 ` Adrian Hunter
2013-12-12 16:45 ` David Ahern
2013-12-12 19:05 ` Arnaldo Carvalho de Melo
2013-12-12 19:16 ` David Ahern
2013-12-12 20:01 ` Arnaldo Carvalho de Melo
2013-12-16 3:16 ` David Ahern
2013-12-16 7:55 ` Adrian Hunter
2013-12-11 12:36 ` [PATCH v0 08/71] perf tools: Let a user specify a PMU event without any config terms Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 09/71] perf tools: Let default config be defined for a PMU Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 10/71] perf tools: Add perf_pmu__scan_file() Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 11/71] perf tools: Add perf_event_paranoid() Alexander Shishkin
2013-12-16 15:26 ` [tip:perf/core] " tip-bot for Adrian Hunter
2013-12-11 12:36 ` [PATCH v0 12/71] perf tools: Add dsos__hit_all() Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 13/71] perf tools: Add machine__get_thread_pid() Alexander Shishkin
2013-12-11 19:28 ` David Ahern
2013-12-11 21:18 ` Andi Kleen
2013-12-11 21:49 ` David Ahern
2013-12-12 13:56 ` Adrian Hunter
2013-12-11 12:36 ` [PATCH v0 14/71] perf tools: Add cpu to struct thread Alexander Shishkin
2013-12-11 14:19 ` Arnaldo Carvalho de Melo
2013-12-12 14:14 ` Adrian Hunter
2013-12-11 19:30 ` David Ahern
2013-12-11 19:55 ` Arnaldo Carvalho de Melo
2013-12-11 19:57 ` David Ahern
2013-12-11 12:36 ` [PATCH v0 15/71] perf tools: Add ability to record the current tid for each cpu Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 16/71] perf tools: Allow header->data_offset to be predetermined Alexander Shishkin
2013-12-16 15:26 ` [tip:perf/core] perf header: Allow header-> data_offset " tip-bot for Adrian Hunter
2013-12-11 12:36 ` [PATCH v0 17/71] perf tools: Add perf_evlist__can_select_event() Alexander Shishkin
2013-12-16 15:27 ` [tip:perf/core] perf evlist: Add can_select_event() method tip-bot for Adrian Hunter
2013-12-11 12:36 ` [PATCH v0 18/71] perf session: Flag if the event stream is entirely in memory Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 19/71] perf evlist: Pass mmap parameters in a struct Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 20/71] perf tools: Move mem_bswap32/64 to util.c Alexander Shishkin
2013-12-16 15:27 ` [tip:perf/core] " tip-bot for Adrian Hunter
2013-12-11 12:36 ` [PATCH v0 21/71] perf tools: Add feature test for __sync_val_compare_and_swap Alexander Shishkin
2013-12-11 19:24 ` Arnaldo Carvalho de Melo
2013-12-11 20:07 ` Andi Kleen
2013-12-12 13:45 ` Adrian Hunter
2013-12-12 13:42 ` Adrian Hunter
2013-12-11 12:36 ` [PATCH v0 22/71] perf tools: Add option macro OPT_CALLBACK_OPTARG Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 23/71] perf evlist: Add perf_evlist__to_front() Alexander Shishkin
2013-12-11 19:38 ` Arnaldo Carvalho de Melo
2013-12-12 14:09 ` Adrian Hunter
2013-12-16 15:27 ` [tip:perf/core] " tip-bot for Adrian Hunter
2013-12-11 12:36 ` [PATCH v0 24/71] perf evlist: Add perf_evlist__set_tracking_event() Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 25/71] perf evsel: Add 'no_aux_samples' option Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 26/71] perf evsel: Add 'immediate' option Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 27/71] perf evlist: Add 'system_wide' option Alexander Shishkin
2013-12-11 19:37 ` David Ahern
2013-12-12 12:22 ` Adrian Hunter
2013-12-11 12:36 ` [PATCH v0 28/71] perf tools: Add id index Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 29/71] perf pmu: Let pmu's with no events show up on perf list Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 30/71] perf session: Add ability to skip 4GiB or more Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 31/71] perf session: Add perf_session__deliver_synth_event() Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 32/71] perf tools: Allow TSC conversion on any arch Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 33/71] perf tools: Move rdtsc() function Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 34/71] perf evlist: Add perf_evlist__enable_event_idx() Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 35/71] perf tools: Add itrace members of struct perf_event_attr Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 36/71] perf tools: Add support for parsing pmu itrace_config Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 37/71] perf tools: Add support for PERF_RECORD_ITRACE_LOST Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 38/71] perf tools: Add itrace sample parsing Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 39/71] perf header: Add Instruction Tracing feature Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 40/71] perf evlist: Add ability to mmap itrace buffers Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 41/71] perf tools: Add user events for Instruction Tracing Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 42/71] perf tools: Add support for Instruction Trace recording Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 43/71] perf record: Add basic Instruction Tracing support Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 44/71] perf record: Extend -m option for Instruction Tracing mmap pages Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 45/71] perf tools: Add a user event for Instruction Tracing errors Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 46/71] perf session: Add Instruction Tracing hooks Alexander Shishkin
2013-12-11 12:36 ` [PATCH v0 47/71] perf session: Add Instruction Tracing options Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 48/71] perf session: Make perf_event__itrace_swap() non-static Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 49/71] perf itrace: Add helpers for Instruction Tracing errors Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 50/71] perf itrace: Add helpers for queuing Instruction Tracing data Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 51/71] perf itrace: Add a heap for sorting Instruction Tracing queues Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 52/71] perf itrace: Add processing for Instruction Tracing events Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 53/71] perf script: Add Instruction Tracing support Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 54/71] perf script: Always allow fields 'addr' and 'cpu' for itrace Alexander Shishkin
2013-12-11 19:41 ` David Ahern
2013-12-12 12:35 ` Adrian Hunter
2013-12-11 12:37 ` [PATCH v0 55/71] perf report: Add Instruction Tracing support Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 56/71] perf tools: Add Instruction Trace sampling support Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 57/71] perf record: " Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 58/71] perf tools: Add Instruction Tracing Snapshot Mode Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 59/71] perf record: Add Instruction Tracing Snapshot Mode support Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 60/71] perf inject: Re-pipe Instruction Tracing events Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 61/71] perf inject: Add Instruction Tracing support Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 62/71] perf inject: Cut Instruction Tracing samples Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 63/71] perf tools: Add Instruction Tracing index Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 64/71] perf tools: Hit all build ids when Instruction Tracing Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 65/71] perf itrace: Add Intel PT as an Instruction Tracing type Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 66/71] perf tools: Add Intel PT packet decoder Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 67/71] perf tools: Add Intel PT instruction decoder Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 68/71] perf tools: Add Intel PT log Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 69/71] perf tools: Add Intel PT decoder Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 70/71] perf tools: Add Intel PT support Alexander Shishkin
2013-12-11 12:37 ` [PATCH v0 71/71] perf tools: Take Intel PT into use Alexander Shishkin
2013-12-11 13:04 ` [PATCH v0 00/71] perf: Add support for Intel Processor Trace Ingo Molnar
2013-12-11 13:14 ` Alexander Shishkin
2013-12-11 13:47 ` Ingo Molnar
2013-12-16 11:08 ` Alexander Shishkin
2013-12-16 14:37 ` Ingo Molnar
2013-12-16 15:18 ` Andi Kleen
2013-12-16 15:30 ` Frederic Weisbecker
2013-12-16 15:45 ` Andi Kleen
2013-12-16 15:57 ` Frederic Weisbecker
2013-12-18 4:03 ` Namhyung Kim
2013-12-11 13:52 ` Arnaldo Carvalho de Melo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1386765443-26966-5-git-send-email-alexander.shishkin@linux.intel.com \
--to=alexander.shishkin@linux.intel.com \
--cc=a.p.zijlstra@chello.nl \
--cc=acme@ghostprotocols.net \
--cc=ak@linux.intel.com \
--cc=dsahern@gmail.com \
--cc=efault@gmx.de \
--cc=eranian@google.com \
--cc=fweisbec@gmail.com \
--cc=jolsa@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=namhyung@gmail.com \
--cc=paulus@samba.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®