Takashi,
This patch does not apply cleanly on my perfmon_cell.c.
Could you check against the one in the GIT tree?
Also, is you mailer somehow formatting to 80-columns?
Some lines of the patch are malformed due to insertion
of carriage return.
On Thu, Nov 01, 2007 at 04:42:26PM +0900, TakashiYamamoto wrote:
> Hello,
>
> Here is the Cell PPU HW thread depended event support.
> Kevin-san, Azuma-san, please review it!
>
> 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 | 204
> +++++++++++++++++++++++++++++-------
> 1 file changed, 165 insertions(+), 39 deletions(-)
>
> Index: linux-2.6/arch/powerpc/perfmon/perfmon_cell.c
> ===================================================================
> --- linux-2.6.orig/arch/powerpc/perfmon/perfmon_cell.c
> +++ linux-2.6/arch/powerpc/perfmon/perfmon_cell.c
> @@ -18,7 +18,7 @@
> * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> * General Public License for more details.
> *
> - * You should have received a copy of the GNU General Public License
> + * You should have received a copy of the GNU XSGeneral Public License
> * along with this program; if not, write to the Free Software
> * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
> * 02111-1307 USA
> @@ -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/
--
-Stephane
_______________________________________________
perfmon mailing list
[email protected]
http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/