Re: [PATCH for review] [6/145] x86_64: Utilize performance counter reservation framework in oprofile

Oleg Verych
2006-08-11T00:42:31Z

Andi Kleen:

> Index: linux/arch/i386/oprofile/nmi_int.c
> ===================================================================
> --- linux.orig/arch/i386/oprofile/nmi_int.c
> +++ linux/arch/i386/oprofile/nmi_int.c
> @@ -98,15 +98,19 @@ static void nmi_cpu_save_registers(struc
> 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){

need space ){

> + 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){

likewise

> + rdmsr(controls[i].addr,
> + controls[i].saved.low,
> + controls[i].saved.high);
> + }
> }
> }
>
> @@ -205,15 +209,19 @@ static void nmi_restore_registers(struct
> 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){

likewise

> + 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){

likewise

> + wrmsr(counters[i].addr,
> + counters[i].saved.low,
> + counters[i].saved.high);
> + }
> }
> }
>
> @@ -234,6 +242,7 @@ static void nmi_cpu_shutdown(void * dumm
> apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
> apic_write(APIC_LVTERR, v);
> nmi_restore_registers(msrs);
> + model->shutdown(msrs);
> }
>
>
> @@ -284,6 +293,14 @@ static int nmi_create_files(struct super
> 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);
> Index: linux/arch/i386/oprofile/op_model_athlon.c
> ===================================================================
> --- linux.orig/arch/i386/oprofile/op_model_athlon.c
> +++ linux/arch/i386/oprofile/op_model_athlon.c
> @@ -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))
> @@ -40,15 +42,21 @@ static unsigned long reset_value[NUM_COU
>
> 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;
> + }
> }
>
>
> @@ -59,19 +67,23 @@ static void athlon_setup_ctrs(struct op_
>
> /* 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);
> @@ -98,6 +110,8 @@ static int athlon_check_ctrs(struct pt_r
> 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);
> @@ -132,12 +146,27 @@ static void athlon_stop(struct op_msrs c
> /* 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,
> @@ -146,5 +175,6 @@ struct op_x86_model_spec const op_athlon
> .setup_ctrs = &athlon_setup_ctrs,
> .check_ctrs = &athlon_check_ctrs,
> .start = &athlon_start,
> - .stop = &athlon_stop
> + .stop = &athlon_stop,
> + .shutdown = &athlon_shutdown
> };
> Index: linux/arch/i386/oprofile/op_model_p4.c
> ===================================================================
> --- linux.orig/arch/i386/oprofile/op_model_p4.c
> +++ linux/arch/i386/oprofile/op_model_p4.c
> @@ -32,7 +32,7 @@
> #define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
>
> static unsigned int num_counters = NUM_COUNTERS_NON_HT;
> -
> +static unsigned int num_controls = NUM_CONTROLS_NON_HT;
>
> /* this has to be checked dynamically since the
> hyper-threadedness of a chip is discovered at
> @@ -40,8 +40,10 @@ static unsigned int num_counters = NUM_C
> static inline void setup_num_counters(void)
> {
> #ifdef CONFIG_SMP
> - if (smp_num_siblings == 2)
> + if (smp_num_siblings == 2){

likewise

> num_counters = NUM_COUNTERS_HT2;
> + num_controls = NUM_CONTROLS_HT2;
> + }
> #endif
> }
>
> @@ -97,15 +99,6 @@ static struct p4_counter_binding p4_coun
>
> #define NUM_UNUSED_CCCRS NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT

maybe (NUM_CCCRS_NON_HT - NUM_COUNTERS_NON_HT) will be better

>
> -/* All cccr we don't use. */
> -static int p4_unused_cccr[NUM_UNUSED_CCCRS] = {
> - MSR_P4_BPU_CCCR1, MSR_P4_BPU_CCCR3,
> - MSR_P4_MS_CCCR1, MSR_P4_MS_CCCR3,
> - MSR_P4_FLAME_CCCR1, MSR_P4_FLAME_CCCR3,
> - MSR_P4_IQ_CCCR0, MSR_P4_IQ_CCCR1,
> - MSR_P4_IQ_CCCR2, MSR_P4_IQ_CCCR3
> -};
> -
> /* p4 event codes in libop/op_event.h are indices into this table. */
>
> static struct p4_event_binding p4_events[NUM_EVENTS] = {
> @@ -372,6 +365,8 @@ static struct p4_event_binding p4_events
> #define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
> #define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
>
> +#define CTRL_IS_RESERVED(msrs,c) (msrs->controls[(c)].addr ? 1 : 0)
> +#define CTR_IS_RESERVED(msrs,c) (msrs->counters[(c)].addr ? 1 : 0)
> #define CTR_READ(l,h,i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h));} while (0)
> #define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0)
> #define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
> @@ -401,29 +396,34 @@ static unsigned long reset_value[NUM_COU
> static void p4_fill_in_addresses(struct op_msrs * const msrs)
> {
> unsigned int i;
> - unsigned int addr, stag;
> + unsigned int addr, cccraddr, stag;
>
> setup_num_counters();
> stag = get_stagger();
>
> - /* the counter registers we pay attention to */
> + /* initialize some registers */
> for (i = 0; i < num_counters; ++i) {
> - msrs->counters[i].addr =
> - p4_counters[VIRT_CTR(stag, i)].counter_address;
> + msrs->counters[i].addr = 0;
> }
> -
> - /* FIXME: bad feeling, we don't save the 10 counters we don't use. */
> -
> - /* 18 CCCR registers */
> - for (i = 0, addr = MSR_P4_BPU_CCCR0 + stag;
> - addr <= MSR_P4_IQ_CCCR5; ++i, addr += addr_increment()) {
> - msrs->controls[i].addr = addr;
> + for (i = 0; i < num_controls; ++i) {
> + msrs->controls[i].addr = 0;
> }
>
> + /* the counter & cccr registers we pay attention to */
> + for (i = 0; i < num_counters; ++i) {
> + addr = p4_counters[VIRT_CTR(stag, i)].counter_address;
> + cccraddr = p4_counters[VIRT_CTR(stag, i)].cccr_address;
> + if (reserve_perfctr_nmi(addr)){

){

> + msrs->counters[i].addr = addr;
> + msrs->controls[i].addr = cccraddr;
> + }
> + }
> +
> /* 43 ESCR registers in three or four discontiguous group */
> for (addr = MSR_P4_BSU_ESCR0 + stag;
> addr < MSR_P4_IQ_ESCR0; ++i, addr += addr_increment()) {
> - msrs->controls[i].addr = addr;
> + if (reserve_evntsel_nmi(addr))
> + msrs->controls[i].addr = addr;
> }
>
> /* no IQ_ESCR0/1 on some models, we save a seconde time BSU_ESCR0/1
> @@ -431,47 +431,57 @@ static void p4_fill_in_addresses(struct
> if (boot_cpu_data.x86_model >= 0x3) {
> for (addr = MSR_P4_BSU_ESCR0 + stag;
> addr <= MSR_P4_BSU_ESCR1; ++i, addr += addr_increment()) {
> - msrs->controls[i].addr = addr;
> + if (reserve_evntsel_nmi(addr))
> + msrs->controls[i].addr = addr;

anyways 'if' opens braces, maybe move init of 'addr' before 'for'

> }
> } else {
> for (addr = MSR_P4_IQ_ESCR0 + stag;
> addr <= MSR_P4_IQ_ESCR1; ++i, addr += addr_increment()) {
> - msrs->controls[i].addr = addr;
> + if (reserve_evntsel_nmi(addr))
> + msrs->controls[i].addr = addr;
> }
> }
>
> for (addr = MSR_P4_RAT_ESCR0 + stag;
> addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
> - msrs->controls[i].addr = addr;
> + if (reserve_evntsel_nmi(addr))
> + msrs->controls[i].addr = addr;
> }
>
> for (addr = MSR_P4_MS_ESCR0 + stag;
> addr <= MSR_P4_TC_ESCR1; ++i, addr += addr_increment()) {
> - msrs->controls[i].addr = addr;
> + if (reserve_evntsel_nmi(addr))
> + msrs->controls[i].addr = addr;
> }
>
> for (addr = MSR_P4_IX_ESCR0 + stag;
> addr <= MSR_P4_CRU_ESCR3; ++i, addr += addr_increment()) {
> - msrs->controls[i].addr = addr;
> + if (reserve_evntsel_nmi(addr))
> + msrs->controls[i].addr = addr;
> }
>
> /* there are 2 remaining non-contiguously located ESCRs */
>
> if (num_counters == NUM_COUNTERS_NON_HT) {
> /* standard non-HT CPUs handle both remaining ESCRs*/
> - msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
> - msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
> + if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5))
> + msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
> + if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
> + msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
>
> } else if (stag == 0) {

if (!stag)

> /* HT CPUs give the first remainder to the even thread, as
> the 32nd control register */
> - msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
> + if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR4))
> + msrs->controls[i++].addr = MSR_P4_CRU_ESCR4;
>
> } else {
> /* and two copies of the second to the odd thread,
> for the 22st and 23nd control registers */
> - msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
> - msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
> + if (reserve_evntsel_nmi(MSR_P4_CRU_ESCR5)) {
> + msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
> + msrs->controls[i++].addr = MSR_P4_CRU_ESCR5;
> + }
> }
> }
>
> @@ -544,7 +554,6 @@ static void p4_setup_ctrs(struct op_msrs
> {
> unsigned int i;
> unsigned int low, high;
> - unsigned int addr;
> unsigned int stag;
>
> stag = get_stagger();
> @@ -557,59 +566,24 @@ static void p4_setup_ctrs(struct op_msrs
>
> /* clear the cccrs we will use */
> for (i = 0 ; i < num_counters ; i++) {
> + if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
> + continue;
> rdmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
> CCCR_CLEAR(low);
> CCCR_SET_REQUIRED_BITS(low);
> wrmsr(p4_counters[VIRT_CTR(stag, i)].cccr_address, low, high);
> }
>
> - /* clear cccrs outside our concern */
> - for (i = stag ; i < NUM_UNUSED_CCCRS ; i += addr_increment()) {
> - rdmsr(p4_unused_cccr[i], low, high);
> - CCCR_CLEAR(low);
> - CCCR_SET_REQUIRED_BITS(low);
> - wrmsr(p4_unused_cccr[i], low, high);
> - }
> -
> /* clear all escrs (including those outside our concern) */
> - for (addr = MSR_P4_BSU_ESCR0 + stag;
> - addr < MSR_P4_IQ_ESCR0; addr += addr_increment()) {
> - wrmsr(addr, 0, 0);
> - }
> -
> - /* On older models clear also MSR_P4_IQ_ESCR0/1 */
> - if (boot_cpu_data.x86_model < 0x3) {
> - wrmsr(MSR_P4_IQ_ESCR0, 0, 0);
> - wrmsr(MSR_P4_IQ_ESCR1, 0, 0);
> - }
> -
> - for (addr = MSR_P4_RAT_ESCR0 + stag;
> - addr <= MSR_P4_SSU_ESCR0; ++i, addr += addr_increment()) {
> - wrmsr(addr, 0, 0);
> - }
> -
> - for (addr = MSR_P4_MS_ESCR0 + stag;
> - addr <= MSR_P4_TC_ESCR1; addr += addr_increment()){
> - wrmsr(addr, 0, 0);
> - }
> -
> - for (addr = MSR_P4_IX_ESCR0 + stag;
> - addr <= MSR_P4_CRU_ESCR3; addr += addr_increment()){
> - wrmsr(addr, 0, 0);
> + for (i = num_counters; i < num_controls; i++) {
> + if (unlikely(!CTRL_IS_RESERVED(msrs,i)))
> + continue;
> + wrmsr(msrs->controls[i].addr, 0, 0);
> }
>
> - if (num_counters == NUM_COUNTERS_NON_HT) {
> - wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
> - wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
> - } else if (stag == 0) {
> - wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
> - } else {
> - wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
> - }
> -
> /* setup all counters */
> for (i = 0 ; i < num_counters ; ++i) {
> - if (counter_config[i].enabled) {
> + if ((counter_config[i].enabled) && (CTRL_IS_RESERVED(msrs,i))) {
> reset_value[i] = counter_config[i].count;
> pmc_setup_one_p4_counter(i);
> CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
> @@ -696,12 +670,32 @@ static void p4_stop(struct op_msrs const
> stag = get_stagger();
>
> for (i = 0; i < num_counters; ++i) {
> + if (!reset_value[i])
> + continue;
> CCCR_READ(low, high, VIRT_CTR(stag, i));
> CCCR_SET_DISABLE(low);
> CCCR_WRITE(low, high, VIRT_CTR(stag, i));
> }
> }
>
> +static void p4_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(msrs->counters[i].addr);
> + }
> + /* some of the control registers are specially reserved in
> + * conjunction with the counter registers (hence the starting offset).
> + * This saves a few bits.
> + */
> + for (i = num_counters ; i < num_controls ; ++i) {
> + if (CTRL_IS_RESERVED(msrs,i))
> + release_evntsel_nmi(msrs->controls[i].addr);
> + }
> +}
> +
>
> #ifdef CONFIG_SMP
> struct op_x86_model_spec const op_p4_ht2_spec = {
> @@ -711,7 +705,8 @@ struct op_x86_model_spec const op_p4_ht2
> .setup_ctrs = &p4_setup_ctrs,
> .check_ctrs = &p4_check_ctrs,
> .start = &p4_start,
> - .stop = &p4_stop
> + .stop = &p4_stop,
> + .shutdown = &p4_shutdown
> };
> #endif
>
> @@ -722,5 +717,6 @@ struct op_x86_model_spec const op_p4_spe
> .setup_ctrs = &p4_setup_ctrs,
> .check_ctrs = &p4_check_ctrs,
> .start = &p4_start,
> - .stop = &p4_stop
> + .stop = &p4_stop,
> + .shutdown = &p4_shutdown
> };
> Index: linux/arch/i386/oprofile/op_model_ppro.c
> ===================================================================
> --- linux.orig/arch/i386/oprofile/op_model_ppro.c
> +++ linux/arch/i386/oprofile/op_model_ppro.c
> @@ -22,10 +22,12 @@
> #define NUM_COUNTERS 2
> #define NUM_CONTROLS 2
>
> +#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, -(u32)(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))
> @@ -41,11 +43,21 @@ static unsigned long reset_value[NUM_COU
>
> static void ppro_fill_in_addresses(struct op_msrs * const msrs)
> {
> - msrs->counters[0].addr = MSR_P6_PERFCTR0;
> - msrs->counters[1].addr = MSR_P6_PERFCTR1;
> + int i;
> +
> + for (i=0; i < NUM_COUNTERS; i++) {
> + if (reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i))
> + msrs->counters[i].addr = MSR_P6_PERFCTR0 + i;
> + else
> + msrs->counters[i].addr = 0;
> + }
>
> - msrs->controls[0].addr = MSR_P6_EVNTSEL0;
> - msrs->controls[1].addr = MSR_P6_EVNTSEL1;
> + for (i=0; i < NUM_CONTROLS; i++) {
> + if (reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i))
> + msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i;
> + else
> + msrs->controls[i].addr = 0;
> + }
> }
>
>
> @@ -56,6 +68,8 @@ static void ppro_setup_ctrs(struct op_ms
>
> /* 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);
> @@ -63,12 +77,14 @@ static void ppro_setup_ctrs(struct op_ms
>
> /* 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);
> @@ -81,6 +97,8 @@ static void ppro_setup_ctrs(struct op_ms
> CTRL_SET_UM(low, counter_config[i].unit_mask);
> CTRL_SET_EVENT(low, counter_config[i].event);
> CTRL_WRITE(low, high, msrs, i);
> + } else {
> + reset_value[i] = 0;
> }
> }
> }
> @@ -93,6 +111,8 @@ static int ppro_check_ctrs(struct pt_reg
> 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);
> @@ -118,18 +138,38 @@ static int ppro_check_ctrs(struct pt_reg
> static void ppro_start(struct op_msrs const * const msrs)
> {
> unsigned int low,high;
> - CTRL_READ(low, high, msrs, 0);
> - CTRL_SET_ACTIVE(low);
> - CTRL_WRITE(low, high, msrs, 0);
> +
> + if (reset_value[0]) {
> + CTRL_READ(low, high, msrs, 0);
> + CTRL_SET_ACTIVE(low);
> + CTRL_WRITE(low, high, msrs, 0);
> + }
> }
>
>
> static void ppro_stop(struct op_msrs const * const msrs)
> {
> unsigned int low,high;
> - CTRL_READ(low, high, msrs, 0);
> - CTRL_SET_INACTIVE(low);
> - CTRL_WRITE(low, high, msrs, 0);
> +
> + if (reset_value[0]) {
> + CTRL_READ(low, high, msrs, 0);
> + CTRL_SET_INACTIVE(low);
> + CTRL_WRITE(low, high, msrs, 0);
> + }
> +}
> +
> +static void ppro_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_P6_PERFCTR0 + i);
> + }
> + for (i = 0 ; i < NUM_CONTROLS ; ++i) {
> + if (CTRL_IS_RESERVED(msrs,i))
> + release_evntsel_nmi(MSR_P6_EVNTSEL0 + i);
> + }
> }
>
>
> @@ -140,5 +180,6 @@ struct op_x86_model_spec const op_ppro_s
> .setup_ctrs = &ppro_setup_ctrs,
> .check_ctrs = &ppro_check_ctrs,
> .start = &ppro_start,
> - .stop = &ppro_stop
> + .stop = &ppro_stop,
> + .shutdown = &ppro_shutdown
> };
> Index: linux/arch/i386/oprofile/op_x86_model.h
> ===================================================================
> --- linux.orig/arch/i386/oprofile/op_x86_model.h
> +++ linux/arch/i386/oprofile/op_x86_model.h
> @@ -40,6 +40,7 @@ struct op_x86_model_spec {
> struct op_msrs const * const msrs);
> void (*start)(struct op_msrs const * const msrs);
> void (*stop)(struct op_msrs const * const msrs);
> + void (*shutdown)(struct op_msrs const * const msrs);
> };
>
> extern struct op_x86_model_spec const op_ppro_spec;

i hope code works the way it should ;D

---
-o--=O`C
#oo'L O
<___=E M