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