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