Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 199111
b: refs/heads/master
c: dfacc4d
h: refs/heads/master
i:
  199109: fd6c203
  199107: ac28129
  199103: c9df853
v: v3
  • Loading branch information
Ingo Molnar committed May 20, 2010
1 parent a495797 commit 411fbe3
Show file tree
Hide file tree
Showing 40 changed files with 339 additions and 2,190 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 85cb68b27c428d477169f3aa46c72dba103a17bd
refs/heads/master: dfacc4d6c98b89609250269f518c1f54c30454ef
108 changes: 61 additions & 47 deletions trunk/arch/sparc/kernel/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ struct cpu_hw_events {

/* Enabled/disable state. */
int enabled;

unsigned int group_flag;
};
DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, };

Expand Down Expand Up @@ -980,53 +982,6 @@ static int collect_events(struct perf_event *group, int max_count,
return n;
}

static void event_sched_in(struct perf_event *event)
{
event->state = PERF_EVENT_STATE_ACTIVE;
event->oncpu = smp_processor_id();
event->tstamp_running += event->ctx->time - event->tstamp_stopped;
if (is_software_event(event))
event->pmu->enable(event);
}

int hw_perf_group_sched_in(struct perf_event *group_leader,
struct perf_cpu_context *cpuctx,
struct perf_event_context *ctx)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
struct perf_event *sub;
int n0, n;

if (!sparc_pmu)
return 0;

n0 = cpuc->n_events;
n = collect_events(group_leader, perf_max_events - n0,
&cpuc->event[n0], &cpuc->events[n0],
&cpuc->current_idx[n0]);
if (n < 0)
return -EAGAIN;
if (check_excludes(cpuc->event, n0, n))
return -EINVAL;
if (sparc_check_constraints(cpuc->event, cpuc->events, n + n0))
return -EAGAIN;
cpuc->n_events = n0 + n;
cpuc->n_added += n;

cpuctx->active_oncpu += n;
n = 1;
event_sched_in(group_leader);
list_for_each_entry(sub, &group_leader->sibling_list, group_entry) {
if (sub->state != PERF_EVENT_STATE_OFF) {
event_sched_in(sub);
n++;
}
}
ctx->nr_active += n;

return 1;
}

static int sparc_pmu_enable(struct perf_event *event)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
Expand All @@ -1044,11 +999,20 @@ static int sparc_pmu_enable(struct perf_event *event)
cpuc->events[n0] = event->hw.event_base;
cpuc->current_idx[n0] = PIC_NO_INDEX;

/*
* If group events scheduling transaction was started,
* skip the schedulability test here, it will be peformed
* at commit time(->commit_txn) as a whole
*/
if (cpuc->group_flag & PERF_EVENT_TXN_STARTED)
goto nocheck;

if (check_excludes(cpuc->event, n0, 1))
goto out;
if (sparc_check_constraints(cpuc->event, cpuc->events, n0 + 1))
goto out;

nocheck:
cpuc->n_events++;
cpuc->n_added++;

Expand Down Expand Up @@ -1128,11 +1092,61 @@ static int __hw_perf_event_init(struct perf_event *event)
return 0;
}

/*
* Start group events scheduling transaction
* Set the flag to make pmu::enable() not perform the
* schedulability test, it will be performed at commit time
*/
static void sparc_pmu_start_txn(const struct pmu *pmu)
{
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);

cpuhw->group_flag |= PERF_EVENT_TXN_STARTED;
}

/*
* Stop group events scheduling transaction
* Clear the flag and pmu::enable() will perform the
* schedulability test.
*/
static void sparc_pmu_cancel_txn(const struct pmu *pmu)
{
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);

cpuhw->group_flag &= ~PERF_EVENT_TXN_STARTED;
}

/*
* Commit group events scheduling transaction
* Perform the group schedulability test as a whole
* Return 0 if success
*/
static int sparc_pmu_commit_txn(const struct pmu *pmu)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
int n;

if (!sparc_pmu)
return -EINVAL;

cpuc = &__get_cpu_var(cpu_hw_events);
n = cpuc->n_events;
if (check_excludes(cpuc->event, 0, n))
return -EINVAL;
if (sparc_check_constraints(cpuc->event, cpuc->events, n))
return -EAGAIN;

return 0;
}

static const struct pmu pmu = {
.enable = sparc_pmu_enable,
.disable = sparc_pmu_disable,
.read = sparc_pmu_read,
.unthrottle = sparc_pmu_unthrottle,
.start_txn = sparc_pmu_start_txn,
.cancel_txn = sparc_pmu_cancel_txn,
.commit_txn = sparc_pmu_commit_txn,
};

const struct pmu *hw_perf_event_init(struct perf_event *event)
Expand Down
3 changes: 2 additions & 1 deletion trunk/arch/x86/include/asm/perf_event_p4.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@
P4_CCCR_ENABLE)

/* HT mask */
#define P4_CCCR_MASK_HT (P4_CCCR_MASK | P4_CCCR_THREAD_ANY)
#define P4_CCCR_MASK_HT \
(P4_CCCR_MASK | P4_CCCR_OVF_PMI_T1 | P4_CCCR_THREAD_ANY)

#define P4_GEN_ESCR_EMASK(class, name, bit) \
class##__##name = ((1 << bit) << P4_ESCR_EVENTMASK_SHIFT)
Expand Down
41 changes: 21 additions & 20 deletions trunk/arch/x86/kernel/cpu/perf_event_p4.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,15 +465,21 @@ static int p4_hw_config(struct perf_event *event)
return rc;
}

static inline void p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
{
unsigned long dummy;
int overflow = 0;
u32 low, high;

rdmsrl(hwc->config_base + hwc->idx, dummy);
if (dummy & P4_CCCR_OVF) {
rdmsr(hwc->config_base + hwc->idx, low, high);

/* we need to check high bit for unflagged overflows */
if ((low & P4_CCCR_OVF) || !(high & (1 << 31))) {
overflow = 1;
(void)checking_wrmsrl(hwc->config_base + hwc->idx,
((u64)dummy) & ~P4_CCCR_OVF);
((u64)low) & ~P4_CCCR_OVF);
}

return overflow;
}

static inline void p4_pmu_disable_event(struct perf_event *event)
Expand Down Expand Up @@ -584,21 +590,15 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)

WARN_ON_ONCE(hwc->idx != idx);

/*
* FIXME: Redundant call, actually not needed
* but just to check if we're screwed
*/
p4_pmu_clear_cccr_ovf(hwc);
/* it might be unflagged overflow */
handled = p4_pmu_clear_cccr_ovf(hwc);

val = x86_perf_event_update(event);
if (val & (1ULL << (x86_pmu.cntval_bits - 1)))
if (!handled && (val & (1ULL << (x86_pmu.cntval_bits - 1))))
continue;

/*
* event overflow
*/
handled = 1;
data.period = event->hw.last_period;
/* event overflow for sure */
data.period = event->hw.last_period;

if (!x86_perf_event_set_period(event))
continue;
Expand Down Expand Up @@ -670,7 +670,7 @@ static void p4_pmu_swap_config_ts(struct hw_perf_event *hwc, int cpu)

/*
* ESCR address hashing is tricky, ESCRs are not sequential
* in memory but all starts from MSR_P4_BSU_ESCR0 (0x03e0) and
* in memory but all starts from MSR_P4_BSU_ESCR0 (0x03a0) and
* the metric between any ESCRs is laid in range [0xa0,0xe1]
*
* so we make ~70% filled hashtable
Expand Down Expand Up @@ -735,8 +735,9 @@ static int p4_get_escr_idx(unsigned int addr)
{
unsigned int idx = P4_ESCR_MSR_IDX(addr);

if (unlikely(idx >= P4_ESCR_MSR_TABLE_SIZE ||
!p4_escr_table[idx])) {
if (unlikely(idx >= P4_ESCR_MSR_TABLE_SIZE ||
!p4_escr_table[idx] ||
p4_escr_table[idx] != addr)) {
WARN_ONCE(1, "P4 PMU: Wrong address passed: %x\n", addr);
return -1;
}
Expand All @@ -762,7 +763,7 @@ static int p4_pmu_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign
{
unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
unsigned long escr_mask[BITS_TO_LONGS(P4_ESCR_MSR_TABLE_SIZE)];
int cpu = raw_smp_processor_id();
int cpu = smp_processor_id();
struct hw_perf_event *hwc;
struct p4_event_bind *bind;
unsigned int i, thread, num;
Expand Down
8 changes: 5 additions & 3 deletions trunk/include/linux/ftrace_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ struct ftrace_event_call {
void *data;

int perf_refcount;
void *perf_data;
int (*perf_event_enable)(struct ftrace_event_call *);
void (*perf_event_disable)(struct ftrace_event_call *);
};
Expand Down Expand Up @@ -191,7 +192,7 @@ struct perf_event;

DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);

extern int perf_trace_enable(int event_id);
extern int perf_trace_enable(int event_id, void *data);
extern void perf_trace_disable(int event_id);
extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
char *filter_str);
Expand All @@ -202,11 +203,12 @@ perf_trace_buf_prepare(int size, unsigned short type, int *rctxp,

static inline void
perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr,
u64 count, unsigned long irq_flags, struct pt_regs *regs)
u64 count, unsigned long irq_flags, struct pt_regs *regs,
void *event)
{
struct trace_entry *entry = raw_data;

perf_tp_event(entry->type, addr, count, raw_data, size, regs);
perf_tp_event(entry->type, addr, count, raw_data, size, regs, event);
perf_swevent_put_recursion_context(rctx);
local_irq_restore(irq_flags);
}
Expand Down
19 changes: 9 additions & 10 deletions trunk/include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ struct perf_guest_info_callbacks {
#include <linux/ftrace.h>
#include <linux/cpu.h>
#include <asm/atomic.h>
#include <asm/local.h>

#define PERF_MAX_STACK_DEPTH 255

Expand Down Expand Up @@ -588,20 +589,18 @@ struct perf_mmap_data {
#ifdef CONFIG_PERF_USE_VMALLOC
struct work_struct work;
#endif
int data_order;
int data_order; /* allocation order */
int nr_pages; /* nr of data pages */
int writable; /* are we writable */
int nr_locked; /* nr pages mlocked */

atomic_t poll; /* POLL_ for wakeups */
atomic_t events; /* event_id limit */

atomic_long_t head; /* write position */
atomic_long_t done_head; /* completed head */

atomic_t lock; /* concurrent writes */
atomic_t wakeup; /* needs a wakeup */
atomic_t lost; /* nr records lost */
local_t head; /* write position */
local_t nest; /* nested writers */
local_t events; /* event limit */
local_t wakeup; /* needs a wakeup */
local_t lost; /* nr records lost */

long watermark; /* wakeup watermark */

Expand Down Expand Up @@ -805,9 +804,9 @@ struct perf_output_handle {
struct perf_mmap_data *data;
unsigned long head;
unsigned long offset;
unsigned long wakeup;
int nmi;
int sample;
int locked;
};

#ifdef CONFIG_PERF_EVENTS
Expand Down Expand Up @@ -994,7 +993,7 @@ static inline bool perf_paranoid_kernel(void)

extern void perf_event_init(void);
extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size, struct pt_regs *regs);
int entry_size, struct pt_regs *regs, void *event);
extern void perf_bp_event(struct perf_event *event, void *data);

#ifndef perf_misc_flags
Expand Down
3 changes: 2 additions & 1 deletion trunk/include/trace/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,8 @@ perf_trace_templ_##call(struct ftrace_event_call *event_call, \
{ assign; } \
\
perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \
__count, irq_flags, __regs); \
__count, irq_flags, __regs, \
event_call->perf_data); \
}

#undef DEFINE_EVENT
Expand Down
Loading

0 comments on commit 411fbe3

Please sign in to comment.