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