Skip to content

Commit

Permalink
Merge branch 'perf/fast' into perf/core
Browse files Browse the repository at this point in the history
Merge reason: Lets ready it for v3.4

Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
Ingo Molnar committed Jan 27, 2012
2 parents 801493c + 08aa0d1 commit 44a6839
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 29 deletions.
4 changes: 0 additions & 4 deletions arch/arm/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
#ifndef __ARM_PERF_EVENT_H__
#define __ARM_PERF_EVENT_H__

/* ARM performance counters start from 1 (in the cp15 accesses) so use the
* same indexes here for consistency. */
#define PERF_EVENT_INDEX_OFFSET 1

/* ARM perf PMU IDs for use by internal perf clients. */
enum arm_perf_pmu_ids {
ARM_PERF_PMU_ID_XSCALE1 = 0,
Expand Down
2 changes: 0 additions & 2 deletions arch/frv/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,4 @@
#ifndef _ASM_PERF_EVENT_H
#define _ASM_PERF_EVENT_H

#define PERF_EVENT_INDEX_OFFSET 0

#endif /* _ASM_PERF_EVENT_H */
2 changes: 0 additions & 2 deletions arch/hexagon/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,4 @@
#ifndef _ASM_PERF_EVENT_H
#define _ASM_PERF_EVENT_H

#define PERF_EVENT_INDEX_OFFSET 0

#endif /* _ASM_PERF_EVENT_H */
2 changes: 0 additions & 2 deletions arch/powerpc/include/asm/perf_event_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ struct pt_regs;
extern unsigned long perf_misc_flags(struct pt_regs *regs);
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);

#define PERF_EVENT_INDEX_OFFSET 1

/*
* Only override the default definitions in include/linux/perf_event.h
* if we have hardware PMU support.
Expand Down
6 changes: 6 additions & 0 deletions arch/powerpc/kernel/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,11 @@ static int power_pmu_event_init(struct perf_event *event)
return err;
}

static int power_pmu_event_idx(struct perf_event *event)
{
return event->hw.idx;
}

struct pmu power_pmu = {
.pmu_enable = power_pmu_enable,
.pmu_disable = power_pmu_disable,
Expand All @@ -1199,6 +1204,7 @@ struct pmu power_pmu = {
.start_txn = power_pmu_start_txn,
.cancel_txn = power_pmu_cancel_txn,
.commit_txn = power_pmu_commit_txn,
.event_idx = power_pmu_event_idx,
};

/*
Expand Down
1 change: 0 additions & 1 deletion arch/s390/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@

/* Empty, just to avoid compiling error */

#define PERF_EVENT_INDEX_OFFSET 0
2 changes: 0 additions & 2 deletions arch/x86/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,6 @@ extern u32 get_ibs_caps(void);
#ifdef CONFIG_PERF_EVENTS
extern void perf_events_lapic_init(void);

#define PERF_EVENT_INDEX_OFFSET 0

/*
* Abuse bit 3 of the cpu eflags register to indicate proper PEBS IP fixups.
* This flag is otherwise unused and ABI specified to be 0, so nobody should
Expand Down
82 changes: 82 additions & 0 deletions arch/x86/kernel/cpu/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/bitops.h>
#include <linux/device.h>

#include <asm/apic.h>
#include <asm/stacktrace.h>
#include <asm/nmi.h>
#include <asm/compat.h>
#include <asm/smp.h>
#include <asm/alternative.h>
#include <asm/timer.h>

#include "perf_event.h"

Expand Down Expand Up @@ -1210,6 +1212,8 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
break;

case CPU_STARTING:
if (x86_pmu.attr_rdpmc)
set_in_cr4(X86_CR4_PCE);
if (x86_pmu.cpu_starting)
x86_pmu.cpu_starting(cpu);
break;
Expand Down Expand Up @@ -1319,6 +1323,8 @@ static int __init init_hw_perf_events(void)
}
}

x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */

pr_info("... version: %d\n", x86_pmu.version);
pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
pr_info("... generic registers: %d\n", x86_pmu.num_counters);
Expand Down Expand Up @@ -1542,10 +1548,71 @@ static int x86_pmu_event_init(struct perf_event *event)
return err;
}

static int x86_pmu_event_idx(struct perf_event *event)
{
int idx = event->hw.idx;

if (x86_pmu.num_counters_fixed && idx >= X86_PMC_IDX_FIXED) {
idx -= X86_PMC_IDX_FIXED;
idx |= 1 << 30;
}

return idx + 1;
}

static ssize_t get_attr_rdpmc(struct device *cdev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, 40, "%d\n", x86_pmu.attr_rdpmc);
}

static void change_rdpmc(void *info)
{
bool enable = !!(unsigned long)info;

if (enable)
set_in_cr4(X86_CR4_PCE);
else
clear_in_cr4(X86_CR4_PCE);
}

static ssize_t set_attr_rdpmc(struct device *cdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned long val = simple_strtoul(buf, NULL, 0);

if (!!val != !!x86_pmu.attr_rdpmc) {
x86_pmu.attr_rdpmc = !!val;
smp_call_function(change_rdpmc, (void *)val, 1);
}

return count;
}

static DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc);

static struct attribute *x86_pmu_attrs[] = {
&dev_attr_rdpmc.attr,
NULL,
};

static struct attribute_group x86_pmu_attr_group = {
.attrs = x86_pmu_attrs,
};

static const struct attribute_group *x86_pmu_attr_groups[] = {
&x86_pmu_attr_group,
NULL,
};

static struct pmu pmu = {
.pmu_enable = x86_pmu_enable,
.pmu_disable = x86_pmu_disable,

.attr_groups = x86_pmu_attr_groups,

.event_init = x86_pmu_event_init,

.add = x86_pmu_add,
Expand All @@ -1557,8 +1624,23 @@ static struct pmu pmu = {
.start_txn = x86_pmu_start_txn,
.cancel_txn = x86_pmu_cancel_txn,
.commit_txn = x86_pmu_commit_txn,

.event_idx = x86_pmu_event_idx,
};

void perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now)
{
if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
return;

if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
return;

userpg->time_mult = this_cpu_read(cyc2ns);
userpg->time_shift = CYC2NS_SCALE_FACTOR;
userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
}

/*
* callchain support
*/
Expand Down
8 changes: 8 additions & 0 deletions arch/x86/kernel/cpu/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,14 @@ struct x86_pmu {
struct x86_pmu_quirk *quirks;
int perfctr_second_write;

/*
* sysfs attrs
*/
int attr_rdpmc;

/*
* CPU Hotplug hooks
*/
int (*cpu_prepare)(int cpu);
void (*cpu_starting)(int cpu);
void (*cpu_dying)(int cpu);
Expand Down
11 changes: 10 additions & 1 deletion include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,12 +291,14 @@ struct perf_event_mmap_page {
__s64 offset; /* add to hardware event value */
__u64 time_enabled; /* time event active */
__u64 time_running; /* time event on cpu */
__u32 time_mult, time_shift;
__u64 time_offset;

/*
* Hole for extension of the self monitor capabilities
*/

__u64 __reserved[123]; /* align to 1k */
__u64 __reserved[121]; /* align to 1k */

/*
* Control data for the mmap() data buffer.
Expand Down Expand Up @@ -615,6 +617,7 @@ struct pmu {
struct list_head entry;

struct device *dev;
const struct attribute_group **attr_groups;
char *name;
int type;

Expand Down Expand Up @@ -680,6 +683,12 @@ struct pmu {
* for each successful ->add() during the transaction.
*/
void (*cancel_txn) (struct pmu *pmu); /* optional */

/*
* Will return the value for perf_event_mmap_page::index for this event,
* if no implementation is provided it will default to: event->hw.idx + 1.
*/
int (*event_idx) (struct perf_event *event); /*optional */
};

/**
Expand Down
Loading

0 comments on commit 44a6839

Please sign in to comment.