Skip to content

Commit

Permalink
[PATCH] i386: Utilize performance counter reservation framework in op…
Browse files Browse the repository at this point in the history
…rofile

Incorporates the new performance counter reservation system in oprofile.
Also cleans up a lot of the initialization code.  The code original zero'd
out every register associated with performance counters regardless if those
registers were used or not.  This causes issues with the nmi watchdog.
Now oprofile tries to reserve registers and gives up if it can't get them.

Cc: levon@movementarian.org
Cc: oprofile-list@lists.sf.net

Signed-off-by:  Don Zickus <dzickus@redhat.com>
Signed-off-by: Andi Kleen <ak@suse.de>
  • Loading branch information
Don Zickus authored and Andi Kleen committed Sep 26, 2006
1 parent 828f0af commit cb9c448
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 114 deletions.
41 changes: 29 additions & 12 deletions arch/i386/oprofile/nmi_int.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,19 @@ static void nmi_cpu_save_registers(struct op_msrs * msrs)
unsigned int i;

for (i = 0; i < nr_ctrs; ++i) {
rdmsr(counters[i].addr,
counters[i].saved.low,
counters[i].saved.high);
if (counters[i].addr){
rdmsr(counters[i].addr,
counters[i].saved.low,
counters[i].saved.high);
}
}

for (i = 0; i < nr_ctrls; ++i) {
rdmsr(controls[i].addr,
controls[i].saved.low,
controls[i].saved.high);
if (controls[i].addr){
rdmsr(controls[i].addr,
controls[i].saved.low,
controls[i].saved.high);
}
}
}

Expand Down Expand Up @@ -205,15 +209,19 @@ static void nmi_restore_registers(struct op_msrs * msrs)
unsigned int i;

for (i = 0; i < nr_ctrls; ++i) {
wrmsr(controls[i].addr,
controls[i].saved.low,
controls[i].saved.high);
if (controls[i].addr){
wrmsr(controls[i].addr,
controls[i].saved.low,
controls[i].saved.high);
}
}

for (i = 0; i < nr_ctrs; ++i) {
wrmsr(counters[i].addr,
counters[i].saved.low,
counters[i].saved.high);
if (counters[i].addr){
wrmsr(counters[i].addr,
counters[i].saved.low,
counters[i].saved.high);
}
}
}

Expand All @@ -234,6 +242,7 @@ static void nmi_cpu_shutdown(void * dummy)
apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
apic_write(APIC_LVTERR, v);
nmi_restore_registers(msrs);
model->shutdown(msrs);
}


Expand Down Expand Up @@ -284,6 +293,14 @@ static int nmi_create_files(struct super_block * sb, struct dentry * root)
struct dentry * dir;
char buf[4];

/* quick little hack to _not_ expose a counter if it is not
* available for use. This should protect userspace app.
* NOTE: assumes 1:1 mapping here (that counters are organized
* sequentially in their struct assignment).
*/
if (unlikely(!avail_to_resrv_perfctr_nmi_bit(i)))
continue;

snprintf(buf, sizeof(buf), "%d", i);
dir = oprofilefs_mkdir(sb, root, buf);
oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
Expand Down
54 changes: 42 additions & 12 deletions arch/i386/oprofile/op_model_athlon.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
#define NUM_COUNTERS 4
#define NUM_CONTROLS 4

#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters[(c)].addr, (l), (h));} while (0)
#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters[(c)].addr, -(unsigned int)(l), -1);} while (0)
#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))

#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
#define CTRL_READ(l,h,msrs,c) do {rdmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
#define CTRL_WRITE(l,h,msrs,c) do {wrmsr(msrs->controls[(c)].addr, (l), (h));} while (0)
#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
Expand All @@ -40,15 +42,21 @@ static unsigned long reset_value[NUM_COUNTERS];

static void athlon_fill_in_addresses(struct op_msrs * const msrs)
{
msrs->counters[0].addr = MSR_K7_PERFCTR0;
msrs->counters[1].addr = MSR_K7_PERFCTR1;
msrs->counters[2].addr = MSR_K7_PERFCTR2;
msrs->counters[3].addr = MSR_K7_PERFCTR3;

msrs->controls[0].addr = MSR_K7_EVNTSEL0;
msrs->controls[1].addr = MSR_K7_EVNTSEL1;
msrs->controls[2].addr = MSR_K7_EVNTSEL2;
msrs->controls[3].addr = MSR_K7_EVNTSEL3;
int i;

for (i=0; i < NUM_COUNTERS; i++) {
if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
else
msrs->counters[i].addr = 0;
}

for (i=0; i < NUM_CONTROLS; i++) {
if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
else
msrs->controls[i].addr = 0;
}
}


Expand All @@ -59,19 +67,23 @@ static void athlon_setup_ctrs(struct op_msrs const * const msrs)

/* clear all counters */
for (i = 0 ; i < NUM_CONTROLS; ++i) {
if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
continue;
CTRL_READ(low, high, msrs, i);
CTRL_CLEAR(low);
CTRL_WRITE(low, high, msrs, i);
}

/* avoid a false detection of ctr overflows in NMI handler */
for (i = 0; i < NUM_COUNTERS; ++i) {
if (unlikely(!CTR_IS_RESERVED(msrs,i)))
continue;
CTR_WRITE(1, msrs, i);
}

/* enable active counters */
for (i = 0; i < NUM_COUNTERS; ++i) {
if (counter_config[i].enabled) {
if ((counter_config[i].enabled) && (CTR_IS_RESERVED(msrs,i))) {
reset_value[i] = counter_config[i].count;

CTR_WRITE(counter_config[i].count, msrs, i);
Expand All @@ -98,6 +110,8 @@ static int athlon_check_ctrs(struct pt_regs * const regs,
int i;

for (i = 0 ; i < NUM_COUNTERS; ++i) {
if (!reset_value[i])
continue;
CTR_READ(low, high, msrs, i);
if (CTR_OVERFLOWED(low)) {
oprofile_add_sample(regs, i);
Expand Down Expand Up @@ -132,12 +146,27 @@ static void athlon_stop(struct op_msrs const * const msrs)
/* Subtle: stop on all counters to avoid race with
* setting our pm callback */
for (i = 0 ; i < NUM_COUNTERS ; ++i) {
if (!reset_value[i])
continue;
CTRL_READ(low, high, msrs, i);
CTRL_SET_INACTIVE(low);
CTRL_WRITE(low, high, msrs, i);
}
}

static void athlon_shutdown(struct op_msrs const * const msrs)
{
int i;

for (i = 0 ; i < NUM_COUNTERS ; ++i) {
if (CTR_IS_RESERVED(msrs,i))
release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
}
for (i = 0 ; i < NUM_CONTROLS ; ++i) {
if (CTRL_IS_RESERVED(msrs,i))
release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
}
}

struct op_x86_model_spec const op_athlon_spec = {
.num_counters = NUM_COUNTERS,
Expand All @@ -146,5 +175,6 @@ struct op_x86_model_spec const op_athlon_spec = {
.setup_ctrs = &athlon_setup_ctrs,
.check_ctrs = &athlon_check_ctrs,
.start = &athlon_start,
.stop = &athlon_stop
.stop = &athlon_stop,
.shutdown = &athlon_shutdown
};
Loading

0 comments on commit cb9c448

Please sign in to comment.