* [RFC Patch 1/5] PERF-HW_BKPT: Allow per-cpu kernel-space Hardware Breakpoint requests
[not found] <20091029220551.166918079@linux.vnet.ibm.com>
@ 2009-10-29 22:21 ` K.Prasad
2009-10-29 22:21 ` [RFC Patch 2/5] PERF-HW_BKPT: Enable/disable the breakpoints when still registered K.Prasad
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: K.Prasad @ 2009-10-29 22:21 UTC (permalink / raw)
To: Ingo Molnar, Frederic Weisbecker, LKML
Cc: Steven Rostedt, Alan Stern, Andrew Morton, Paul Mackerras,
K.Prasad
[-- Attachment #1: per_cpu_breakpoint_01 --]
[-- Type: text/plain, Size: 8494 bytes --]
Allow kernel-space hw-breakpoints to be restricted only for a subset of
CPUs using a cpumask field in 'struct hw_breakpoint'.
Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com>
---
arch/x86/include/asm/hw_breakpoint.h | 1
arch/x86/kernel/hw_breakpoint.c | 12 +++
include/asm-generic/hw_breakpoint.h | 2
kernel/hw_breakpoint.c | 124 +++++++++++++++++++++++++----------
4 files changed, 104 insertions(+), 35 deletions(-)
Index: linux-2.6-tip.perf_hbkpt/arch/x86/kernel/hw_breakpoint.c
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/arch/x86/kernel/hw_breakpoint.c
+++ linux-2.6-tip.perf_hbkpt/arch/x86/kernel/hw_breakpoint.c
@@ -68,6 +68,12 @@ static unsigned long encode_dr7(int drnu
return bp_info;
}
+/* Disable breakpoints on the physical debug registers */
+void arch_disable_hw_breakpoint(void)
+{
+ set_debugreg(0UL, 7);
+}
+
void arch_update_kernel_hw_breakpoint(void *unused)
{
struct hw_breakpoint *bp;
@@ -78,7 +84,7 @@ void arch_update_kernel_hw_breakpoint(vo
set_debugreg(0UL, 7);
for (i = hbp_kernel_pos; i < HBP_NUM; i++) {
- per_cpu(this_hbp_kernel[i], cpu) = bp = hbp_kernel[i];
+ bp = per_cpu(this_hbp_kernel[i], cpu);
if (bp) {
temp_kdr7 |= encode_dr7(i, bp->info.len, bp->info.type);
set_debugreg(bp->info.address, i);
@@ -207,6 +213,10 @@ int arch_validate_hwbkpt_settings(struct
unsigned int align;
int ret = -EINVAL;
+ /* User-space breakpoints cannot be restricted to a subset of CPUs */
+ if (tsk && bp->cpumask)
+ return ret;
+
switch (bp->info.type) {
/*
* Ptrace-refactoring code
Index: linux-2.6-tip.perf_hbkpt/include/asm-generic/hw_breakpoint.h
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/include/asm-generic/hw_breakpoint.h
+++ linux-2.6-tip.perf_hbkpt/include/asm-generic/hw_breakpoint.h
@@ -8,6 +8,7 @@
#ifdef __KERNEL__
#include <linux/list.h>
#include <linux/types.h>
+#include <linux/cpumask.h>
#include <linux/kallsyms.h>
/**
@@ -102,6 +103,7 @@
*/
struct hw_breakpoint {
void (*triggered)(struct hw_breakpoint *, struct pt_regs *);
+ const cpumask_t *cpumask;
struct arch_hw_breakpoint info;
};
Index: linux-2.6-tip.perf_hbkpt/kernel/hw_breakpoint.c
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/kernel/hw_breakpoint.c
+++ linux-2.6-tip.perf_hbkpt/kernel/hw_breakpoint.c
@@ -47,14 +47,7 @@
*/
static DEFINE_SPINLOCK(hw_breakpoint_lock);
-/* Array of kernel-space breakpoint structures */
-struct hw_breakpoint *hbp_kernel[HBP_NUM];
-
-/*
- * Per-processor copy of hbp_kernel[]. Used only when hbp_kernel is being
- * modified but we need the older copy to handle any hbp exceptions. It will
- * sync with hbp_kernel[] value after updation is done through IPIs.
- */
+/* Per-cpu copy of HW-breakpoint structure */
DEFINE_PER_CPU(struct hw_breakpoint*, this_hbp_kernel[HBP_NUM]);
/*
@@ -72,6 +65,9 @@ unsigned int hbp_kernel_pos = HBP_NUM;
*/
unsigned int hbp_user_refcount[HBP_NUM];
+/* An array denoting the number of consumed HW Breakpoints on each CPU */
+static DEFINE_PER_CPU(int, hbp_consumed);
+
/*
* Load the debug registers during startup of a CPU.
*/
@@ -294,6 +290,23 @@ void unregister_user_hw_breakpoint(struc
}
EXPORT_SYMBOL_GPL(unregister_user_hw_breakpoint);
+/* Update per-cpu instances of HW Breakpoint structure */
+static void update_each_cpu_kernel_hbp(void *bp_param)
+{
+ int i, cpu = get_cpu();
+ struct hw_breakpoint *bp = (struct hw_breakpoint *)bp_param;
+
+ for (i = HBP_NUM-1; i >= hbp_kernel_pos; i--) {
+ if (per_cpu(this_hbp_kernel[i], cpu))
+ continue;
+ per_cpu(this_hbp_kernel[i], cpu) = bp;
+ per_cpu(hbp_consumed, cpu)++;
+ break;
+ }
+ arch_update_kernel_hw_breakpoint(NULL);
+ put_cpu();
+}
+
/**
* register_kernel_hw_breakpoint - register a hardware breakpoint for kernel space
* @bp: the breakpoint structure to register
@@ -305,27 +318,79 @@ EXPORT_SYMBOL_GPL(unregister_user_hw_bre
int register_kernel_hw_breakpoint(struct hw_breakpoint *bp)
{
int rc;
+ unsigned int cpu;
rc = arch_validate_hwbkpt_settings(bp, NULL);
if (rc)
return rc;
+ /* Default to ALL CPUs if cpumask is not specified */
+ if (!bp->cpumask)
+ bp->cpumask = cpu_possible_mask;
+
spin_lock_bh(&hw_breakpoint_lock);
- rc = -ENOSPC;
- /* Check if we are over-committing */
- if ((hbp_kernel_pos > 0) && (!hbp_user_refcount[hbp_kernel_pos-1])) {
- hbp_kernel_pos--;
- hbp_kernel[hbp_kernel_pos] = bp;
- on_each_cpu(arch_update_kernel_hw_breakpoint, NULL, 1);
- rc = 0;
+ rc = -EINVAL;
+ for_each_cpu(cpu, bp->cpumask) {
+ /*
+ * Check if we need a new slot of debug register in every CPU
+ * i.e. if 'hbp_kernel_pos' needs to be decremented or if the
+ * request can be serviced by consuming the vacant debug
+ * registers
+ */
+ if (per_cpu(hbp_consumed, cpu) == (HBP_NUM - hbp_kernel_pos)) {
+ /* Check if a new slot is available */
+ if ((hbp_kernel_pos == 0) ||
+ (hbp_user_refcount[hbp_kernel_pos - 1] != 0)) {
+ rc = -ENOSPC;
+ goto err_ret;
+ } else {
+ hbp_kernel_pos--;
+ break;
+ }
+ }
}
+ if (cpumask_test_cpu(smp_processor_id(), bp->cpumask))
+ update_each_cpu_kernel_hbp(bp);
+ smp_call_function_many(bp->cpumask, update_each_cpu_kernel_hbp, bp, 1);
+ rc = 0;
+
+err_ret:
spin_unlock_bh(&hw_breakpoint_lock);
return rc;
}
EXPORT_SYMBOL_GPL(register_kernel_hw_breakpoint);
+/* Removes breakpoint structure from the per-cpu breakpoint data-structure */
+static void remove_each_cpu_kernel_hbp(void *bp_param)
+{
+ int i, j, cpu = get_cpu();
+ struct hw_breakpoint *bp = (struct hw_breakpoint *)bp_param;
+
+ /*
+ * Disable breakpoints to avoid concurrent exceptions from accessing
+ * old or NULL breakpoint structures
+ */
+ arch_disable_hw_breakpoint();
+ for (i = HBP_NUM-1; i >= hbp_kernel_pos; i--) {
+ if (per_cpu(this_hbp_kernel[i], cpu) == bp) {
+ /*
+ * Shift the breakpoint structures by one-position
+ * above to compact them
+ */
+ for (j = i; j > hbp_kernel_pos; j--)
+ per_cpu(this_hbp_kernel[j], cpu) =
+ per_cpu(this_hbp_kernel[j-1], cpu);
+ per_cpu(this_hbp_kernel[hbp_kernel_pos], cpu) = NULL;
+ break;
+ }
+ }
+ per_cpu(hbp_consumed, cpu)--;
+ arch_update_kernel_hw_breakpoint(NULL);
+ put_cpu();
+}
+
/**
* unregister_kernel_hw_breakpoint - unregister a HW breakpoint for kernel space
* @bp: the breakpoint structure to unregister
@@ -334,32 +399,23 @@ EXPORT_SYMBOL_GPL(register_kernel_hw_bre
*/
void unregister_kernel_hw_breakpoint(struct hw_breakpoint *bp)
{
- int i, j;
+ int cpu;
spin_lock_bh(&hw_breakpoint_lock);
- /* Find the 'bp' in our list of breakpoints for kernel */
- for (i = hbp_kernel_pos; i < HBP_NUM; i++)
- if (bp == hbp_kernel[i])
- break;
+ if (cpumask_test_cpu(smp_processor_id(), bp->cpumask))
+ remove_each_cpu_kernel_hbp(bp);
+ smp_call_function_many(bp->cpumask, remove_each_cpu_kernel_hbp, bp, 1);
+ for_each_possible_cpu(cpu)
+ if (per_cpu(hbp_consumed, cpu) == (HBP_NUM - hbp_kernel_pos))
+ goto ret_path;
- /* Check if we did not find a match for 'bp'. If so return early */
- if (i == HBP_NUM) {
- spin_unlock_bh(&hw_breakpoint_lock);
- return;
- }
-
- /*
- * We'll shift the breakpoints one-level above to compact if
- * unregistration creates a hole
- */
- for (j = i; j > hbp_kernel_pos; j--)
- hbp_kernel[j] = hbp_kernel[j-1];
+ if (bp->cpumask == cpu_possible_mask)
+ bp->cpumask = NULL;
- hbp_kernel[hbp_kernel_pos] = NULL;
- on_each_cpu(arch_update_kernel_hw_breakpoint, NULL, 1);
hbp_kernel_pos++;
+ret_path:
spin_unlock_bh(&hw_breakpoint_lock);
}
EXPORT_SYMBOL_GPL(unregister_kernel_hw_breakpoint);
Index: linux-2.6-tip.perf_hbkpt/arch/x86/include/asm/hw_breakpoint.h
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/arch/x86/include/asm/hw_breakpoint.h
+++ linux-2.6-tip.perf_hbkpt/arch/x86/include/asm/hw_breakpoint.h
@@ -48,6 +48,7 @@ extern int arch_validate_hwbkpt_settings
extern void arch_update_user_hw_breakpoint(int pos, struct task_struct *tsk);
extern void arch_flush_thread_hw_breakpoint(struct task_struct *tsk);
extern void arch_update_kernel_hw_breakpoint(void *);
+extern void arch_disable_hw_breakpoint(void);
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data);
#endif /* __KERNEL__ */
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC Patch 2/5] PERF-HW_BKPT: Enable/disable the breakpoints when still registered
[not found] <20091029220551.166918079@linux.vnet.ibm.com>
2009-10-29 22:21 ` [RFC Patch 1/5] PERF-HW_BKPT: Allow per-cpu kernel-space Hardware Breakpoint requests K.Prasad
@ 2009-10-29 22:21 ` K.Prasad
2009-10-29 22:21 ` [RFC Patch 3/5] PERF-HW_BKPT: Fix traceback seen when resuming after suspend-to-ram K.Prasad
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: K.Prasad @ 2009-10-29 22:21 UTC (permalink / raw)
To: Ingo Molnar, Frederic Weisbecker, LKML
Cc: Steven Rostedt, Alan Stern, Andrew Morton, Paul Mackerras,
K.Prasad
[-- Attachment #1: enable_disable_patch_03 --]
[-- Type: text/plain, Size: 4841 bytes --]
Allow breakpoints to be enabled/disabled without yielding the
breakpoint request through new APIs -
<enable><disable>_hw_breakpoint()
Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com>
---
arch/x86/kernel/hw_breakpoint.c | 15 ++++++++++-----
include/asm-generic/hw_breakpoint.h | 14 ++++++++++++++
kernel/hw_breakpoint.c | 31 ++++++++++++++++++++++++++++++-
3 files changed, 54 insertions(+), 6 deletions(-)
Index: linux-2.6-tip.perf_hbkpt/arch/x86/kernel/hw_breakpoint.c
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/arch/x86/kernel/hw_breakpoint.c
+++ linux-2.6-tip.perf_hbkpt/arch/x86/kernel/hw_breakpoint.c
@@ -85,10 +85,11 @@ void arch_update_kernel_hw_breakpoint(vo
for (i = hbp_kernel_pos; i < HBP_NUM; i++) {
bp = per_cpu(this_hbp_kernel[i], cpu);
- if (bp) {
+ if (!bp)
+ continue;
+ set_debugreg(bp->info.address, i);
+ if (atomic_read(&bp->enabled) == BP_ENABLED)
temp_kdr7 |= encode_dr7(i, bp->info.len, bp->info.type);
- set_debugreg(bp->info.address, i);
- }
}
/* No need to set DR6. Update the debug registers with kernel-space
@@ -288,8 +289,9 @@ void arch_update_user_hw_breakpoint(int
thread->debugreg7 &= ~dr7_masks[pos];
if (bp) {
thread->debugreg[pos] = bp->info.address;
- thread->debugreg7 |= encode_dr7(pos, bp->info.len,
- bp->info.type);
+ if (atomic_read(&bp->enabled) == BP_ENABLED)
+ thread->debugreg7 |= encode_dr7(pos, bp->info.len,
+ bp->info.type);
} else
thread->debugreg[pos] = 0;
}
@@ -377,6 +379,9 @@ static int __kprobes hw_breakpoint_handl
*/
if (!bp)
continue;
+ /* Ignore exceptions due to disabled breakpoints */
+ if (atomic_read(&bp->enabled) == BP_DISABLED)
+ continue;
(bp->triggered)(bp, args->regs);
}
Index: linux-2.6-tip.perf_hbkpt/include/asm-generic/hw_breakpoint.h
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/include/asm-generic/hw_breakpoint.h
+++ linux-2.6-tip.perf_hbkpt/include/asm-generic/hw_breakpoint.h
@@ -101,7 +101,19 @@
*
* ----------------------------------------------------------------------
*/
+
+enum bp_status {
+ BP_DISABLED = 0,
+ BP_ENABLED = 1
+};
+
struct hw_breakpoint {
+ /*
+ * The 'enabled' flag denotes if a breakpoint hit would in-turn invoke
+ * the 'triggered' function. Not to be set directly by the end-user.
+ * Must be operated through <enable><disable>_hw_breakpoint() APIs only.
+ */
+ atomic_t enabled;
void (*triggered)(struct hw_breakpoint *, struct pt_regs *);
const cpumask_t *cpumask;
struct arch_hw_breakpoint info;
@@ -135,6 +147,8 @@ extern void unregister_user_hw_breakpoin
extern int register_kernel_hw_breakpoint(struct hw_breakpoint *bp);
extern void unregister_kernel_hw_breakpoint(struct hw_breakpoint *bp);
+extern void enable_hw_breakpoint(struct hw_breakpoint *bp);
+extern void disable_hw_breakpoint(struct hw_breakpoint *bp);
extern unsigned int hbp_kernel_pos;
#endif /* __KERNEL__ */
Index: linux-2.6-tip.perf_hbkpt/kernel/hw_breakpoint.c
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/kernel/hw_breakpoint.c
+++ linux-2.6-tip.perf_hbkpt/kernel/hw_breakpoint.c
@@ -229,8 +229,10 @@ int register_user_hw_breakpoint(struct t
break;
}
}
- if (!rc)
+ if (!rc) {
set_tsk_thread_flag(tsk, TIF_DEBUG);
+ atomic_set(&bp->enabled, BP_ENABLED);
+ }
spin_unlock_bh(&hw_breakpoint_lock);
return rc;
@@ -351,6 +353,7 @@ int register_kernel_hw_breakpoint(struct
}
}
+ atomic_set(&bp->enabled, BP_ENABLED);
if (cpumask_test_cpu(smp_processor_id(), bp->cpumask))
update_each_cpu_kernel_hbp(bp);
smp_call_function_many(bp->cpumask, update_each_cpu_kernel_hbp, bp, 1);
@@ -420,6 +423,32 @@ ret_path:
}
EXPORT_SYMBOL_GPL(unregister_kernel_hw_breakpoint);
+/**
+ * enable_hw_breakpoint - re-enable a breakpoint previously disabled
+ * @bp: pointer to the breakpoint structure to be enabled
+ *
+ * Re-enable or disable a breakpoint, previously disabled using
+ * disable_hw_breakpoint()
+ */
+void enable_hw_breakpoint(struct hw_breakpoint *bp)
+{
+ atomic_set(&bp->enabled, BP_ENABLED);
+}
+EXPORT_SYMBOL_GPL(enable_hw_breakpoint);
+
+/**
+ * disable_hw_breakpoint - disable a breakpoint from raising breakpoint exceptions
+ * @bp: pointer to the breakpoint structure to be disabled
+ *
+ * Disable a breakpoint without actually losing the registration. Re-enable it
+ * again using enable_hw_breakpoint()
+ */
+void disable_hw_breakpoint(struct hw_breakpoint *bp)
+{
+ atomic_set(&bp->enabled, BP_DISABLED);
+}
+EXPORT_SYMBOL_GPL(disable_hw_breakpoint);
+
static struct notifier_block hw_breakpoint_exceptions_nb = {
.notifier_call = hw_breakpoint_exceptions_notify,
/* we need to be notified first */
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC Patch 3/5] PERF-HW_BKPT: Fix traceback seen when resuming after suspend-to-ram
[not found] <20091029220551.166918079@linux.vnet.ibm.com>
2009-10-29 22:21 ` [RFC Patch 1/5] PERF-HW_BKPT: Allow per-cpu kernel-space Hardware Breakpoint requests K.Prasad
2009-10-29 22:21 ` [RFC Patch 2/5] PERF-HW_BKPT: Enable/disable the breakpoints when still registered K.Prasad
@ 2009-10-29 22:21 ` K.Prasad
2009-10-29 22:22 ` [RFC Patch 4/5] PERF-HW_HBKPT: Enable perf-events to use hw-breakpoints K.Prasad
2009-10-29 22:22 ` [RFC Patch 5/5] PERF-HW_HBKPT: Display kernel symbol-name along with perf output K.Prasad
4 siblings, 0 replies; 7+ messages in thread
From: K.Prasad @ 2009-10-29 22:21 UTC (permalink / raw)
To: Ingo Molnar, Frederic Weisbecker, LKML
Cc: Steven Rostedt, Alan Stern, Andrew Morton, Paul Mackerras,
K.Prasad
[-- Attachment #1: s2r_patch.txt --]
[-- Type: text/plain, Size: 2063 bytes --]
Load the debug registers (when a CPU turns online) through a tasklet. This
helps to keep routines (using protected hw-breakpoint data) to be invoked
only from non-interrupt context, thus making the spin_lock_bh() locking
sufficient.
Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com>
---
kernel/hw_breakpoint.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
Index: linux-2.6-tip.perf_hbkpt/kernel/hw_breakpoint.c
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/kernel/hw_breakpoint.c
+++ linux-2.6-tip.perf_hbkpt/kernel/hw_breakpoint.c
@@ -23,6 +23,7 @@
* This file contains the arch-independent routines.
*/
+#include <linux/interrupt.h>
#include <linux/irqflags.h>
#include <linux/kallsyms.h>
#include <linux/notifier.h>
@@ -69,20 +70,19 @@ unsigned int hbp_user_refcount[HBP_NUM];
static DEFINE_PER_CPU(int, hbp_consumed);
/*
- * Load the debug registers during startup of a CPU.
+ * A tasklet to populate the debug register's values from the
+ * breakpoint structure
*/
-void load_debug_registers(void)
+static struct tasklet_struct hbp_tasklet;
+
+/* Tasklet function that populates the debug registers */
+void hbp_tasklet_function(unsigned long unused)
{
- unsigned long flags;
struct task_struct *tsk = current;
spin_lock_bh(&hw_breakpoint_lock);
- /* Prevent IPIs for new kernel breakpoint updates */
- local_irq_save(flags);
arch_update_kernel_hw_breakpoint(NULL);
- local_irq_restore(flags);
-
if (test_tsk_thread_flag(tsk, TIF_DEBUG))
arch_install_thread_hw_breakpoint(tsk);
@@ -90,6 +90,18 @@ void load_debug_registers(void)
}
/*
+ * Load the debug registers during startup of a CPU.
+ */
+void load_debug_registers(void)
+{
+ unsigned long flags;
+
+ if (!hbp_tasklet.func)
+ tasklet_init(&hbp_tasklet, &hbp_tasklet_function, 0UL);
+ tasklet_schedule(&hbp_tasklet);
+}
+
+/*
* Erase all the hardware breakpoint info associated with a thread.
*
* If tsk != current then tsk must not be usable (for example, a
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC Patch 4/5] PERF-HW_HBKPT: Enable perf-events to use hw-breakpoints
[not found] <20091029220551.166918079@linux.vnet.ibm.com>
` (2 preceding siblings ...)
2009-10-29 22:21 ` [RFC Patch 3/5] PERF-HW_BKPT: Fix traceback seen when resuming after suspend-to-ram K.Prasad
@ 2009-10-29 22:22 ` K.Prasad
2009-11-22 2:52 ` Frederic Weisbecker
2009-10-29 22:22 ` [RFC Patch 5/5] PERF-HW_HBKPT: Display kernel symbol-name along with perf output K.Prasad
4 siblings, 1 reply; 7+ messages in thread
From: K.Prasad @ 2009-10-29 22:22 UTC (permalink / raw)
To: Ingo Molnar, Frederic Weisbecker, LKML
Cc: Steven Rostedt, Alan Stern, Andrew Morton, Paul Mackerras,
K.Prasad
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: perf_hbkpt_integration_04 --]
[-- Type: text/plain; charset=utf-8, Size: 8520 bytes --]
Enable perf-events to collect memory access statistics on kernel-space
data in the context of a running process.
Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com>
---
include/linux/perf_event.h | 18 ++++++
kernel/perf_event.c | 108 ++++++++++++++++++++++++++++++++++++++++-
tools/perf/util/parse-events.c | 47 +++++++++++++++++
3 files changed, 172 insertions(+), 1 deletion(-)
Index: linux-2.6-tip.perf_hbkpt/include/linux/perf_event.h
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/include/linux/perf_event.h
+++ linux-2.6-tip.perf_hbkpt/include/linux/perf_event.h
@@ -31,6 +31,7 @@ enum perf_type_id {
PERF_TYPE_TRACEPOINT = 2,
PERF_TYPE_HW_CACHE = 3,
PERF_TYPE_RAW = 4,
+ PERF_TYPE_BREAKPOINT = 5,
PERF_TYPE_MAX, /* non-ABI */
};
@@ -106,6 +107,14 @@ enum perf_sw_ids {
PERF_COUNT_SW_MAX, /* non-ABI */
};
+/* Various breakpoint types for monitoring accesses over variables */
+enum perf_bp_id {
+ PERF_COUNT_BP_WRITE = 0,
+ PERF_COUNT_BP_RW = 1,
+
+ PERF_COUNT_BP_MAX, /* non-ABI */
+};
+
/*
* Bits that can be set in attr.sample_type to request information
* in the overflow packets.
@@ -207,6 +216,11 @@ struct perf_event_attr {
__u32 wakeup_events; /* wakeup every n events */
__u32 wakeup_watermark; /* bytes before wakeup */
};
+
+ /* Store the symbol name for breakpoint request */
+ /* TODO: ksym_name[KSYM_NAME_LEN] requires kallsyms.h to be included */
+ char ksym_name[128];
+
__u32 __reserved_2;
__u64 __reserved_3;
@@ -476,6 +490,10 @@ struct hw_perf_event {
s64 remaining;
struct hrtimer hrtimer;
};
+ struct { /* hardware breakpoints */
+ struct hw_breakpoint *bp;
+ int counter;
+ };
};
atomic64_t prev_count;
u64 sample_period;
Index: linux-2.6-tip.perf_hbkpt/kernel/perf_event.c
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/kernel/perf_event.c
+++ linux-2.6-tip.perf_hbkpt/kernel/perf_event.c
@@ -4,7 +4,7 @@
* Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
* Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
* Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
- * Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ * Copyright � 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
*
* For licensing details see kernel-base/COPYING
*/
@@ -31,6 +31,7 @@
#include <linux/ftrace_event.h>
#include <asm/irq_regs.h>
+#include <asm/hw_breakpoint.h>
/*
* Each CPU has a list of per CPU events:
@@ -4124,6 +4125,27 @@ static const struct pmu perf_ops_task_cl
.read = task_clock_perf_event_read,
};
+static int hw_breakpoint_perf_event_enable(struct perf_event *event)
+{
+ enable_hw_breakpoint(event->hw.bp);
+ return 0;
+}
+
+static void hw_breakpoint_perf_event_disable(struct perf_event *event)
+{
+ disable_hw_breakpoint(event->hw.bp);
+}
+
+static void hw_breakpoint_perf_event_read(struct perf_event *event)
+{
+}
+
+static const struct pmu perf_ops_hw_breakpoint = {
+ .enable = hw_breakpoint_perf_event_enable,
+ .disable = hw_breakpoint_perf_event_disable,
+ .read = hw_breakpoint_perf_event_read,
+};
+
#ifdef CONFIG_EVENT_PROFILE
void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
@@ -4285,6 +4307,86 @@ static const struct pmu *sw_perf_event_i
return pmu;
}
+static void perf_hw_breakpoint_handler(struct hw_breakpoint *bp,
+ struct pt_regs *regs)
+{
+ int event_id = 0;
+ struct perf_sample_data data = {
+ .addr = bp->info.address,
+ };
+
+ switch (bp->info.type) {
+ case HW_BREAKPOINT_WRITE:
+ event_id = PERF_COUNT_BP_WRITE;
+ break;
+
+ case HW_BREAKPOINT_RW:
+ event_id = PERF_COUNT_BP_RW;
+ break;
+
+ default:
+ return;
+ }
+
+ do_perf_sw_event(PERF_TYPE_BREAKPOINT, event_id, 1, 1,
+ &data, regs);
+}
+
+static void hw_breakpoint_perf_event_destroy(struct perf_event *event)
+{
+ struct hw_breakpoint *bp = event->hw.bp;
+
+ unregister_kernel_hw_breakpoint(bp);
+ kfree(bp);
+}
+
+static const struct pmu *hw_breakpoint_perf_event_init(struct perf_event *event,
+ int cpu, gfp_t gfpflags)
+{
+ int ret;
+ struct perf_event_attr *attr = &event->attr;
+ u64 event_id = attr->config;
+ struct hw_breakpoint *bp;
+
+ bp = event->hw.bp = kzalloc(sizeof(struct hw_breakpoint), gfpflags);
+ if (!bp)
+ return ERR_PTR(-ENOMEM);
+
+ switch (event_id) {
+
+ case PERF_COUNT_BP_WRITE:
+ bp->info.type = HW_BREAKPOINT_WRITE;
+ break;
+ case PERF_COUNT_BP_RW:
+ bp->info.type = HW_BREAKPOINT_RW;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ /*
+ * Ideally we should determine the size of the kernel-symbol and request
+ * for corresponding breakpoint length. But since the lengths are encoded,
+ * we will request for a 1-Byte length breakpoint to be placed at the start.
+ */
+ bp->info.len = HW_BREAKPOINT_LEN_1;
+ bp->triggered = perf_hw_breakpoint_handler;
+
+ if (attr->ksym_name)
+ bp->info.name = attr->ksym_name;
+ else
+ return ERR_PTR(-EINVAL);
+
+ if (cpu != -1)
+ bp->cpumask = cpumask_of(cpu);
+
+ ret = register_kernel_hw_breakpoint(bp);
+ if (ret)
+ return ERR_PTR(ret);
+
+ event->destroy = hw_breakpoint_perf_event_destroy;
+ return &perf_ops_hw_breakpoint;
+}
+
/*
* Allocate and initialize a event structure
*/
@@ -4370,6 +4472,10 @@ perf_event_alloc(struct perf_event_attr
pmu = tp_perf_event_init(event);
break;
+ case PERF_TYPE_BREAKPOINT:
+ pmu = hw_breakpoint_perf_event_init(event, cpu, gfpflags);
+ break;
+
default:
break;
}
Index: linux-2.6-tip.perf_hbkpt/tools/perf/util/parse-events.c
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/tools/perf/util/parse-events.c
+++ linux-2.6-tip.perf_hbkpt/tools/perf/util/parse-events.c
@@ -30,6 +30,7 @@ char debugfs_path[MAXPATHLEN];
#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
+#define CHBP(x) .type = PERF_TYPE_BREAKPOINT, .config = PERF_COUNT_BP_##x
static struct event_symbol event_symbols[] = {
{ CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
@@ -47,6 +48,13 @@ static struct event_symbol event_symbols
{ CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
{ CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
{ CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
+
+ /*
+ * Allow the hw-breakpoint events to be the last two elements for a small
+ * optimisation used in parse_hbp_event().
+ */
+ { CHBP(WRITE), "memory-write", "w" },
+ { CHBP(RW), "memory-readwrite", "rw" },
};
#define __PERF_EVENT_FIELD(config, name) \
@@ -77,6 +85,11 @@ static const char *sw_event_names[] = {
"major-faults",
};
+static const char *hbp_event_names[] = {
+ "memory-write",
+ "memory-readwrite",
+};
+
#define MAX_ALIASES 8
static const char *hw_cache[][MAX_ALIASES] = {
@@ -322,6 +335,9 @@ const char *__event_name(int type, u64 c
case PERF_TYPE_TRACEPOINT:
return tracepoint_id_to_name(config);
+ case PERF_TYPE_BREAKPOINT:
+ return hbp_event_names[config];
+
default:
break;
}
@@ -621,6 +637,32 @@ parse_numeric_event(const char **strp, s
}
static enum event_result
+parse_hbp_event(const char **strp, struct perf_event_attr *attr)
+{
+ unsigned int i, j, n;
+
+ char *bp_data = (char *)(*strp);
+ char *bp_event_name = strsep(&bp_data, ":");
+
+ /* bp_data will turn NULL if ":" was not present in the event string */
+ if (!bp_data)
+ return EVT_FAILED;
+
+ for (i = (ARRAY_SIZE(event_symbols) - PERF_COUNT_BP_MAX), j = 0;
+ i < ARRAY_SIZE(event_symbols); i++, j++) {
+ n = check_events(bp_event_name, i);
+ if (!n)
+ continue;
+ attr->config = j;
+ attr->type = PERF_TYPE_BREAKPOINT;
+ strcpy(attr->ksym_name, bp_data);
+ *strp = (*strp) + strlen(*strp) + strlen(bp_data) + 1;
+ return EVT_HANDLED;
+ }
+ return EVT_FAILED;
+}
+
+static enum event_result
parse_event_modifier(const char **strp, struct perf_event_attr *attr)
{
const char *str = *strp;
@@ -658,6 +700,10 @@ parse_event_symbols(const char **str, st
{
enum event_result ret;
+ ret = parse_hbp_event(str, attr);
+ if (ret != EVT_FAILED)
+ goto modifier;
+
ret = parse_tracepoint_event(str, attr);
if (ret != EVT_FAILED)
goto modifier;
@@ -773,6 +819,7 @@ static const char * const event_type_des
"Software event",
"Tracepoint event",
"Hardware cache event",
+ "Memory access event",
};
/*
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC Patch 5/5] PERF-HW_HBKPT: Display kernel symbol-name along with perf output
[not found] <20091029220551.166918079@linux.vnet.ibm.com>
` (3 preceding siblings ...)
2009-10-29 22:22 ` [RFC Patch 4/5] PERF-HW_HBKPT: Enable perf-events to use hw-breakpoints K.Prasad
@ 2009-10-29 22:22 ` K.Prasad
4 siblings, 0 replies; 7+ messages in thread
From: K.Prasad @ 2009-10-29 22:22 UTC (permalink / raw)
To: Ingo Molnar, Frederic Weisbecker, LKML
Cc: Steven Rostedt, Alan Stern, Andrew Morton, Paul Mackerras,
K.Prasad
[-- Attachment #1: perf_hbkpt_ksymname_05 --]
[-- Type: text/plain, Size: 3178 bytes --]
Enable the kernel symbol to be shown when perf statistics are reported. This
enables the user to quickly recognise the hit counter with the symbol to which
it corresponds to.
Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com>
---
tools/perf/builtin-report.c | 4 ++--
tools/perf/util/parse-events.c | 18 +++++++++++-------
tools/perf/util/parse-events.h | 2 +-
3 files changed, 14 insertions(+), 10 deletions(-)
Index: linux-2.6-tip.perf_hbkpt/tools/perf/util/parse-events.c
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/tools/perf/util/parse-events.c
+++ linux-2.6-tip.perf_hbkpt/tools/perf/util/parse-events.c
@@ -285,15 +285,14 @@ static char *event_cache_name(u8 cache_t
const char *event_name(int counter)
{
- u64 config = attrs[counter].config;
- int type = attrs[counter].type;
-
- return __event_name(type, config);
+ return __event_name(&attrs[counter]);
}
-const char *__event_name(int type, u64 config)
+const char *__event_name(const struct perf_event_attr *attr)
{
- static char buf[32];
+ int type = attr->type;
+ u64 config = attr->config;
+ static char buf[256];
if (type == PERF_TYPE_RAW) {
sprintf(buf, "raw 0x%llx", config);
@@ -336,7 +335,12 @@ const char *__event_name(int type, u64 c
return tracepoint_id_to_name(config);
case PERF_TYPE_BREAKPOINT:
- return hbp_event_names[config];
+ /*
+ * Separate the breakpoint event from the kernel symbol
+ * using a ":" symbol
+ */
+ sprintf(buf, "%s:%s", hbp_event_names[config], attr->ksym_name);
+ return buf;
default:
break;
Index: linux-2.6-tip.perf_hbkpt/tools/perf/util/parse-events.h
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/tools/perf/util/parse-events.h
+++ linux-2.6-tip.perf_hbkpt/tools/perf/util/parse-events.h
@@ -20,7 +20,7 @@ extern struct perf_event_attr attrs[MAX_
extern char *filters[MAX_COUNTERS];
extern const char *event_name(int ctr);
-extern const char *__event_name(int type, u64 config);
+extern const char *__event_name(const struct perf_event_attr *attr);
extern int parse_events(const struct option *opt, const char *str, int unset);
extern int parse_filter(const struct option *opt, const char *str, int unset);
Index: linux-2.6-tip.perf_hbkpt/tools/perf/builtin-report.c
===================================================================
--- linux-2.6-tip.perf_hbkpt.orig/tools/perf/builtin-report.c
+++ linux-2.6-tip.perf_hbkpt/tools/perf/builtin-report.c
@@ -849,7 +849,7 @@ process_read_event(event_t *event, unsig
attr = perf_header__find_attr(event->read.id, header);
if (show_threads) {
- const char *name = attr ? __event_name(attr->type, attr->config)
+ const char *name = attr ? __event_name(attr)
: "unknown";
perf_read_values_add_value(&show_threads_values,
event->read.pid, event->read.tid,
@@ -863,7 +863,7 @@ process_read_event(event_t *event, unsig
(void *)(long)(event->header.size),
event->read.pid,
event->read.tid,
- attr ? __event_name(attr->type, attr->config)
+ attr ? __event_name(attr)
: "FAIL",
event->read.value);
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC Patch 4/5] PERF-HW_HBKPT: Enable perf-events to use hw-breakpoints
2009-10-29 22:22 ` [RFC Patch 4/5] PERF-HW_HBKPT: Enable perf-events to use hw-breakpoints K.Prasad
@ 2009-11-22 2:52 ` Frederic Weisbecker
2009-11-22 4:08 ` Frederic Weisbecker
0 siblings, 1 reply; 7+ messages in thread
From: Frederic Weisbecker @ 2009-11-22 2:52 UTC (permalink / raw)
To: K.Prasad
Cc: Ingo Molnar, LKML, Steven Rostedt, Alan Stern, Andrew Morton,
Paul Mackerras
On Fri, Oct 30, 2009 at 03:52:23AM +0530, K.Prasad wrote:
> Enable perf-events to collect memory access statistics on kernel-space
> data in the context of a running process.
>
> Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com>
I'm going to take the userspace part of this patch to integrate breakpoints
in perf tools.
But I'm not sure passing the name of the symbol to the kernel and store
it in the perf attr is a good idea.
We should probably resolve the name from userspace and pass the address
to the kernel. Mostly because if we want to support breakpoints in
userspace apps, we don't want conflicts between kernel and userspace
symbols.
Thanks.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC Patch 4/5] PERF-HW_HBKPT: Enable perf-events to use hw-breakpoints
2009-11-22 2:52 ` Frederic Weisbecker
@ 2009-11-22 4:08 ` Frederic Weisbecker
0 siblings, 0 replies; 7+ messages in thread
From: Frederic Weisbecker @ 2009-11-22 4:08 UTC (permalink / raw)
To: K.Prasad
Cc: Ingo Molnar, LKML, Steven Rostedt, Alan Stern, Andrew Morton,
Paul Mackerras
On Sun, Nov 22, 2009 at 03:52:00AM +0100, Frederic Weisbecker wrote:
> On Fri, Oct 30, 2009 at 03:52:23AM +0530, K.Prasad wrote:
> > Enable perf-events to collect memory access statistics on kernel-space
> > data in the context of a running process.
> >
> > Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com>
>
>
>
> I'm going to take the userspace part of this patch to integrate breakpoints
> in perf tools.
>
> But I'm not sure passing the name of the symbol to the kernel and store
> it in the perf attr is a good idea.
> We should probably resolve the name from userspace and pass the address
> to the kernel. Mostly because if we want to support breakpoints in
> userspace apps, we don't want conflicts between kernel and userspace
> symbols.
>
> Thanks.
>
Hmm, actually instead of memory-write/memory-readwrite
I would rather see:
mem:symbol:[r][w][x]
like mem:pid_max:rw
We could default it to rw for now.
This will be more flexible I guess.
And later for ranges:
mem:symbol[[start]:[len]:[rwx]
This could be:
mem:array_name[0:5]:rwx
So, I'll need an ad-hoc parsing function for this one. This
would be hard by integrating your patch.
I'll try something else. But I can probably take the 5th patch
of your series.
Thanks.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2009-11-22 4:08 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20091029220551.166918079@linux.vnet.ibm.com>
2009-10-29 22:21 ` [RFC Patch 1/5] PERF-HW_BKPT: Allow per-cpu kernel-space Hardware Breakpoint requests K.Prasad
2009-10-29 22:21 ` [RFC Patch 2/5] PERF-HW_BKPT: Enable/disable the breakpoints when still registered K.Prasad
2009-10-29 22:21 ` [RFC Patch 3/5] PERF-HW_BKPT: Fix traceback seen when resuming after suspend-to-ram K.Prasad
2009-10-29 22:22 ` [RFC Patch 4/5] PERF-HW_HBKPT: Enable perf-events to use hw-breakpoints K.Prasad
2009-11-22 2:52 ` Frederic Weisbecker
2009-11-22 4:08 ` Frederic Weisbecker
2009-10-29 22:22 ` [RFC Patch 5/5] PERF-HW_HBKPT: Display kernel symbol-name along with perf output K.Prasad
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox