This patch changes the interface for the default sample format calls.
Rather then passing two arguments from the context to the hardware
sampler routines, the entire context is passed.  This change simplifies
the call by reducing the number of arguments.  It also provides access
to the other arguments needed by the IBM Cell hardware sampler format.
Note that the call changes for the IBM CELL sampler routins is not 
in this patch.  They are in a separate patch that adds all of the 
CELL support.   

Signed-off-by: Carl Love <[EMAIL PROTECTED]>


Index: linux-2.6.25.ppc64/arch/ia64/perfmon/perfmon_default_smpl.c
===================================================================
--- linux-2.6.25.ppc64.orig/arch/ia64/perfmon/perfmon_default_smpl.c
+++ linux-2.6.25.ppc64/arch/ia64/perfmon/perfmon_default_smpl.c
@@ -108,15 +108,16 @@ static int pfm_default_fmt_init(struct p
        return 0;
 }
 
-static int pfm_default_fmt_handler(void *buf, struct pfm_ovfl_arg *arg,
+static int pfm_default_fmt_handler(struct pfm_context *ctx,
                                   unsigned long ip, u64 tstamp, void *data)
 {
-       struct pfm_default_smpl_hdr *hdr;
+       struct pfm_default_smpl_hdr *hdr = ctx->smpl_addr;
        struct pfm_default_smpl_entry *ent;
        void *cur, *last;
        u64 *e;
        size_t entry_size;
        u16 npmds, i, ovfl_pmd;
+       struct pfm_ovfl_arg *arg = &ctx->ovfl_arg;
 
        hdr         = buf;
        cur         = buf+hdr->hdr_cur_offs;
Index: linux-2.6.25.ppc64/arch/x86/perfmon/perfmon_pebs_core_smpl.c
===================================================================
--- linux-2.6.25.ppc64.orig/arch/x86/perfmon/perfmon_pebs_core_smpl.c
+++ linux-2.6.25.ppc64/arch/x86/perfmon/perfmon_pebs_core_smpl.c
@@ -158,9 +158,11 @@ static int pfm_pebs_core_fmt_init(struct
        return 0;
 }
 
-static int pfm_pebs_core_fmt_handler(void *buf, struct pfm_ovfl_arg *arg,
+static int pfm_pebs_core_fmt_handler(struct pfm_context *ctx,
                               unsigned long ip, u64 tstamp, void *data)
 {
+       void *buf = ctx->smpl_addr;
+       struct pfm_ovfl_arg *arg = &ctx->ovfl_arg;
        struct pfm_pebs_core_smpl_hdr *hdr;
 
        hdr = buf;
Index: linux-2.6.25.ppc64/include/linux/perfmon_fmt.h
===================================================================
--- linux-2.6.25.ppc64.orig/include/linux/perfmon_fmt.h
+++ linux-2.6.25.ppc64/include/linux/perfmon_fmt.h
@@ -29,7 +29,7 @@ typedef int (*fmt_init_t)(struct pfm_con
                          u16 nmpds, void *arg);
 typedef int (*fmt_restart_t)(int is_active, u32 *ovfl_ctrl, void *buf);
 typedef int (*fmt_exit_t)(void *buf);
-typedef int (*fmt_handler_t)(void *buf, struct pfm_ovfl_arg *arg,
+typedef int (*fmt_handler_t)(struct pfm_context *ctx,
                             unsigned long ip, u64 stamp, void *data);
 
 struct pfm_smpl_fmt {
Index: linux-2.6.25.ppc64/perfmon/perfmon_intr.c
===================================================================
--- linux-2.6.25.ppc64.orig/perfmon/perfmon_intr.c
+++ linux-2.6.25.ppc64/perfmon/perfmon_intr.c
@@ -282,8 +282,7 @@ static int pfm_intr_process_smpl_fmt(str
                 */
                start_cycles = sched_clock();
                printk("carll, call format handler\n");
-               ret = (*ctx->smpl_fmt->fmt_handler)(ctx->smpl_addr, ovfl_arg,
-                                                   ip, now, regs);
+               ret = (*ctx->smpl_fmt->fmt_handler)(ctx, ip, now, regs);
                end_cycles = sched_clock();
 
                /*
Index: linux-2.6.25.ppc64/perfmon/perfmon_dfl_smpl.c
===================================================================
--- linux-2.6.25.ppc64.orig/perfmon/perfmon_dfl_smpl.c
+++ linux-2.6.25.ppc64/perfmon/perfmon_dfl_smpl.c
@@ -129,18 +129,20 @@ static int pfm_dfl_fmt_init(struct pfm_c
  *
  * context is locked, interrupts are disabled (no preemption)
  */
-static int pfm_dfl_fmt_handler(void *buf, struct pfm_ovfl_arg *arg,
+static int pfm_dfl_fmt_handler(struct pfm_context *ctx,
                               unsigned long ip, u64 tstamp, void *data)
 {
-       struct pfm_dfl_smpl_hdr *hdr;
+       struct pfm_dfl_smpl_hdr *hdr = ctx->smpl_addr;
        struct pfm_dfl_smpl_entry *ent;
+       struct pfm_ovfl_arg *arg = &ctx->ovfl_arg;
        void *cur, *last;
        u64 *e;
        size_t entry_size, min_size;
        u16 npmds, i;
        u16 ovfl_pmd;
+       void *buf;
 
-       hdr = buf;
+        buf = hdr;
        cur = buf+hdr->hdr_cur_offs;
        last = buf+hdr->hdr_buf_size;
        ovfl_pmd = arg->ovfl_pmd;



-------------------------------------------------------------------------

On Mon, 2008-07-21 at 14:41 +0200, stephane eranian wrote:
> Carl,
> 
> Looked at this while traveling.
> I had not looked at this code in  a very long time.
> 
> I think it would make sense to expose the context to the handler routine and
> to the sampling format as a whole. Your example shows that this may be needed
> because of how the hardware behaves.
> 
> If we do that, then we can highly simplify the interface of
> pfm_fmt_handler() because
> a lot of the information currently passed would become available
> directly from the context.
> Thus, the handler could peek on the context structure to find the
> information it needs.
> In particular, I think we could get rid of the pfm_ovfl_arg structure.
> We could also eliminate
> the smpl_pmds[] array and have the handler build the values directly.
> This would avoid
> one copy (tday: ctx -> smpl_pmds -> sampling buffer).
> 
> Of course this change would break existing sampling formats, but there
> aren't that many
> out there yet. I think it could avoid problems later on.
> 
> 
> 
> On Sat, Jul 19, 2008 at 1:03 AM, stephane eranian
> <[EMAIL PROTECTED]> wrote:
> > Carl,
> >
> > Let me think about this a bit more.
> >
> > But I'd like to comment on your question about passing ctx to 
> > pfm_fmt_handler().
> > The motivation not to expose ctx is to limit the number of structures 
> > exposed
> > to format (kernel modules).  This was we can changed the layout of ctx with
> > no impact on any modules.
> >
> >
> > On Sat, Jul 19, 2008 at 12:36 AM, Carl Love <[EMAIL PROTECTED]> wrote:
> >> Stephane:
> >>
> >> I am updating the Cell perfmon code for the hardware sampling support.
> >> This is code that was in the last CELL SDK release but has not been
> >> pushed into the perfmon2 project.  I am having to update the patch some
> >> as the perfmon2 code has changed.  I ran into an issue with the format
> >> handler routine pfm_cell_hw_smpl_handler().  The function is called as a
> >> result of the scheduler rescheduling the process being monitored by
> >> perfmon.  Specifically, pfm_cell_hw_smpl_handler() is called from the
> >> arch specific call pfm_cell_disable_counters().  Since the hw sampler
> >> function is not passed the context, we have to get the context via
> >>  ctx = __get_cpu_var(pmu_ctx);
> >> Which occurs at line 294 in file  perfmon_cell_hw_smpl.c.
> >> Unfortunately, the ctx that we get via the call does not seem to always
> >> be the correct context.  The result is that when we try to access
> >> ctx->active_set we get a NULL access.  We think the problem is that the
> >> ctxt on the processor has already changed and so we are not accessing
> >> the context that was running which does have an active set.  Digging
> >> through all the code, is is not clear why it is not always correct.  The
> >> correct ctx is passed to the pfm_cell_disable_counters() routine.  It
> >> looks like if we just added the ctx as an argument to the
> >> hw_smpl_handler function then we could pass in the correct ctx from the
> >> pfm_cell_disand could eliminate the __get_cpu_var(pmu_ctx) call.
> >>
> >> Looks like Cell is the only architecture that would use the ctx argument
> >> in the smpl_handler routine.  The perfmon2 code seems to assume that all
> >> of the sampling is based on pmd counter overflows.  For cell, we have
> >> the hardware trace buffer which generates a pmd overflow when it fills.
> >> The trace buffer is 1024 entries.  Since we can't read and restore the
> >> trace buffer, we end up having to call the smpl_handler on each context
> >> switch to save a partial sample. We need to access to the cntxt to do
> >> this.
> >>
> >> Do you think it would be acceptable to add the context to the generic
> >> perfmon fmt_handler() call for use by the Cell architecture?  I would
> >> have to fix the format handler calls for all the other architectures as
> >> well.
> >>
> >> I am attaching the patch if you would like to look at it.  Perhaps there
> >> is another solution then changing the fmt_handler() call.  Any thoughts
> >> would be appreciated.  Thanks.
> >>
> >>                Carl Love
> >>
> >> ----------------------------------------------------------------------
> >>
> >>
> >> This patch contains the Perfmon2 Cell hardware sampling support
> >> changes from the SDK 3.0 code that have not been accepted into
> >> the perfmon2 mainline.  The code comes from following sdk 3.0 patches
> >> 36441_1.diff, 36499.diff, 37225.diff, 38627.diff, 36441_2.diff,
> >> 36859_3.diff, 38625.diff, perfmon2.git.patch.
> >>
> >> Signed-off-by: Carl Love <[EMAIL PROTECTED]>
> >>
> >>
> >> Index: linux-2.6.25.ppc64/include/asm-powerpc/perfmon_cell_hw_smpl.h
> >> ===================================================================
> >> --- /dev/null
> >> +++ linux-2.6.25.ppc64/include/asm-powerpc/perfmon_cell_hw_smpl.h
> >> @@ -0,0 +1,121 @@
> >> +/*
> >> + * Copyright IBM Corp 2007
> >> + *
> >> + * Contributed by Carl Love <[EMAIL PROTECTED]>
> >> + * and Kevin Corry <[EMAIL PROTECTED]>
> >> + *
> >> + * This program is free software; you can redistribute it and/or
> >> + * modify it under the terms of version 2 of the GNU General Public
> >> + * License as published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * 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
> >> + * along with this program; if not, write to the Free Software
> >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
> >> + * 02111-1307 USA
> >> + */
> >> +#ifndef __ASM_POWERPC_PERFMON_CELL_HW_SMPL_H__
> >> +#define __ASM_POWERPC_PERFMON_CELL_HW_SMPL_H__
> >> +
> >> +/**
> >> + * struct pfm_cell_hw_smpl_arg
> >> + *
> >> + * @buf_size: Size of full sampling-buffer (in bytes).
> >> + * @buf_flags: Sampling-buffer-specific flags.
> >> + * @reserved1: Pad to 128-bit boundary.
> >> + *
> >> + * Format specific parameters (passed at context creation).
> >> + **/
> >> +struct pfm_cell_hw_smpl_arg {
> >> +       __u64 buf_size;
> >> +        __u32 buf_flags;
> >> +       __u32 reserved1;
> >> +};
> >> +
> >> +/**
> >> + * struct pfm_cell_hw_smpl_hdr
> >> + *
> >> + * @count: Number of valid sampling-buffer entries.
> >> + * @cur_offset: Offset (in bytes) from the top of the sampling-buffer to 
> >> the
> >> + *              next available space for a sampling-buffer entry.
> >> + * @overflows: Number of times the sampling-buffer has filled up.
> >> + * @buf_size: Total bytes in the sampling-buffer.
> >> + * @version: Sampling module version.
> >> + * @buf_flags: Copy of buf_flags from pfm_cell_hw_smpl_arg.
> >> + * @reserved1: Pad to 128-bit boundary.
> >> + *
> >> + * This header is at the beginning of the sampling-buffer returned to the 
> >> user\
> >> +.
> >> + * It is directly followed by the first record.
> >> + **/
> >> +struct pfm_cell_hw_smpl_hdr {
> >> +       __u64 count;
> >> +       __u64 cur_offset;
> >> +       __u64 overflows;
> >> +       __u64 buf_size;
> >> +       __u32 version;
> >> +       __u32 buf_flags;
> >> +       __u64 reserved1;
> >> +};
> >> +
> >> +/**
> >> + * struct pfm_cell_hw_smpl_entry_hdr
> >> + *
> >> + * @pid: Thread ID.
> >> + * @tgid: Thread group ID. For NPTL, this is getpid().
> >> + * @cpu: CPU on which the overflow occurred.
> >> + * @set: Event-set that was active when the overflow occurred.
> >> + * @num_lines: Number of trace-buffer lines in this entry.
> >> + * @entry_num: Sequence number of sampling-buffer entries.
> >> + * @pm_interval: If the last sample in this entry is for a partial time
> >> + *               interval, this is the value of pm_interval when the 
> >> partial
> >> + *               sample was recorded. If the value is zero, there is no 
> >> partial
> >> + *               sample at the end of the entry.
> >> + * @reserved1: Pad to 128-bit boundary.
> >> + *
> >> + *
> >> + * The header for each data entry in the sampling-buffer. The entry header
> >> + * is immediately followed by the contents of the trace-buffer. Each line 
> >> in
> >> + * the trace-buffer is 128 bits wide. The entry header specifies the 
> >> number
> >> + * of 128-bit trace-buffer lines that follow the header.
> >> + **/
> >> +struct pfm_cell_hw_smpl_entry_hdr {
> >> +       __u32 pid;
> >> +       __u32 tgid;
> >> +        __u32 cpu;
> >> +       __u32 set;
> >> +       __u32 num_samples;
> >> +       __u32 entry_num;
> >> +       __u32 pm_interval;
> >> +       __u32 reserved1;
> >> +};
> >> +
> >> +/* The max size of each sampling-buffer entry is the size of the entry 
> >> header
> >> + * plus the full size of the trace-buffer.
> >> + */
> >> +#define PFM_CELL_HW_SMPL_MAX_ENTRY_SIZE        \
> >> +          (sizeof(struct pfm_cell_hw_smpl_entry_hdr) +                 \
> >> +           2 * sizeof(u64) * CBE_PM_TRACE_BUF_MAX_COUNT)
> >> +
> >> +/* The sampling-buffer must be at least as large as the sampling-buffer 
> >> header
> >> + * and the max size of one sampling-buffer entry.
> >> + */
> >> +#define PFM_CELL_HW_SMPL_MIN_BUF_SIZE (sizeof(struct 
> >> pfm_cell_hw_smpl_hdr) + \
> >> +                                      PFM_CELL_HW_SMPL_MAX_ENTRY_SIZE)
> >> +
> >> +#define PFM_CELL_HW_SMPL_VERSION               1
> >> +#define PFM_CELL_HW_SMPL_NAME                  "perfmon_cell_hw_smpl"
> >> +#define PFM_CELL_HW_SMPL_OVFL_PMD              (PFM_MAX_PMDS + 1)
> >> +#define PFM_CELL_HW_SMPL_OVFL_PMD_PARTIAL      (PFM_MAX_PMDS + 2)
> >> +#define PFM_MSG_CELL_HW_SMPL_BUF_FULL          99
> >> +
> >> +/* Values are indexes into pfm_cell_pmc_desc[] array. */
> >> +#define CELL_PMC_PM_STATUS                     20
> >> +#define CELL_PMC_PM_CONTROL                    21
> >> +#define CELL_PMC_PM_INTERVAL                   22
> >> +
> >> +#endif /* __ASM_POWERPC_PERFMON_CELL_HW_SMPL_H__ */
> >> Index: linux-2.6.25.ppc64/arch/powerpc/perfmon/Kconfig
> >> ===================================================================
> >> --- linux-2.6.25.ppc64.orig/arch/powerpc/perfmon/Kconfig
> >> +++ linux-2.6.25.ppc64/arch/powerpc/perfmon/Kconfig
> >> @@ -64,4 +64,13 @@ config PERFMON_CELL
> >>        Enables support for the Cell hardware performance counters.
> >>        If unsure, say M.
> >>
> >> +config PERFMON_CELL_HW_SMPL
> >> +       tristate "Support for Cell hardware counter sampling"
> >> +       depends on PERFMON
> >> +       default n
> >> +       help
> >> +       Enables support for the Cell hardware counter sampling modes using
> >> +       the PMU trace-buffer.
> >> +       If unsure, say M.
> >> +
> >>  endmenu
> >> Index: linux-2.6.25.ppc64/include/linux/perfmon_kern.h
> >> ===================================================================
> >> --- linux-2.6.25.ppc64.orig/include/linux/perfmon_kern.h
> >> +++ linux-2.6.25.ppc64/include/linux/perfmon_kern.h
> >> @@ -469,6 +469,11 @@ struct pfm_stats {
> >>        char cpu_name[8];
> >>  };
> >>
> >> +/* carll, not sure exactly which #define these should be in */
> >> +union pfarg_msg *pfm_get_new_msg(struct pfm_context *ctx);
> >> +void pfm_mask_monitoring(struct pfm_context *ctx,
> >> +                        struct pfm_event_set *set);
> >> +
> >>  #ifdef CONFIG_PERFMON_DEBUG_FS
> >>  #define pfm_stats_get(x)  __get_cpu_var(pfm_stats).v[PFM_ST_##x]
> >>  #define pfm_stats_inc(x)  __get_cpu_var(pfm_stats).v[PFM_ST_##x]++
> >> Index: linux-2.6.25.ppc64/arch/powerpc/perfmon/Makefile
> >> ===================================================================
> >> --- linux-2.6.25.ppc64.orig/arch/powerpc/perfmon/Makefile
> >> +++ linux-2.6.25.ppc64/arch/powerpc/perfmon/Makefile
> >> @@ -1,6 +1,7 @@
> >> -obj-$(CONFIG_PERFMON)          += perfmon.o
> >> -obj-$(CONFIG_PERFMON_POWER4)   += perfmon_power4.o
> >> -obj-$(CONFIG_PERFMON_POWER5)   += perfmon_power5.o
> >> -obj-$(CONFIG_PERFMON_POWER6)   += perfmon_power6.o
> >> -obj-$(CONFIG_PERFMON_PPC32)    += perfmon_ppc32.o
> >> -obj-$(CONFIG_PERFMON_CELL)     += perfmon_cell.o
> >> +obj-$(CONFIG_PERFMON)                  += perfmon.o
> >> +obj-$(CONFIG_PERFMON_POWER4)           += perfmon_power4.o
> >> +obj-$(CONFIG_PERFMON_POWER5)           += perfmon_power5.o
> >> +obj-$(CONFIG_PERFMON_POWER6)           += perfmon_power6.o
> >> +obj-$(CONFIG_PERFMON_PPC32)            += perfmon_ppc32.o
> >> +obj-$(CONFIG_PERFMON_CELL)             += perfmon_cell.o
> >> +obj-$(CONFIG_PERFMON_CELL_HW_SMPL)     += perfmon_cell_hw_smpl.o
> >> Index: linux-2.6.25.ppc64/arch/powerpc/perfmon/perfmon_cell.c
> >> ===================================================================
> >> --- linux-2.6.25.ppc64.orig/arch/powerpc/perfmon/perfmon_cell.c
> >> +++ linux-2.6.25.ppc64/arch/powerpc/perfmon/perfmon_cell.c
> >> @@ -31,6 +31,7 @@
> >>  #include <asm/io.h>
> >>  #include <asm/machdep.h>
> >>  #include <asm/rtas.h>
> >> +#include <asm/perfmon_cell_hw_smpl.h>
> >>  #include <asm/ps3.h>
> >>  #include <asm/spu.h>
> >>
> >> @@ -98,7 +99,6 @@ static struct pfm_regmap_desc pfm_cell_p
> >>  #define PFM_PM_NUM_PMCS        ARRAY_SIZE(pfm_cell_pmc_desc)
> >>
> >>  #define CELL_PMC_GROUP_CONTROL    16
> >> -#define CELL_PMC_PM_STATUS        20
> >>  #define CELL_PMC_PM_CONTROL       21
> >>  #define CELL_PMC_PM_CONTROL_CNTR_MASK   0x01E00000UL
> >>  #define CELL_PMC_PM_CONTROL_CNTR_16     0x01E00000UL
> >> @@ -716,15 +716,31 @@ static void pfm_cell_enable_counters(str
> >>  * pfm_cell_disable_counters
> >>  *
> >>  * Just need to turn off the global disable bit in pm_control.
> >> + *
> >> + * Also, if we're using the hardware-sampling module, we need to empty the
> >> + * trace-buffer, since it cannot be restored to its current state when 
> >> this
> >> + * event-set is enabled again.
> >>  **/
> >>  static void pfm_cell_disable_counters(struct pfm_context *ctx,
> >>                                      struct pfm_event_set *set)
> >>  {
> >> +       struct pfm_smpl_fmt *smpl_fmt = ctx->smpl_fmt;
> >> +       struct pt_regs *regs;
> >> +
> >>        struct pfm_cell_platform_pmu_info *info =
> >>                ((struct pfm_arch_pmu_info *)
> >>                 (pfm_pmu_conf->pmu_info))->platform_info;
> >>
> >>        info->disable_pm(smp_processor_id());
> >> +
> >> +       if (smpl_fmt && !strcmp(smpl_fmt->fmt_name, 
> >> PFM_CELL_HW_SMPL_NAME)) {
> >> +               ctx->ovfl_arg.ovfl_pmd = PFM_CELL_HW_SMPL_OVFL_PMD_PARTIAL;
> >> +               ctx->ovfl_arg.active_set = ctx->active_set->id;
> >> +               regs = current->thread.regs;
> >> +               smpl_fmt->fmt_handler(ctx->smpl_addr, &ctx->ovfl_arg,
> >> +                                     instruction_pointer(regs), 0, regs);
> >> +       }
> >> +
> >>        if (machine_is(ps3))
> >>                reset_signals(smp_processor_id());
> >>  }
> >> @@ -1263,7 +1279,27 @@ static void handle_trace_buffer_interrup
> >>                                           struct pfm_context *ctx,
> >>                                           u32 pm_status)
> >>  {
> >> -       /* FIX: Currently ignoring trace-buffer interrupts. */
> >> +       struct pfm_smpl_fmt *smpl_fmt;
> >> +
> >> +       if (pm_status & CBE_PM_TRACE_BUFFER_FULL_INTR) {
> >> +               /* The trace-buffer is full. Get the
> >> +                * sampling-buffer address and call the handler.
> >> +                */
> >> +               smpl_fmt = ctx->smpl_fmt;
> >> +
> >> +               if (smpl_fmt &&
> >> +                   !strcmp(smpl_fmt->fmt_name, PFM_CELL_HW_SMPL_NAME)) {
> >> +                       ctx->ovfl_arg.ovfl_pmd = PFM_CELL_HW_SMPL_OVFL_PMD;
> >> +                       ctx->ovfl_arg.active_set = ctx->active_set->id;
> >> +                       smpl_fmt->fmt_handler(ctx->smpl_addr, 
> >> &ctx->ovfl_arg,
> >> +                                             iip, 0, regs);
> >> +               }
> >> +       }
> >> +
> >> +       /* Currently the trace buffer underflow and interval timer
> >> +        * interrupts are ignored.
> >> +        */
> >> +
> >>        return;
> >>  }
> >>
> >> @@ -1325,6 +1361,13 @@ static void pfm_cell_irq_handler(struct
> >>                handle_trace_buffer_interrupts(instruction_pointer(regs),
> >>                                               regs, ctx, 
> >> last_read_pm_status);
> >>
> >> +       /* If the hardware-sampling module masked monitoring for this 
> >> context,
> >> +        * don't re-enable the PMU.
> >> +        */
> >> +       if (ctx->state & PFM_CTX_MASKED) {
> >> +               return;
> >> +       }
> >> +
> >>        /* The interrupt settings is the value written to the pm_status
> >>         * register. It is saved in the context when the register is
> >>         * written.
> >> Index: linux-2.6.25.ppc64/arch/powerpc/perfmon/perfmon_cell_hw_smpl.c
> >> ===================================================================
> >> --- /dev/null
> >> +++ linux-2.6.25.ppc64/arch/powerpc/perfmon/perfmon_cell_hw_smpl.c
> >> @@ -0,0 +1,391 @@
> >> +/*
> >> + * Copyright IBM Corp 2007
> >> + *
> >> + * Contributed by Carl Love <[EMAIL PROTECTED]>
> >> + * and Kevin Corry <[EMAIL PROTECTED]>
> >> + *
> >> + * This program is free software; you can redistribute it and/or
> >> + * modify it under the terms of version 2 of the GNU General Public
> >> + * License as published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * 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
> >> + * along with this program; if not, write to the Free Software
> >> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
> >> + * 02111-1307 USA
> >> + *
> >> + *
> >> + * This file implements the IBM Cell PMU hardware-sampling module.
> >> + */
> >> +#include <linux/module.h>
> >> +#include <linux/perfmon_kern.h>
> >> +#include <linux/perfmon.h>
> >> +#include <asm/cell-pmu.h>
> >> +#include <asm/perfmon_cell_hw_smpl.h>
> >> +
> >> +MODULE_AUTHOR("Carl Love <[EMAIL PROTECTED]>, "
> >> +             "Kevin Corry <[EMAIL PROTECTED]>");
> >> +MODULE_DESCRIPTION("Perfmon2 CELL hardware sampling format");
> >> +MODULE_LICENSE("GPL");
> >> +
> >> +/**
> >> + * pfm_cell_hw_smpl_validate
> >> + *
> >> + * Validate the arguments passed from user-space for creating the
> >> + * sampling-buffer. The buffer must be large enough to hold the
> >> + * sampling-buffer header and at least one copy of the trace-buffer.
> >> + **/
> >> +static int pfm_cell_hw_smpl_validate(u32 flags, u16 npmds, void *data)
> >> +{
> >> +       struct pfm_cell_hw_smpl_arg *arg = data;
> >> +
> >> +       if (!arg) {
> >> +               PFM_ERR("No argument passed.");
> >> +               return -EINVAL;
> >> +       }
> >> +
> >> +       if (arg->buf_size < PFM_CELL_HW_SMPL_MIN_BUF_SIZE) {
> >> +               PFM_ERR("Specified buffer size (%lu) too small. "
> >> +                       "Min size is %lu bytes.",
> >> +                       arg->buf_size, PFM_CELL_HW_SMPL_MIN_BUF_SIZE);
> >> +               return -EINVAL;
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +/**
> >> + * pfm_cell_hw_smpl_get_size
> >> + *
> >> + * Tell the Perfmon2 core how large a buffer we need to have allocated, 
> >> and
> >> + * it will do the allocation for us. The size of the buffer has already 
> >> been
> >> + * validated.
> >> + **/
> >> +static int pfm_cell_hw_smpl_get_size(unsigned int flags,
> >> +                                    void *data, size_t *size)
> >> +{
> >> +       struct pfm_cell_hw_smpl_arg *arg = data;
> >> +       *size = arg->buf_size;
> >> +       return 0;
> >> +}
> >> +
> >> +/**
> >> + * pfm_cell_hw_smpl_init
> >> + *
> >> + * Initialize the start of the sampling-buffer with a header structure.
> >> + * The buffer has already been allocated by the Perfmon2 core.
> >> + **/
> >> +static int pfm_cell_hw_smpl_init(struct pfm_context *ctx, void *buf,
> >> +                                u32 flags, u16 npmds, void *data)
> >> +{
> >> +       struct pfm_cell_hw_smpl_hdr *hdr = buf;
> >> +       struct pfm_cell_hw_smpl_arg *arg = data;
> >> +
> >> +       hdr->count = 0;
> >> +       hdr->cur_offset = sizeof(*hdr);
> >> +       hdr->overflows = 0;
> >> +       hdr->buf_size = arg->buf_size;
> >> +       hdr->version = PFM_CELL_HW_SMPL_VERSION;
> >> +       hdr->buf_flags = arg->buf_flags;
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +/**
> >> + * pfm_cell_hw_smpl_add_msg
> >> + *
> >> + * Add a "buffer full" message to the context. A user-space process can
> >> + * then read() from the file-descriptor to get a copy of the message.
> >> + **/
> >> +static int pfm_cell_hw_smpl_add_msg(struct pfm_context *ctx)
> >> +{
> >> +       union pfarg_msg *msg;
> >> +
> >> +       if (ctx->flags.no_msg) {
> >> +               /* User-space won't be reading any messages. */
> >> +               return 0;
> >> +       }
> >> +
> >> +       msg = pfm_get_new_msg(ctx);
> >> +
> >> +       if (msg == NULL) {
> >> +               /* The message queue is full. The user must have called
> >> +                * pfm_restart(), but didn't extract any messages.
> >> +                */
> >> +               PFM_ERR("No notification messages available.");
> >> +               return -EBUSY;
> >> +       }
> >> +
> >> +       msg->type = PFM_MSG_CELL_HW_SMPL_BUF_FULL;
> >> +
> >> +       return 0;
> >> +}
> >> +/**
> >> + * init_entry_header
> >> + **/
> >> +static struct pfm_cell_hw_smpl_entry_hdr *
> >> +init_entry_header(struct pfm_cell_hw_smpl_hdr *buf_hdr,
> >> +                 struct pfm_event_set *set)
> >> +{
> >> +       struct pfm_cell_hw_smpl_entry_hdr *ent_hdr;
> >> +
> >> +       ent_hdr = (void *)buf_hdr + buf_hdr->cur_offset;
> >> +       ent_hdr->pid = current->pid;
> >> +       ent_hdr->tgid = current->tgid;
> >> +       ent_hdr->cpu = smp_processor_id();
> >> +       ent_hdr->set = set->id;
> >> +       ent_hdr->num_samples = 0;
> >> +       ent_hdr->entry_num = buf_hdr->count;
> >> +       ent_hdr->pm_interval = 0;
> >> +
> >> +       return ent_hdr;
> >> +}
> >> +
> >> +/**
> >> + * pmds_long_reset
> >> + *
> >> + * Reset all in-use PMDs to their "long" reset value. We write to the 
> >> hardware
> >> + * counters, so this should be called before "saving" the counters to the
> >> + * event-set copy.
> >> + **/
> >> +static inline void pmds_long_reset(struct pfm_event_set *set, int cpu)
> >> +{
> >> +      int i;
> >> +      for (i = 0; i < NR_CTRS; i++)
> >> +              if (test_bit(i, cast_ulp(&set->used_pmds)))
> >> +                      cbe_write_ctr(cpu, i, set->pmds[i].long_reset);
> >> +}
> >> +
> >> +/**
> >> + * read_trace_buffer
> >> + *
> >> + * Read at most 1024 samples from the trace-buffer. Note, samples could
> >> + * be added to the trace-buffer while it is being read. However, we only
> >> + * made sure we had space for up to 1024 samples.
> >> + **/
> >> +static void read_trace_buffer(struct pfm_cell_hw_smpl_entry_hdr *ent_hdr,
> >> +                             u64 **trace_buffer_sample)
> >> +{
> >> +       int cpu = smp_processor_id();
> >> +       u32 trace_addr;
> >> +
> >> +       *trace_buffer_sample = (u64 *)(ent_hdr + 1);
> >> +       trace_addr = cbe_read_pm(cpu, trace_address);
> >> +       while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY) &&
> >> +              ent_hdr->num_samples < CBE_PM_TRACE_BUF_MAX_COUNT) {
> >> +               cbe_read_trace_buffer(cpu, *trace_buffer_sample);
> >> +               *trace_buffer_sample += 2;
> >> +               ent_hdr->num_samples++;
> >> +               trace_addr = cbe_read_pm(cpu, trace_address);
> >> +       }
> >> +}
> >> +
> >> +/**
> >> + * read_partial_sample
> >> + *
> >> + * We are disabling this event-set, and are in the middle of a sampling
> >> + * interval. When this event set gets re-enabled, the pm_interval will get
> >> + * reset to its initial value, so we'll lose the counter values from this
> >> + * incomplete sample. In "count" sampling-mode, we should be able to 
> >> prevent
> >> + * this data loss by recording a "partial" sample from the actual 
> >> counters.
> >> + * In occurrence and threshold sampling, however, the partial data is not
> >> + * available, so we'll have to settle for an "empty" sample. In any case,
> >> + * fill in the current pm_interval value so user-space will know that the 
> >> last
> >> + * sample in this entry is partial or empty, and so they will be able to
> >> + * calculate the percentage-complete for that sample.
> >> + **/
> >> +static void read_partial_sample(struct pfm_event_set *set,
> >> +                               struct pfm_cell_hw_smpl_entry_hdr *ent_hdr,
> >> +                               u64 **trace_buffer_sample)
> >> +{
> >> +       u32 pm_control = set->pmcs[CELL_PMC_PM_CONTROL];
> >> +       u32 *partial_sample = (u32 *)*trace_buffer_sample;
> >> +       int i, cpu = smp_processor_id();
> >> +
> >> +       if (CBE_PM_TRACE_MODE_GET(pm_control) == CBE_PM_TRACE_MODE_COUNT) {
> >> +               for (i = 0; i < NR_PHYS_CTRS; i++) {
> >> +                       partial_sample[i] = cbe_read_phys_ctr(cpu, i);
> >> +               }
> >> +       } else {
> >> +               memset(partial_sample, 0,
> >> +                      NR_PHYS_CTRS * sizeof(*partial_sample));
> >> +       }
> >> +
> >> +       ent_hdr->pm_interval = cbe_read_pm(cpu, pm_interval);
> >> +       ent_hdr->num_samples++;
> >> +       *trace_buffer_sample += 2;
> >> +
> >> +       /* In all cases, reset the in-use PMDs to their "long" reset value
> >> +        * since we've effectively invalidated the data in this interval.
> >> +        */
> >> +       pmds_long_reset(set, cpu);
> >> +}
> >> +
> >> +/**
> >> + * handle_full_buffer
> >> + **/
> >> +static int handle_full_buffer(struct pfm_cell_hw_smpl_hdr *buf_hdr,
> >> +                             struct pfm_context *ctx,
> >> +                             struct pfm_event_set *set)
> >> +{
> >> +       int cpu = smp_processor_id();
> >> +
> >> +       /* Increment the number of sampling-buffer overflows. This
> >> +        * is important for detecting duplicate sets of samples.
> >> +        */
> >> +       buf_hdr->overflows++;
> >> +
> >> +       /* Reset the PMDs to their "long-reset" value. The hardware 
> >> counters
> >> +        * will be saved during the mask-monitoring call, and will be
> >> +        * restored later when we are unmasked, so we need to be sure the
> >> +        * counters are set to their correct initial values.
> >> +        */
> >> +       pmds_long_reset(set, cpu);
> >> +
> >> +       /* Reset the interval timer so we start a whole
> >> +        * new interval when we get restarted.
> >> +        */
> >> +       cbe_write_pm(cpu, pm_interval, set->pmcs[CELL_PMC_PM_INTERVAL]);
> >> +
> >> +       /* Mask monitoring until a pfm_restart() occurs. */
> >> +       pfm_mask_monitoring(ctx, set);
> >> +       ctx->state = PFM_CTX_MASKED;
> >> +       ctx->flags.can_restart = 1;
> >> +
> >> +       /* Add a message to the context's message queue. */
> >> +       pfm_cell_hw_smpl_add_msg(ctx);
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +
> >> +/**
> >> + * pfm_cell_hw_smpl_handler
> >> + *
> >> + * Create a new entry-header in the sampling-buffer and copy the current
> >> + * contents of the trace-buffer into the sampling-buffer.
> >> + **/
> >> +static int pfm_cell_hw_smpl_handler(void *buf,
> >> +                                   struct pfm_ovfl_arg *arg,
> >> +                                   unsigned long ip,
> >> +                                   u64 tstamp,
> >> +                                   void *data)
> >> +{
> >> +       struct pfm_cell_hw_smpl_hdr *hdr = buf;
> >> +       struct pfm_cell_hw_smpl_entry_hdr *ent;
> >> +       struct pfm_context *ctx;
> >> +       struct pfm_event_set *set;
> >> +       u64 *trace_buffer_sample;
> >> +       u64 free_bytes;
> >> +
> >> +       /* If this handler was called due to an actual PMD overflowing, do
> >> +        * nothing. Only store the contents of the trace-buffer if the 
> >> trace-
> >> +        * buffer overflowed or if we're disabling an event-set (during a
> >> +        * process context-switch or an event-set switch).
> >> +        */
> >> +       if (!(arg->ovfl_pmd == PFM_CELL_HW_SMPL_OVFL_PMD ||
> >> +             arg->ovfl_pmd == PFM_CELL_HW_SMPL_OVFL_PMD_PARTIAL))
> >> +               return 0;
> >> +
> >> +       ctx = __get_cpu_var(pmu_ctx);
> >> +       set = ctx->active_set;
> >> +
> >> +       /* Check if the sampling-buffer is full. This should never happen,
> >> +        * since we check if the buffer is full after adding the new entry.
> >> +        */
> >> +       free_bytes = hdr->buf_size - hdr->cur_offset;
> >> +
> >> +       if (free_bytes < PFM_CELL_HW_SMPL_MAX_ENTRY_SIZE)
> >> +               return handle_full_buffer(hdr, ctx, set);
> >> +
> >> +       ent = init_entry_header(hdr, set);
> >> +       read_trace_buffer(ent, &trace_buffer_sample);
> >> +
> >> +       if (arg->ovfl_pmd == PFM_CELL_HW_SMPL_OVFL_PMD_PARTIAL &&
> >> +           ent->num_samples < CBE_PM_TRACE_BUF_MAX_COUNT) {
> >> +               read_partial_sample(set, ent, &trace_buffer_sample);
> >> +       }
> >> +
> >> +       /* Update the sampling-buffer header for the next entry. Since the
> >> +        * hw_smpl_hdr and hw_smpl_entry_hdr structures are both padded to
> >> +        * 128-bits, and each trace-buffer line is 128-bits, we know that
> >> +        * every buffer entry will start on a 128-bit boundary.
> >> +        */
> >> +       if (ent->num_samples) {
> >> +               hdr->cur_offset = (void *)trace_buffer_sample - (void 
> >> *)hdr;
> >> +               hdr->count++;
> >> +       }
> >> +
> >> +       /* Check the available size in the buffer again so we won't lose 
> >> the
> >> +        * next sample entry.
> >> +        */
> >> +       free_bytes = hdr->buf_size - hdr->cur_offset;
> >> +       if (free_bytes < PFM_CELL_HW_SMPL_MAX_ENTRY_SIZE)
> >> +               return handle_full_buffer(hdr, ctx, set);
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +/**
> >> + * pfm_cell_hw_smpl_restart
> >> + *
> >> + * Reinitialize the sampling-buffer header, effectively deleting all 
> >> entries
> >> + * previously stored in the sampling-buffer.
> >> + *
> >> + * FIX: What is the "is_active" argument for? It's not used by any of the
> >> + *      other sampling modules.
> >> + **/
> >> +static int pfm_cell_hw_smpl_restart(int is_active, u32 *ovfl_ctrl, void 
> >> *buf)
> >> +{
> >> +       struct pfm_cell_hw_smpl_hdr *hdr = buf;
> >> +
> >> +       hdr->count = 0;
> >> +       hdr->cur_offset = sizeof(*hdr);
> >> +       hdr->overflows = 0;
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +/**
> >> + * pfm_cell_hw_smpl_exit
> >> + **/
> >> +static int pfm_cell_hw_smpl_exit(void *buf)
> >> +{
> >> +       return 0;
> >> +}
> >> +
> >> +/**
> >> + * cell_hw_smpl_fmt
> >> + *
> >> + * Structure to describe the Cell hardware-sampling module to the 
> >> Perfmon2 core.
> >> + **/
> >> +static struct pfm_smpl_fmt cell_hw_smpl_fmt = {
> >> +       .fmt_name = PFM_CELL_HW_SMPL_NAME,
> >> +       .fmt_arg_size = sizeof(struct pfm_cell_hw_smpl_arg),
> >> +       .fmt_flags = PFM_FMT_BUILTIN_FLAG,
> >> +       .fmt_version = PFM_CELL_HW_SMPL_VERSION,
> >> +       .fmt_validate = pfm_cell_hw_smpl_validate,
> >> +       .fmt_getsize = pfm_cell_hw_smpl_get_size,
> >> +       .fmt_init = pfm_cell_hw_smpl_init,
> >> +       .fmt_handler = pfm_cell_hw_smpl_handler,
> >> +       .fmt_restart = pfm_cell_hw_smpl_restart,
> >> +       .fmt_exit = pfm_cell_hw_smpl_exit,
> >> +       .owner = THIS_MODULE,
> >> +};
> >> +
> >> +static int __init pfm_cell_hw_smpl_init_module(void)
> >> +{
> >> +       return pfm_fmt_register(&cell_hw_smpl_fmt);
> >> +}
> >> +
> >> +static void __exit pfm_cell_hw_smpl_exit_module(void)
> >> +{
> >> +       pfm_fmt_unregister(&cell_hw_smpl_fmt);
> >> +}
> >> +
> >> +module_init(pfm_cell_hw_smpl_init_module);
> >> +module_exit(pfm_cell_hw_smpl_exit_module);
> >> Index: linux-2.6.25.ppc64/include/asm-powerpc/cell-pmu.h
> >> ===================================================================
> >> --- linux-2.6.25.ppc64.orig/include/asm-powerpc/cell-pmu.h
> >> +++ linux-2.6.25.ppc64/include/asm-powerpc/cell-pmu.h
> >> @@ -41,6 +41,11 @@
> >>  #define CBE_PM_FREEZE_ALL_CTRS             0x00100000
> >>  #define CBE_PM_ENABLE_EXT_TRACE            0x00008000
> >>
> >> +#define CBE_PM_TRACE_MODE_NONE             0
> >> +#define CBE_PM_TRACE_MODE_COUNT            1
> >> +#define CBE_PM_TRACE_MODE_OCCURRENCE       2
> >> +#define CBE_PM_TRACE_MODE_THRESHOLD        3
> >> +
> >>  /* Macros for the trace_address register. */
> >>  #define CBE_PM_TRACE_BUF_FULL              0x00000800
> >>  #define CBE_PM_TRACE_BUF_EMPTY             0x00000400
> >> Index: linux-2.6.25.ppc64/perfmon/perfmon_msg.c
> >> ===================================================================
> >> --- linux-2.6.25.ppc64.orig/perfmon/perfmon_msg.c
> >> +++ linux-2.6.25.ppc64/perfmon/perfmon_msg.c
> >> @@ -36,7 +36,9 @@
> >>  * 02111-1307 USA
> >>  */
> >>  #include <linux/kernel.h>
> >> +#include <linux/module.h>
> >>  #include <linux/poll.h>
> >> +#include <linux/perfmon.h>
> >>  #include <linux/perfmon_kern.h>
> >>
> >>  /**
> >> @@ -45,7 +47,7 @@
> >>  *
> >>  * if queue if full NULL is returned
> >>  */
> >> -static union pfarg_msg *pfm_get_new_msg(struct pfm_context *ctx)
> >> +union pfarg_msg *pfm_get_new_msg(struct pfm_context *ctx)
> >>  {
> >>        int next;
> >>
> >> @@ -66,6 +68,7 @@ static union pfarg_msg *pfm_get_new_msg(
> >>
> >>        return ctx->msgq+next;
> >>  }
> >> +EXPORT_SYMBOL(pfm_get_new_msg);
> >>
> >>  /**
> >>  * pfm_notify_user - wakeup any thread wiating on msg queue,  post SIGIO
> >> Index: linux-2.6.25.ppc64/perfmon/perfmon_init.c
> >> ===================================================================
> >> --- linux-2.6.25.ppc64.orig/perfmon/perfmon_init.c
> >> +++ linux-2.6.25.ppc64/perfmon/perfmon_init.c
> >> @@ -37,6 +37,7 @@
> >>  * 02111-1307 USA
> >>  */
> >>  #include <linux/kernel.h>
> >> +#include <linux/module.h>
> >>  #include <linux/perfmon_kern.h>
> >>  #include "perfmon_priv.h"
> >>
> >> @@ -48,6 +49,7 @@ DEFINE_PER_CPU(struct pfm_context  *, pm
> >>  DEFINE_PER_CPU(u64, pmu_activation_number);
> >>  DEFINE_PER_CPU(struct pfm_stats, pfm_stats);
> >>  DEFINE_PER_CPU(struct hrtimer, pfm_hrtimer);
> >> +EXPORT_PER_CPU_SYMBOL(pmu_ctx);
> >>
> >>
> >>  int perfmon_disabled;  /* >0 if perfmon is disabled */
> >> Index: linux-2.6.25.ppc64/perfmon/perfmon_smpl.c
> >> ===================================================================
> >> --- linux-2.6.25.ppc64.orig/perfmon/perfmon_smpl.c
> >> +++ linux-2.6.25.ppc64/perfmon/perfmon_smpl.c
> >> @@ -285,6 +285,7 @@ void pfm_mask_monitoring(struct pfm_cont
> >>        }
> >>        PFM_DBG_ovfl("can_restart=%u", ctx->flags.can_restart);
> >>  }
> >> +EXPORT_SYMBOL(pfm_mask_monitoring);
> >>
> >>  /**
> >>  * pfm_unmask_monitoring - unmask monitoring
> >>
> >>
> >>
> >> -------------------------------------------------------------------------
> >> This SF.Net email is sponsored by the Moblin Your Move Developer's 
> >> challenge
> >> Build the coolest Linux based applications with Moblin SDK & win great 
> >> prizes
> >> Grand prize is a trip for two to an Open Source event anywhere in the world
> >> http://moblin-contest.org/redirect.php?banner_id=100&url=/
> >> _______________________________________________
> >> perfmon2-devel mailing list
> >> [email protected]
> >> https://lists.sourceforge.net/lists/listinfo/perfmon2-devel
> >>
> >


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
perfmon2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/perfmon2-devel

Reply via email to