Subject: Perfmon2: Reset PMDs when handling a full sampling-buffer From: Kevin Corry In addition to resetting the counters to their "long" reset value after recording a partial sample, we also need to reset the counters while handling a full sampling-buffer. In handle_full_buffer, when we call pfm_mask_monitoring(), it will save the current PMD values. However, the counters were still running between the time the last sample was recorded in the buffer and the time when the counters were disabled in the interrupt handler. When the PMD values get restored later during pfm_unmask_monitoring(), it will restore these values, which effectively changes the initial values for the hardware-sampling. Also reset the interval timer so we start a new interval when monitoring is unmasked. Signed-off-by: Kevin Corry Signed-off-by: Carl Love Signed-off-by: Arnd Bergmann Index: linux-2.6/arch/powerpc/perfmon/perfmon_cell_hw_smpl.c =================================================================== --- linux-2.6.orig/arch/powerpc/perfmon/perfmon_cell_hw_smpl.c +++ linux-2.6/arch/powerpc/perfmon/perfmon_cell_hw_smpl.c @@ -145,6 +145,21 @@ init_entry_header(struct pfm_cell_hw_smp } /** + * 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 @@ -203,14 +218,10 @@ static void read_partial_sample(struct p 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. We have not saved the PMDs to the event-set at - * this point, so write to the actual counter registers. + /* In all cases, reset the in-use PMDs to their "long" reset value + * since we've effectively invalidated the data in this interval. */ - 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); + pmds_long_reset(set, cpu); } /** @@ -220,11 +231,25 @@ static int handle_full_buffer(struct pfm 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]); + /* Add a message to the context's message queue and wake up any * user-space program's that are polling on the context's file * descriptor.