Sorry, I neglected to attach the patch to the previous email.  Here it is.


Corey Ashford wrote:
Stephane,

Here is a new version of the patch without the spin locks. I tried it out and it seems to work fine without the locks, so I have dropped them from this version.

Due to the problems with pmu_ctx mentioned in the other email, I have not made the simplification you suggested.

If we can figure out a way to make that work, I will post another patch with that change.

I hope this new version is acceptable.

Thanks for your help and consideration of this new patch,

- Corey

Corey Ashford
Software Engineer
IBM Linux Technology Center, Linux Toolchain
Beaverton, OR
503-578-3507
cjash...@us.ibm.com


------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
perfmon2-devel mailing list
perfmon2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/perfmon2-devel

--
Regards,

- Corey

Corey Ashford
Software Engineer
IBM Linux Technology Center, Linux Toolchain
Beaverton, OR
503-578-3507
cjash...@us.ibm.com
diff --git a/arch/powerpc/perfmon/perfmon_power6.c 
b/arch/powerpc/perfmon/perfmon_power6.c
index 7882feb..fb4cd14 100644
--- a/arch/powerpc/perfmon/perfmon_power6.c
+++ b/arch/powerpc/perfmon/perfmon_power6.c
@@ -25,6 +25,8 @@
 #include <linux/module.h>
 #include <linux/perfmon_kern.h>
 
+#include <linux/hrtimer.h>
+
 MODULE_AUTHOR("Corey Ashford <cjash...@us.ibm.com>");
 MODULE_DESCRIPTION("POWER6 PMU description table");
 MODULE_LICENSE("GPL");
@@ -71,10 +73,17 @@ static struct pfm_regmap_desc pfm_power6_pmd_desc[] = {
 
 #define PFM_PM_NUM_PMDS        ARRAY_SIZE(pfm_power6_pmd_desc)
 
-u32 pmc5_start_save[NR_CPUS];
-u32 pmc6_start_save[NR_CPUS];
+struct pmc5_6_per_cpu {
+       u32 pmc5_start_save;
+       u32 pmc6_start_save;
+       struct pfm_arch_context *ctx_arch;
+       struct hrtimer timer;
+};
+
+static DEFINE_PER_CPU(struct pmc5_6_per_cpu, pmc5_6_percpu);
+
+#define PMC5_6_PERCPU __get_cpu_var(pmc5_6_percpu)
 
-static struct timer_list pmc5_6_update[NR_CPUS];
 u64 enable_cntrs_cnt;
 u64 disable_cntrs_cnt;
 u64 call_delta;
@@ -84,9 +93,9 @@ u64 pm1_4_interrupt;
  * timer.
  */
 struct pfm_arch_context *pmc5_6_ctx_arch[NR_CPUS];
-long int update_time;
+ktime_t update_time;
 
-static void delta(int cpu_num, struct pfm_arch_context *ctx_arch)
+static void delta(struct pfm_arch_context *ctx_arch)
 {
        u32 tmp5, tmp6;
 
@@ -100,22 +109,21 @@ static void delta(int cpu_num, struct pfm_arch_context 
*ctx_arch)
         * arithmetic for the deltas to come out correct (especially in the
         * presence of a 32-bit counter wrap).
         */
-       ctx_arch->powergs_pmc5 += (u64)(tmp5 - pmc5_start_save[cpu_num]);
-       ctx_arch->powergs_pmc6 += (u64)(tmp6 - pmc6_start_save[cpu_num]);
+       ctx_arch->powergs_pmc5 += (u64)(tmp5 - PMC5_6_PERCPU.pmc5_start_save);
+       ctx_arch->powergs_pmc6 += (u64)(tmp6 - PMC5_6_PERCPU.pmc6_start_save);
 
-       pmc5_start_save[cpu_num] = tmp5;
-       pmc6_start_save[cpu_num] = tmp6;
-
-       return;
+       PMC5_6_PERCPU.pmc5_start_save = tmp5;
+       PMC5_6_PERCPU.pmc6_start_save = tmp6;
 }
 
 
-static void pmc5_6_updater(unsigned long cpu_num)
+static enum hrtimer_restart pmc5_6_updater(struct hrtimer *hrtimer)
 {
        /* update the virtual pmd 5 and pmd 6 counters */
 
-       delta(cpu_num, pmc5_6_ctx_arch[cpu_num]);
-       mod_timer(&pmc5_6_update[cpu_num], jiffies + update_time);
+       delta(PMC5_6_PERCPU.ctx_arch);
+        hrtimer_forward_now(&PMC5_6_PERCPU.timer, update_time);
+        return HRTIMER_RESTART;
 }
 
 
@@ -185,7 +193,6 @@ static void pfm_power6_write_pmd(unsigned int cnum, u64 
value)
 static u64 pfm_power6_sread(struct pfm_context *ctx, unsigned int cnum)
 {
        struct pfm_arch_context *ctx_arch = pfm_ctx_arch(ctx);
-       int cpu_num = smp_processor_id();
 
        /* On POWER 6 PMC5 and PMC6 are implemented as
         * virtual counters.  See comment in pfm_power6_pmd_desc
@@ -194,11 +201,11 @@ static u64 pfm_power6_sread(struct pfm_context *ctx, 
unsigned int cnum)
 
        switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) {
        case SPRN_PMC5:
-               return ctx_arch->powergs_pmc5 + (u64)((u32)mfspr(SPRN_PMC5) - 
pmc5_start_save[cpu_num]);
+               return ctx_arch->powergs_pmc5 + (u64)((u32)mfspr(SPRN_PMC5) - 
PMC5_6_PERCPU.pmc5_start_save);
                break;
 
        case SPRN_PMC6:
-               return ctx_arch->powergs_pmc6 + (u64)((u32)mfspr(SPRN_PMC6) - 
pmc6_start_save[cpu_num]);
+               return ctx_arch->powergs_pmc6 + (u64)((u32)mfspr(SPRN_PMC6) - 
PMC5_6_PERCPU.pmc6_start_save);
                break;
 
        case PFM_DELTA_TB:
@@ -222,16 +229,15 @@ void pfm_power6_swrite(struct pfm_context *ctx, unsigned 
int cnum,
        u64 val)
 {
        struct pfm_arch_context *ctx_arch = pfm_ctx_arch(ctx);
-       int cpu_num = smp_processor_id();
 
        switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) {
        case SPRN_PMC5:
-               pmc5_start_save[cpu_num] = mfspr(SPRN_PMC5);
+               PMC5_6_PERCPU.pmc5_start_save = mfspr(SPRN_PMC5);
                ctx_arch->powergs_pmc5 = val;
                break;
 
        case SPRN_PMC6:
-               pmc6_start_save[cpu_num] = mfspr(SPRN_PMC6);
+               PMC5_6_PERCPU.pmc6_start_save = mfspr(SPRN_PMC6);
                ctx_arch->powergs_pmc6 = val;
                break;
 
@@ -284,7 +290,6 @@ static void pfm_power6_enable_counters(struct pfm_context 
*ctx,
 {
 
        unsigned int i, max_pmc;
-       int cpu_num = smp_processor_id();
        struct pfm_arch_context *ctx_arch;
 
        enable_cntrs_cnt++;
@@ -300,8 +305,8 @@ static void pfm_power6_enable_counters(struct pfm_context 
*ctx,
                        pfm_power6_write_pmc(i - 1, set->pmcs[i - 1]);
 
        /* save current free running HW event count */
-       pmc5_start_save[cpu_num] = mfspr(SPRN_PMC5);
-       pmc6_start_save[cpu_num] = mfspr(SPRN_PMC6);
+       PMC5_6_PERCPU.pmc5_start_save = mfspr(SPRN_PMC5);
+       PMC5_6_PERCPU.pmc6_start_save = mfspr(SPRN_PMC6);
 
        ctx_arch->delta_purr_start = mfspr(SPRN_PURR);
 
@@ -314,19 +319,11 @@ static void pfm_power6_enable_counters(struct pfm_context 
*ctx,
        /* Start kernel timer for this cpu to periodically update
         * the virtual counters.
         */
-       init_timer(&pmc5_6_update[cpu_num]);
-       pmc5_6_update[cpu_num].function = pmc5_6_updater;
-       pmc5_6_update[cpu_num].data = (unsigned long) cpu_num;
-       pmc5_6_update[cpu_num].expires = jiffies + update_time;
-       /* context for this timer, timer will be removed if context
-        * is switched because the counters will be stopped first.
-        * NEEDS WORK, I think this is all ok, a little concerned about a
-        * race between the kernel timer going off right as the counters
-        * are being stopped and the context switching.  Need to think
-        * about this.
-        */
-       pmc5_6_ctx_arch[cpu_num] = ctx_arch;
-       add_timer(&pmc5_6_update[cpu_num]);
+       PMC5_6_PERCPU.ctx_arch = ctx_arch;
+
+       if (! hrtimer_active(&PMC5_6_PERCPU.timer)) {
+               hrtimer_start(&PMC5_6_PERCPU.timer, update_time, 
HRTIMER_MODE_REL);
+       }
 }
 
 /**
@@ -337,7 +334,6 @@ static void pfm_power6_disable_counters(struct pfm_context 
*ctx,
                                        struct pfm_event_set *set)
 {
        struct pfm_arch_context *ctx_arch;
-       int cpu_num = smp_processor_id();
 
        disable_cntrs_cnt++;
 
@@ -345,14 +341,14 @@ static void pfm_power6_disable_counters(struct 
pfm_context *ctx,
        mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
        asm volatile ("sync");
 
-       /* delete kernel update timer */
-       del_timer_sync(&pmc5_6_update[cpu_num]);
+       /* cancel the pmc5/6 update timer */
+       hrtimer_cancel(&PMC5_6_PERCPU.timer);
 
        /* Update the virtual pmd 5 and 6 counters from the free running
         * HW counters
         */
        ctx_arch = pfm_ctx_arch(ctx);
-       delta(cpu_num, ctx_arch);
+       delta(ctx_arch);
 
        ctx_arch->delta_tb +=
                (((u64)mfspr(SPRN_TBRU) << 32) | mfspr(SPRN_TBRL))
@@ -480,6 +476,13 @@ static struct pfm_pmu_config pfm_power6_pmu_conf = {
        .owner = THIS_MODULE
 };
 
+static void init_pmc5_6_per_cpu(void *info) {
+       hrtimer_init(&PMC5_6_PERCPU.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       PMC5_6_PERCPU.timer.function = pmc5_6_updater;
+       PMC5_6_PERCPU.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
+}
+
+
 static int __init pfm_power6_pmu_init_module(void)
 {
        int ret;
@@ -498,15 +501,22 @@ static int __init pfm_power6_pmu_init_module(void)
         */
 
 # define MAX_EVENT_RATE (ppc_proc_freq * 2)
-
-       /*
-        * Calculate the time, in jiffies, it takes for event counter 5 or
-        * 6 to completely wrap when counting at the max event rate, and
-        * then figure on sampling at twice that rate.
-        */
-       update_time = (((unsigned long)HZ * OVERFLOW_VALUE)
-                      / ((unsigned long)MAX_EVENT_RATE)) / 2;
-
+# define SAFETY_FACTOR 2
+       {
+               u64 update_time_ns;
+
+               /*
+                * Calculate the time, in seconds + nanoseconds, it takes for
+                * counter 5 or 6 to completely wrap when counting at the max
+                * event rate, and then figure on sampling at half that period.
+                */
+               update_time_ns = ((NSEC_PER_SEC * OVERFLOW_VALUE) /
+                   MAX_EVENT_RATE) / SAFETY_FACTOR;
+               update_time = ktime_set(
+                   update_time_ns / NSEC_PER_SEC,
+                   update_time_ns % NSEC_PER_SEC);
+       }
+       on_each_cpu(init_pmc5_6_per_cpu, NULL, 1);
        ret =  pfm_pmu_register(&pfm_power6_pmu_conf);
        return ret;
 }
------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
perfmon2-devel mailing list
perfmon2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/perfmon2-devel

Reply via email to