Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: perf: Always build the powerpc perf_arch_fetch_caller_regs version perf: Always build the stub perf_arch_fetch_caller_regs version perf, probe-finder: Build fix on Debian perf/scripts: Tuple was set from long in both branches in python_process_event() perf: Fix 'perf sched record' deadlock perf, x86: Fix callgraphs of 32-bit processes on 64-bit kernels perf, x86: Fix AMD hotplug & constraint initialization x86: Move notify_cpu_starting() callback to a later stage x86,kgdb: Always initialize the hw breakpoint attribute perf: Use hot regs with software sched switch/migrate events perf: Correctly align perf event tracing buffer
This commit is contained in:
commit
8ce42c8b7f
@ -128,7 +128,6 @@ _GLOBAL(__restore_cpu_power7)
|
|||||||
/* place holder */
|
/* place holder */
|
||||||
blr
|
blr
|
||||||
|
|
||||||
#ifdef CONFIG_EVENT_TRACING
|
|
||||||
/*
|
/*
|
||||||
* Get a minimal set of registers for our caller's nth caller.
|
* Get a minimal set of registers for our caller's nth caller.
|
||||||
* r3 = regs pointer, r5 = n.
|
* r3 = regs pointer, r5 = n.
|
||||||
@ -154,4 +153,3 @@ _GLOBAL(perf_arch_fetch_caller_regs)
|
|||||||
PPC_STL r4,_NIP-STACK_FRAME_OVERHEAD(r3)
|
PPC_STL r4,_NIP-STACK_FRAME_OVERHEAD(r3)
|
||||||
PPC_STL r7,_LINK-STACK_FRAME_OVERHEAD(r3)
|
PPC_STL r7,_LINK-STACK_FRAME_OVERHEAD(r3)
|
||||||
blr
|
blr
|
||||||
#endif /* CONFIG_EVENT_TRACING */
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <asm/apic.h>
|
#include <asm/apic.h>
|
||||||
#include <asm/stacktrace.h>
|
#include <asm/stacktrace.h>
|
||||||
#include <asm/nmi.h>
|
#include <asm/nmi.h>
|
||||||
|
#include <asm/compat.h>
|
||||||
|
|
||||||
static u64 perf_event_mask __read_mostly;
|
static u64 perf_event_mask __read_mostly;
|
||||||
|
|
||||||
@ -158,7 +159,7 @@ struct x86_pmu {
|
|||||||
struct perf_event *event);
|
struct perf_event *event);
|
||||||
struct event_constraint *event_constraints;
|
struct event_constraint *event_constraints;
|
||||||
|
|
||||||
void (*cpu_prepare)(int cpu);
|
int (*cpu_prepare)(int cpu);
|
||||||
void (*cpu_starting)(int cpu);
|
void (*cpu_starting)(int cpu);
|
||||||
void (*cpu_dying)(int cpu);
|
void (*cpu_dying)(int cpu);
|
||||||
void (*cpu_dead)(int cpu);
|
void (*cpu_dead)(int cpu);
|
||||||
@ -1333,11 +1334,12 @@ static int __cpuinit
|
|||||||
x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
|
x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
|
||||||
{
|
{
|
||||||
unsigned int cpu = (long)hcpu;
|
unsigned int cpu = (long)hcpu;
|
||||||
|
int ret = NOTIFY_OK;
|
||||||
|
|
||||||
switch (action & ~CPU_TASKS_FROZEN) {
|
switch (action & ~CPU_TASKS_FROZEN) {
|
||||||
case CPU_UP_PREPARE:
|
case CPU_UP_PREPARE:
|
||||||
if (x86_pmu.cpu_prepare)
|
if (x86_pmu.cpu_prepare)
|
||||||
x86_pmu.cpu_prepare(cpu);
|
ret = x86_pmu.cpu_prepare(cpu);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPU_STARTING:
|
case CPU_STARTING:
|
||||||
@ -1350,6 +1352,7 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
|
|||||||
x86_pmu.cpu_dying(cpu);
|
x86_pmu.cpu_dying(cpu);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CPU_UP_CANCELED:
|
||||||
case CPU_DEAD:
|
case CPU_DEAD:
|
||||||
if (x86_pmu.cpu_dead)
|
if (x86_pmu.cpu_dead)
|
||||||
x86_pmu.cpu_dead(cpu);
|
x86_pmu.cpu_dead(cpu);
|
||||||
@ -1359,7 +1362,7 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NOTIFY_OK;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init pmu_check_apic(void)
|
static void __init pmu_check_apic(void)
|
||||||
@ -1628,14 +1631,42 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
|
#ifdef CONFIG_COMPAT
|
||||||
|
static inline int
|
||||||
|
perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
|
||||||
{
|
{
|
||||||
unsigned long bytes;
|
/* 32-bit process in 64-bit kernel. */
|
||||||
|
struct stack_frame_ia32 frame;
|
||||||
|
const void __user *fp;
|
||||||
|
|
||||||
bytes = copy_from_user_nmi(frame, fp, sizeof(*frame));
|
if (!test_thread_flag(TIF_IA32))
|
||||||
|
return 0;
|
||||||
|
|
||||||
return bytes == sizeof(*frame);
|
fp = compat_ptr(regs->bp);
|
||||||
|
while (entry->nr < PERF_MAX_STACK_DEPTH) {
|
||||||
|
unsigned long bytes;
|
||||||
|
frame.next_frame = 0;
|
||||||
|
frame.return_address = 0;
|
||||||
|
|
||||||
|
bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
|
||||||
|
if (bytes != sizeof(frame))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (fp < compat_ptr(regs->sp))
|
||||||
|
break;
|
||||||
|
|
||||||
|
callchain_store(entry, frame.return_address);
|
||||||
|
fp = compat_ptr(frame.next_frame);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static inline int
|
||||||
|
perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry)
|
perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry)
|
||||||
@ -1651,11 +1682,16 @@ perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry)
|
|||||||
callchain_store(entry, PERF_CONTEXT_USER);
|
callchain_store(entry, PERF_CONTEXT_USER);
|
||||||
callchain_store(entry, regs->ip);
|
callchain_store(entry, regs->ip);
|
||||||
|
|
||||||
|
if (perf_callchain_user32(regs, entry))
|
||||||
|
return;
|
||||||
|
|
||||||
while (entry->nr < PERF_MAX_STACK_DEPTH) {
|
while (entry->nr < PERF_MAX_STACK_DEPTH) {
|
||||||
|
unsigned long bytes;
|
||||||
frame.next_frame = NULL;
|
frame.next_frame = NULL;
|
||||||
frame.return_address = 0;
|
frame.return_address = 0;
|
||||||
|
|
||||||
if (!copy_stack_frame(fp, &frame))
|
bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
|
||||||
|
if (bytes != sizeof(frame))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ((unsigned long)fp < regs->sp)
|
if ((unsigned long)fp < regs->sp)
|
||||||
@ -1702,7 +1738,6 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_EVENT_TRACING
|
|
||||||
void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
|
void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
|
||||||
{
|
{
|
||||||
regs->ip = ip;
|
regs->ip = ip;
|
||||||
@ -1714,4 +1749,3 @@ void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int ski
|
|||||||
regs->cs = __KERNEL_CS;
|
regs->cs = __KERNEL_CS;
|
||||||
local_save_flags(regs->flags);
|
local_save_flags(regs->flags);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
@ -137,6 +137,13 @@ static inline int amd_is_nb_event(struct hw_perf_event *hwc)
|
|||||||
return (hwc->config & 0xe0) == 0xe0;
|
return (hwc->config & 0xe0) == 0xe0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int amd_has_nb(struct cpu_hw_events *cpuc)
|
||||||
|
{
|
||||||
|
struct amd_nb *nb = cpuc->amd_nb;
|
||||||
|
|
||||||
|
return nb && nb->nb_id != -1;
|
||||||
|
}
|
||||||
|
|
||||||
static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
|
static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
|
||||||
struct perf_event *event)
|
struct perf_event *event)
|
||||||
{
|
{
|
||||||
@ -147,7 +154,7 @@ static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
|
|||||||
/*
|
/*
|
||||||
* only care about NB events
|
* only care about NB events
|
||||||
*/
|
*/
|
||||||
if (!(nb && amd_is_nb_event(hwc)))
|
if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -214,7 +221,7 @@ amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
|
|||||||
/*
|
/*
|
||||||
* if not NB event or no NB, then no constraints
|
* if not NB event or no NB, then no constraints
|
||||||
*/
|
*/
|
||||||
if (!(nb && amd_is_nb_event(hwc)))
|
if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc)))
|
||||||
return &unconstrained;
|
return &unconstrained;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -293,51 +300,55 @@ static struct amd_nb *amd_alloc_nb(int cpu, int nb_id)
|
|||||||
return nb;
|
return nb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void amd_pmu_cpu_online(int cpu)
|
static int amd_pmu_cpu_prepare(int cpu)
|
||||||
{
|
{
|
||||||
struct cpu_hw_events *cpu1, *cpu2;
|
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
|
||||||
struct amd_nb *nb = NULL;
|
|
||||||
|
WARN_ON_ONCE(cpuc->amd_nb);
|
||||||
|
|
||||||
|
if (boot_cpu_data.x86_max_cores < 2)
|
||||||
|
return NOTIFY_OK;
|
||||||
|
|
||||||
|
cpuc->amd_nb = amd_alloc_nb(cpu, -1);
|
||||||
|
if (!cpuc->amd_nb)
|
||||||
|
return NOTIFY_BAD;
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void amd_pmu_cpu_starting(int cpu)
|
||||||
|
{
|
||||||
|
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
|
||||||
|
struct amd_nb *nb;
|
||||||
int i, nb_id;
|
int i, nb_id;
|
||||||
|
|
||||||
if (boot_cpu_data.x86_max_cores < 2)
|
if (boot_cpu_data.x86_max_cores < 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
|
||||||
* function may be called too early in the
|
|
||||||
* boot process, in which case nb_id is bogus
|
|
||||||
*/
|
|
||||||
nb_id = amd_get_nb_id(cpu);
|
nb_id = amd_get_nb_id(cpu);
|
||||||
if (nb_id == BAD_APICID)
|
WARN_ON_ONCE(nb_id == BAD_APICID);
|
||||||
return;
|
|
||||||
|
|
||||||
cpu1 = &per_cpu(cpu_hw_events, cpu);
|
|
||||||
cpu1->amd_nb = NULL;
|
|
||||||
|
|
||||||
raw_spin_lock(&amd_nb_lock);
|
raw_spin_lock(&amd_nb_lock);
|
||||||
|
|
||||||
for_each_online_cpu(i) {
|
for_each_online_cpu(i) {
|
||||||
cpu2 = &per_cpu(cpu_hw_events, i);
|
nb = per_cpu(cpu_hw_events, i).amd_nb;
|
||||||
nb = cpu2->amd_nb;
|
if (WARN_ON_ONCE(!nb))
|
||||||
if (!nb)
|
|
||||||
continue;
|
continue;
|
||||||
if (nb->nb_id == nb_id)
|
|
||||||
goto found;
|
if (nb->nb_id == nb_id) {
|
||||||
|
kfree(cpuc->amd_nb);
|
||||||
|
cpuc->amd_nb = nb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nb = amd_alloc_nb(cpu, nb_id);
|
cpuc->amd_nb->nb_id = nb_id;
|
||||||
if (!nb) {
|
cpuc->amd_nb->refcnt++;
|
||||||
pr_err("perf_events: failed NB allocation for CPU%d\n", cpu);
|
|
||||||
raw_spin_unlock(&amd_nb_lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
found:
|
|
||||||
nb->refcnt++;
|
|
||||||
cpu1->amd_nb = nb;
|
|
||||||
|
|
||||||
raw_spin_unlock(&amd_nb_lock);
|
raw_spin_unlock(&amd_nb_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void amd_pmu_cpu_offline(int cpu)
|
static void amd_pmu_cpu_dead(int cpu)
|
||||||
{
|
{
|
||||||
struct cpu_hw_events *cpuhw;
|
struct cpu_hw_events *cpuhw;
|
||||||
|
|
||||||
@ -349,8 +360,10 @@ static void amd_pmu_cpu_offline(int cpu)
|
|||||||
raw_spin_lock(&amd_nb_lock);
|
raw_spin_lock(&amd_nb_lock);
|
||||||
|
|
||||||
if (cpuhw->amd_nb) {
|
if (cpuhw->amd_nb) {
|
||||||
if (--cpuhw->amd_nb->refcnt == 0)
|
struct amd_nb *nb = cpuhw->amd_nb;
|
||||||
kfree(cpuhw->amd_nb);
|
|
||||||
|
if (nb->nb_id == -1 || --nb->refcnt == 0)
|
||||||
|
kfree(nb);
|
||||||
|
|
||||||
cpuhw->amd_nb = NULL;
|
cpuhw->amd_nb = NULL;
|
||||||
}
|
}
|
||||||
@ -379,8 +392,9 @@ static __initconst struct x86_pmu amd_pmu = {
|
|||||||
.get_event_constraints = amd_get_event_constraints,
|
.get_event_constraints = amd_get_event_constraints,
|
||||||
.put_event_constraints = amd_put_event_constraints,
|
.put_event_constraints = amd_put_event_constraints,
|
||||||
|
|
||||||
.cpu_prepare = amd_pmu_cpu_online,
|
.cpu_prepare = amd_pmu_cpu_prepare,
|
||||||
.cpu_dead = amd_pmu_cpu_offline,
|
.cpu_starting = amd_pmu_cpu_starting,
|
||||||
|
.cpu_dead = amd_pmu_cpu_dead,
|
||||||
};
|
};
|
||||||
|
|
||||||
static __init int amd_pmu_init(void)
|
static __init int amd_pmu_init(void)
|
||||||
|
@ -30,6 +30,11 @@ struct stack_frame {
|
|||||||
unsigned long return_address;
|
unsigned long return_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct stack_frame_ia32 {
|
||||||
|
u32 next_frame;
|
||||||
|
u32 return_address;
|
||||||
|
};
|
||||||
|
|
||||||
static inline unsigned long rewind_frame_pointer(int n)
|
static inline unsigned long rewind_frame_pointer(int n)
|
||||||
{
|
{
|
||||||
struct stack_frame *frame;
|
struct stack_frame *frame;
|
||||||
|
@ -618,8 +618,8 @@ int kgdb_arch_init(void)
|
|||||||
* portion of kgdb because this operation requires mutexs to
|
* portion of kgdb because this operation requires mutexs to
|
||||||
* complete.
|
* complete.
|
||||||
*/
|
*/
|
||||||
|
hw_breakpoint_init(&attr);
|
||||||
attr.bp_addr = (unsigned long)kgdb_arch_init;
|
attr.bp_addr = (unsigned long)kgdb_arch_init;
|
||||||
attr.type = PERF_TYPE_BREAKPOINT;
|
|
||||||
attr.bp_len = HW_BREAKPOINT_LEN_1;
|
attr.bp_len = HW_BREAKPOINT_LEN_1;
|
||||||
attr.bp_type = HW_BREAKPOINT_W;
|
attr.bp_type = HW_BREAKPOINT_W;
|
||||||
attr.disabled = 1;
|
attr.disabled = 1;
|
||||||
|
@ -242,8 +242,6 @@ static void __cpuinit smp_callin(void)
|
|||||||
end_local_APIC_setup();
|
end_local_APIC_setup();
|
||||||
map_cpu_to_logical_apicid();
|
map_cpu_to_logical_apicid();
|
||||||
|
|
||||||
notify_cpu_starting(cpuid);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to setup vector mappings before we enable interrupts.
|
* Need to setup vector mappings before we enable interrupts.
|
||||||
*/
|
*/
|
||||||
@ -264,6 +262,8 @@ static void __cpuinit smp_callin(void)
|
|||||||
*/
|
*/
|
||||||
smp_store_cpu_info(cpuid);
|
smp_store_cpu_info(cpuid);
|
||||||
|
|
||||||
|
notify_cpu_starting(cpuid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow the master to continue.
|
* Allow the master to continue.
|
||||||
*/
|
*/
|
||||||
|
@ -842,13 +842,6 @@ extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
|
|||||||
|
|
||||||
extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64);
|
extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64);
|
||||||
|
|
||||||
static inline void
|
|
||||||
perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
|
|
||||||
{
|
|
||||||
if (atomic_read(&perf_swevent_enabled[event_id]))
|
|
||||||
__perf_sw_event(event_id, nr, nmi, regs, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
|
perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip);
|
||||||
|
|
||||||
@ -887,6 +880,20 @@ static inline void perf_fetch_caller_regs(struct pt_regs *regs, int skip)
|
|||||||
return perf_arch_fetch_caller_regs(regs, ip, skip);
|
return perf_arch_fetch_caller_regs(regs, ip, skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
|
||||||
|
{
|
||||||
|
if (atomic_read(&perf_swevent_enabled[event_id])) {
|
||||||
|
struct pt_regs hot_regs;
|
||||||
|
|
||||||
|
if (!regs) {
|
||||||
|
perf_fetch_caller_regs(&hot_regs, 1);
|
||||||
|
regs = &hot_regs;
|
||||||
|
}
|
||||||
|
__perf_sw_event(event_id, nr, nmi, regs, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern void __perf_event_mmap(struct vm_area_struct *vma);
|
extern void __perf_event_mmap(struct vm_area_struct *vma);
|
||||||
|
|
||||||
static inline void perf_event_mmap(struct vm_area_struct *vma)
|
static inline void perf_event_mmap(struct vm_area_struct *vma)
|
||||||
|
@ -1164,11 +1164,9 @@ void perf_event_task_sched_out(struct task_struct *task,
|
|||||||
struct perf_event_context *ctx = task->perf_event_ctxp;
|
struct perf_event_context *ctx = task->perf_event_ctxp;
|
||||||
struct perf_event_context *next_ctx;
|
struct perf_event_context *next_ctx;
|
||||||
struct perf_event_context *parent;
|
struct perf_event_context *parent;
|
||||||
struct pt_regs *regs;
|
|
||||||
int do_switch = 1;
|
int do_switch = 1;
|
||||||
|
|
||||||
regs = task_pt_regs(task);
|
perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0);
|
||||||
perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, regs, 0);
|
|
||||||
|
|
||||||
if (likely(!ctx || !cpuctx->task_ctx))
|
if (likely(!ctx || !cpuctx->task_ctx))
|
||||||
return;
|
return;
|
||||||
@ -2786,12 +2784,11 @@ __weak struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_EVENT_TRACING
|
|
||||||
__weak
|
__weak
|
||||||
void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
|
void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Output
|
* Output
|
||||||
@ -3378,15 +3375,23 @@ static void perf_event_task_output(struct perf_event *event,
|
|||||||
struct perf_task_event *task_event)
|
struct perf_task_event *task_event)
|
||||||
{
|
{
|
||||||
struct perf_output_handle handle;
|
struct perf_output_handle handle;
|
||||||
int size;
|
|
||||||
struct task_struct *task = task_event->task;
|
struct task_struct *task = task_event->task;
|
||||||
int ret;
|
unsigned long flags;
|
||||||
|
int size, ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this CPU attempts to acquire an rq lock held by a CPU spinning
|
||||||
|
* in perf_output_lock() from interrupt context, it's game over.
|
||||||
|
*/
|
||||||
|
local_irq_save(flags);
|
||||||
|
|
||||||
size = task_event->event_id.header.size;
|
size = task_event->event_id.header.size;
|
||||||
ret = perf_output_begin(&handle, event, size, 0, 0);
|
ret = perf_output_begin(&handle, event, size, 0, 0);
|
||||||
|
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
local_irq_restore(flags);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
task_event->event_id.pid = perf_event_pid(event, task);
|
task_event->event_id.pid = perf_event_pid(event, task);
|
||||||
task_event->event_id.ppid = perf_event_pid(event, current);
|
task_event->event_id.ppid = perf_event_pid(event, current);
|
||||||
@ -3397,6 +3402,7 @@ static void perf_event_task_output(struct perf_event *event,
|
|||||||
perf_output_put(&handle, task_event->event_id);
|
perf_output_put(&handle, task_event->event_id);
|
||||||
|
|
||||||
perf_output_end(&handle);
|
perf_output_end(&handle);
|
||||||
|
local_irq_restore(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_event_task_match(struct perf_event *event)
|
static int perf_event_task_match(struct perf_event *event)
|
||||||
|
@ -17,7 +17,12 @@ EXPORT_SYMBOL_GPL(perf_arch_fetch_caller_regs);
|
|||||||
static char *perf_trace_buf;
|
static char *perf_trace_buf;
|
||||||
static char *perf_trace_buf_nmi;
|
static char *perf_trace_buf_nmi;
|
||||||
|
|
||||||
typedef typeof(char [PERF_MAX_TRACE_SIZE]) perf_trace_t ;
|
/*
|
||||||
|
* Force it to be aligned to unsigned long to avoid misaligned accesses
|
||||||
|
* suprises
|
||||||
|
*/
|
||||||
|
typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)])
|
||||||
|
perf_trace_t;
|
||||||
|
|
||||||
/* Count the events in use (per event id, not per instance) */
|
/* Count the events in use (per event id, not per instance) */
|
||||||
static int total_ref_count;
|
static int total_ref_count;
|
||||||
@ -130,6 +135,8 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
|
|||||||
char *trace_buf, *raw_data;
|
char *trace_buf, *raw_data;
|
||||||
int pc, cpu;
|
int pc, cpu;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long));
|
||||||
|
|
||||||
pc = preempt_count();
|
pc = preempt_count();
|
||||||
|
|
||||||
/* Protect the per cpu buffer, begin the rcu read side */
|
/* Protect the per cpu buffer, begin the rcu read side */
|
||||||
@ -152,7 +159,7 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
|
|||||||
raw_data = per_cpu_ptr(trace_buf, cpu);
|
raw_data = per_cpu_ptr(trace_buf, cpu);
|
||||||
|
|
||||||
/* zero the dead bytes from align to not leak stack to user */
|
/* zero the dead bytes from align to not leak stack to user */
|
||||||
*(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
|
memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64));
|
||||||
|
|
||||||
entry = (struct trace_entry *)raw_data;
|
entry = (struct trace_entry *)raw_data;
|
||||||
tracing_generic_entry_update(entry, *irq_flags, pc);
|
tracing_generic_entry_update(entry, *irq_flags, pc);
|
||||||
|
@ -200,7 +200,7 @@ endif
|
|||||||
|
|
||||||
CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
||||||
EXTLIBS = -lpthread -lrt -lelf -lm
|
EXTLIBS = -lpthread -lrt -lelf -lm
|
||||||
ALL_CFLAGS = $(CFLAGS)
|
ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||||||
ALL_LDFLAGS = $(LDFLAGS)
|
ALL_LDFLAGS = $(LDFLAGS)
|
||||||
STRIP ?= strip
|
STRIP ?= strip
|
||||||
|
|
||||||
@ -492,19 +492,19 @@ ifeq ($(uname_S),Darwin)
|
|||||||
PTHREAD_LIBS =
|
PTHREAD_LIBS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
||||||
ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
||||||
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
|
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
||||||
BASIC_CFLAGS += -DLIBELF_NO_MMAP
|
BASIC_CFLAGS += -DLIBELF_NO_MMAP
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
|
msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
||||||
msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);
|
msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);
|
||||||
BASIC_CFLAGS += -DNO_DWARF_SUPPORT
|
BASIC_CFLAGS += -DNO_DWARF_SUPPORT
|
||||||
else
|
else
|
||||||
|
@ -208,7 +208,7 @@ static void python_process_event(int cpu, void *data,
|
|||||||
int size __unused,
|
int size __unused,
|
||||||
unsigned long long nsecs, char *comm)
|
unsigned long long nsecs, char *comm)
|
||||||
{
|
{
|
||||||
PyObject *handler, *retval, *context, *t;
|
PyObject *handler, *retval, *context, *t, *obj;
|
||||||
static char handler_name[256];
|
static char handler_name[256];
|
||||||
struct format_field *field;
|
struct format_field *field;
|
||||||
unsigned long long val;
|
unsigned long long val;
|
||||||
@ -256,16 +256,23 @@ static void python_process_event(int cpu, void *data,
|
|||||||
offset &= 0xffff;
|
offset &= 0xffff;
|
||||||
} else
|
} else
|
||||||
offset = field->offset;
|
offset = field->offset;
|
||||||
PyTuple_SetItem(t, n++,
|
obj = PyString_FromString((char *)data + offset);
|
||||||
PyString_FromString((char *)data + offset));
|
|
||||||
} else { /* FIELD_IS_NUMERIC */
|
} else { /* FIELD_IS_NUMERIC */
|
||||||
val = read_size(data + field->offset, field->size);
|
val = read_size(data + field->offset, field->size);
|
||||||
if (field->flags & FIELD_IS_SIGNED) {
|
if (field->flags & FIELD_IS_SIGNED) {
|
||||||
PyTuple_SetItem(t, n++, PyInt_FromLong(val));
|
if ((long long)val >= LONG_MIN &&
|
||||||
|
(long long)val <= LONG_MAX)
|
||||||
|
obj = PyInt_FromLong(val);
|
||||||
|
else
|
||||||
|
obj = PyLong_FromLongLong(val);
|
||||||
} else {
|
} else {
|
||||||
PyTuple_SetItem(t, n++, PyInt_FromLong(val));
|
if (val <= LONG_MAX)
|
||||||
|
obj = PyInt_FromLong(val);
|
||||||
|
else
|
||||||
|
obj = PyLong_FromUnsignedLongLong(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PyTuple_SetItem(t, n++, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_PyTuple_Resize(&t, n) == -1)
|
if (_PyTuple_Resize(&t, n) == -1)
|
||||||
|
Loading…
Reference in New Issue
Block a user