Hello,

> Takashi,
> 
> This patch does not apply cleanly on my perfmon_cell.c.
> Could you check against the one in the GIT tree?

Yes.

> Also, is you mailer somehow formatting to 80-columns?
> Some lines of the patch are malformed due to insertion
> of carriage return.

My mailer formed it to 76-culums. I changed it.
I checked this patch againt the GIT tree
(commit 75c9e70942a28aa9366f969930305f172d2d2e0b) again.
Please use this patch!

And I want to wait for comments againt this patch for a while.

Thanks.
Takashi Yamamoto.

--------------------------------------------------------------
Cell PPU IU(Instruction Unit)/XU(Execution Unit) event support in 
per-thread(task) mode.

In per-thread mode, the PPU IU/XU events should be measured 
while the target SW thread(task) runs on the target HW thread. 
To realize that, the counter enable bit of the pmX_control PMC is
manipulated in pfm_cell_restore_pmcs().

Signed-off-by: Takashi Yamamoto <TakashiA.Yamamoto at jp.sony.com>
---
 arch/powerpc/perfmon/perfmon_cell.c |  202 +++++++++++++++++++++++++++++-------
 1 file changed, 164 insertions(+), 38 deletions(-)

--- a/arch/powerpc/perfmon/perfmon_cell.c
+++ b/arch/powerpc/perfmon/perfmon_cell.c
@@ -96,7 +96,9 @@ static struct pfm_regmap_desc pfm_cell_p
 };
 #define PFM_PM_NUM_PMCS        ARRAY_SIZE(pfm_cell_pmc_desc)
 
-#define CELL_PMC_PM_STATUS 20
+#define CELL_PMC_GROUP_CONTROL    16
+#define CELL_PMC_PM_STATUS        20
+
 /*
  * Mapping from Perfmon logical data counters to Cell hardware counters.
  */
@@ -112,6 +114,19 @@ static struct pfm_regmap_desc pfm_cell_p
 };
 #define PFM_PM_NUM_PMDS        ARRAY_SIZE(pfm_cell_pmd_desc)
 
+#define PFM_EVENT_PMC_BUS_WORD(x)      (((x) >> 48) & 0x00ff)
+#define PFM_EVENT_PMC_FULL_SIGNAL_NUMBER(x) ((x) & 0xffffffff)
+#define PFM_EVENT_PMC_SIGNAL_GROUP(x) (((x) & 0xffffffff) / 100)
+#define PFM_PM_CTR_INPUT_MUX_BIT(pm07_control) (((pm07_control) >> 26) & 0x1f)
+#define PFM_PM_CTR_INPUT_MUX_GROUP_INDEX(pm07_control) ((pm07_control) >> 31)
+#define PFM_GROUP_CONTROL_GROUP0_WORD(grp_ctrl) ((grp_ctrl) >> 30)
+#define PFM_GROUP_CONTROL_GROUP1_WORD(grp_ctrl) (((grp_ctrl) >> 28) & 0x3)
+#define PFM_NUM_OF_GROUPS 2
+#define PFM_PPU_IU1_THREAD1_BASE_BIT 19
+#define PFM_PPU_XU_THREAD1_BASE_BIT  16
+#define PFM_COUNTER_CTRL_PMC_PPU_THREAD0 0x100000000ULL
+#define PFM_COUNTER_CTRL_PMC_PPU_THREAD1 0x200000000ULL
+
 /*
  * Debug-bus signal handling.
  *
@@ -691,6 +706,72 @@ static void pfm_cell_disable_counters(st
                reset_signals(smp_processor_id());
 }
 
+/*
+ * Return the thread id of the specified ppu signal.
+ */
+static inline u32 get_target_ppu_thread_id(u32 group, u32 bit)
+{
+       if ((group == SIG_GROUP_PPU_IU1 &&
+            bit < PFM_PPU_IU1_THREAD1_BASE_BIT) ||
+           (group == SIG_GROUP_PPU_XU &&
+            bit < PFM_PPU_XU_THREAD1_BASE_BIT))
+               return 0;
+       else
+               return 1;
+}
+
+/*
+ * Return whether the specified counter is for PPU signal group.
+ */
+static inline int is_counter_for_ppu_sig_grp(u32 counter_control, u32 sig_grp)
+{
+       if (!(counter_control & CBE_PM_CTR_INPUT_CONTROL) &&
+           (counter_control & CBE_PM_CTR_ENABLE) &&
+           ((sig_grp == SIG_GROUP_PPU_IU1) || (sig_grp == SIG_GROUP_PPU_XU)))
+               return 1;
+       else
+               return 0;
+}
+
+/*
+ * Search ppu signal groups.
+ */
+static int get_ppu_signal_groups(struct pfm_event_set *set,
+                                u32 *ppu_sig_grp0, u32 *ppu_sig_grp1)
+{
+       u64 pm_event, *used_pmcs = set->used_pmcs;
+       int i, j;
+       u32 grp0_wd, grp1_wd, wd, sig_grp;
+
+       *ppu_sig_grp0 = 0;
+       *ppu_sig_grp1 = 0;
+       grp0_wd = PFM_GROUP_CONTROL_GROUP0_WORD(
+               set->pmcs[CELL_PMC_GROUP_CONTROL]);
+       grp1_wd = PFM_GROUP_CONTROL_GROUP1_WORD(
+               set->pmcs[CELL_PMC_GROUP_CONTROL]);
+
+       for (i = 0, j = 0; (i < NR_CTRS) && (j < PFM_NUM_OF_GROUPS); i++) {
+               if (test_bit(i + NR_CTRS, used_pmcs)) {
+                       pm_event = set->pmcs[i + NR_CTRS];
+                       wd = PFM_EVENT_PMC_BUS_WORD(pm_event);
+                       sig_grp = PFM_EVENT_PMC_SIGNAL_GROUP(pm_event);
+                       if ((sig_grp == SIG_GROUP_PPU_IU1) ||
+                           (sig_grp == SIG_GROUP_PPU_XU)) {
+
+                               if (wd == grp0_wd && *ppu_sig_grp0 == 0) {
+                                       *ppu_sig_grp0 = sig_grp;
+                                       j++;
+                               } else if (wd == grp1_wd &&
+                                          *ppu_sig_grp1 == 0) {
+                                       *ppu_sig_grp1 = sig_grp;
+                                       j++;
+                               }
+                       }
+               }
+       }
+       return j;
+}
+
 /**
  * pfm_cell_restore_pmcs
  *
@@ -699,56 +780,54 @@ static void pfm_cell_disable_counters(st
  * individually (as is done in other architectures), but that results in
  * multiple RTAS calls. As an optimization, we will setup the RTAS argument
  * array so we can do all event-control registers in one RTAS call.
+ *
+ * In per-thread mode,
+ * The counter enable bit of the pmX_control PMC is enabled while the target
+ * task runs on the target HW thread.
  **/
 void pfm_cell_restore_pmcs(struct pfm_event_set *set)
 {
-       struct cell_rtas_arg signals[NR_CTRS];
-       u64 value, *used_pmcs = set->used_pmcs;
-       int i, rc, num_used = 0, cpu = smp_processor_id();
-       s32 signal_number;
+       u64 ctr_ctrl;
+       u64 *used_pmcs = set->used_pmcs;
+       int i;
+       int cpu = smp_processor_id();
+       u32 current_th_id;
        struct pfm_cell_platform_pmu_info *info =
                ((struct pfm_arch_pmu_info *)
                 (pfm_pmu_conf->arch_info))->platform_info;
 
-       memset(signals, 0, sizeof(signals));
-
        for (i = 0; i < NR_CTRS; i++) {
-               /* Write the per-counter control register. If the PMC is not
-                * in use, then it will simply clear the register, which will
-                * disable the associated counter.
-                */
-               info->write_pm07_control(cpu, i, set->pmcs[i]);
+               ctr_ctrl = set->pmcs[i];
 
-               /* Set up the next RTAS array entry for this counter. Only
-                * include pm07_event registers that are in use by this set
-                * so the RTAS call doesn't have to process blank array entries.
-                */
-               if (!test_bit(i + NR_CTRS, used_pmcs)) {
-                       continue;
-               }
+               if (ctr_ctrl & PFM_COUNTER_CTRL_PMC_PPU_THREAD0) {
+                       current_th_id = info->get_hw_thread_id(cpu);
 
-               value = set->pmcs[i + NR_CTRS];
-               signal_number = RTAS_SIGNAL_NUMBER(value);
-               if (!signal_number) {
-                       /* Don't include counters that are counting cycles. */
-                       continue;
+                       /*
+                        * Set the counter enable bit down if the current
+                        * HW thread is NOT 0
+                        **/
+                       if (current_th_id)
+                               ctr_ctrl = ctr_ctrl & ~CBE_PM_CTR_ENABLE;
+
+               } else if (ctr_ctrl & PFM_COUNTER_CTRL_PMC_PPU_THREAD1) {
+                       current_th_id = info->get_hw_thread_id(cpu);
+
+                       /*
+                        * Set the counter enable bit down if the current
+                        * HW thread is 0
+                        **/
+                       if (!current_th_id)
+                               ctr_ctrl = ctr_ctrl & ~CBE_PM_CTR_ENABLE;
                }
 
-               signals[num_used].cpu = RTAS_CPU(cpu);
-               signals[num_used].sub_unit = RTAS_SUB_UNIT(value);
-               signals[num_used].bus_word = 1 << RTAS_BUS_WORD(value);
-               signals[num_used].signal_group = signal_number / 100;
-               signals[num_used].bit = signal_number % 100;
-               num_used++;
-       }
-
-       rc = activate_signals(signals, num_used);
-       if (rc) {
-               PFM_WARN("Error calling activate_signal(): %d\n", rc);
-               /* FIX: We will also need this routine to be able to return
-                * an error if Stephane agrees to change pfm_arch_write_pmc
-                * to return an error.
+               /* Write the per-counter control register. If the PMC is not
+                * in use, then it will simply clear the register, which will
+                * disable the associated counter.
                 */
+               info->write_pm07_control(cpu, i, ctr_ctrl);
+
+               if (test_bit(i + NR_CTRS, used_pmcs))
+                       write_pm07_event(cpu, 0, set->pmcs[i + NR_CTRS]);
        }
 
        /* Write all the global PMCs. Need to call pfm_cell_write_pmc()
@@ -760,6 +839,52 @@ void pfm_cell_restore_pmcs(struct pfm_ev
 }
 
 /**
+ * pfm_cell_load_context
+ *
+ * In per-thread mode,
+ *  The pmX_control PMCs which are used for PPU IU/XU event are marked with
+ *  the thread id(PFM_COUNTER_CTRL_PMC_PPU_THREAD0/THREAD1).
+ **/
+static int pfm_cell_load_context(struct pfm_context *ctx,
+                                struct pfm_event_set *set,
+                                struct task_struct *task)
+{
+       int i;
+       u32 ppu_sig_grp[PFM_NUM_OF_GROUPS] = {SIG_GROUP_NONE, SIG_GROUP_NONE};
+       u32 bit;
+       int grp_index;
+       u32 target_th_id;
+       int ppu_sig_num = 0;
+
+       if (!ctx->flags.system)
+               ppu_sig_num = get_ppu_signal_groups(set, &ppu_sig_grp[0],
+                                                   &ppu_sig_grp[1]);
+
+       for (i = 0; i < NR_CTRS; i++) {
+               grp_index = PFM_PM_CTR_INPUT_MUX_GROUP_INDEX(set->pmcs[i]);
+               if (ppu_sig_num &&
+                   (ppu_sig_grp[grp_index] != SIG_GROUP_NONE) &&
+                   is_counter_for_ppu_sig_grp(set->pmcs[i],
+                                              ppu_sig_grp[grp_index])) {
+
+                       bit = PFM_PM_CTR_INPUT_MUX_BIT(set->pmcs[i]);
+                       target_th_id = get_target_ppu_thread_id(
+                               ppu_sig_grp[grp_index], bit);
+                       if (!target_th_id)
+                               set->pmcs[i] |=
+                                       PFM_COUNTER_CTRL_PMC_PPU_THREAD0;
+                       else
+                               set->pmcs[i] |=
+                                       PFM_COUNTER_CTRL_PMC_PPU_THREAD1;
+                       PFM_DBG("mark ctr:%d target_thread:%d",
+                               i, target_th_id);
+               }
+       }
+
+       return 0;
+}
+
+/**
  * pfm_cell_unload_context
  *
  * For system-wide contexts and self-monitored contexts, make the RTAS call
@@ -1026,6 +1151,7 @@ static struct pfm_arch_pmu_info pfm_cell
        .get_ovfl_pmds    = pfm_cell_get_ovfl_pmds,
        .restore_pmcs     = pfm_cell_restore_pmcs,
        .ctxswout_thread  = pfm_cell_ctxswout_thread,
+       .load_context     = pfm_cell_load_context,
        .unload_context   = pfm_cell_unload_context,
 };


_______________________________________________
perfmon mailing list
[email protected]
http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/

Reply via email to