static void fsl_booke_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr) { unsigned long pc; int is_kernel; int val; int i; /* set the PMM bit (see comment below) */ mtmsr(mfmsr() | MSR_PMM); pc = regs->nip; is_kernel = (pc >= KERNELBASE); for (i = 0; i < num_counters; ++i) { val = ctr_read(i); if (val < 0) { if (oprofile_running && ctr[i].enabled) { oprofile_add_pc(pc, is_kernel, i); ctr_write(i, reset_value[i]); } else { ctr_write(i, 0); } } } /* The freeze bit was set by the interrupt. */ /* Clear the freeze bit, and reenable the interrupt. * The counters won't actually start until the rfi clears * the PMM bit */ pmc_start_ctrs(1); }
static inline void op_add_pm(unsigned long pc, int kern, unsigned long counter, struct op_counter_config *ctr, unsigned long event) { unsigned long fake_counter = 2 + event; if (counter == 1) fake_counter += PM_NUM_COUNTERS; if (ctr[fake_counter].enabled) oprofile_add_pc(pc, kern, fake_counter); }
static irqreturn_t xenoprof_ovf_interrupt(int irq, void * dev_id, struct pt_regs * regs) { int head, tail, size; struct xenoprof_buf * buf; int cpu; cpu = smp_processor_id(); buf = xenoprof_buf[cpu]; head = buf->event_head; tail = buf->event_tail; size = buf->event_size; if (tail > head) { while (tail < size) { oprofile_add_pc(buf->event_log[tail].eip, buf->event_log[tail].mode, buf->event_log[tail].event); oprofile_samples++; tail++; } tail = 0; } while (tail < head) { oprofile_add_pc(buf->event_log[tail].eip, buf->event_log[tail].mode, buf->event_log[tail].event); oprofile_samples++; tail++; } buf->event_tail = tail; return IRQ_HANDLED; }
void tile_backtrace(struct pt_regs *const regs, unsigned int depth) { struct KBacktraceIterator kbt; unsigned int i; /* * Get the address just after the "jalr" instruction that * jumps to the handler for a syscall. When we find this * address in a backtrace, we silently ignore it, which gives * us a one-step backtrace connection from the sys_xxx() * function in the kernel to the xxx() function in libc. * Otherwise, we lose the ability to properly attribute time * from the libc calls to the kernel implementations, since * oprofile only considers PCs from backtraces a pair at a time. */ unsigned long handle_syscall_pc = handle_syscall_link_address(); KBacktraceIterator_init(&kbt, NULL, regs); kbt.profile = 1; /* * The sample for the pc is already recorded. Now we are adding the * address of the callsites on the stack. Our iterator starts * with the frame of the (already sampled) call site. If our * iterator contained a "return address" field, we could have just * used it and wouldn't have needed to skip the first * frame. That's in effect what the arm and x86 versions do. * Instead we peel off the first iteration to get the equivalent * behavior. */ if (KBacktraceIterator_end(&kbt)) return; KBacktraceIterator_next(&kbt); for (i = 0; i < depth; ++i) { int is_kernel; unsigned long pc; if (KBacktraceIterator_end(&kbt)) break; pc = kbt.it.pc; is_kernel = (pc >= PAGE_OFFSET && !is_arch_mappable_range(pc, 1)); if (pc != handle_syscall_pc) oprofile_add_pc(pc, is_kernel, 0); KBacktraceIterator_next(&kbt); } }
static void rs64_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr) { unsigned int mmcr0; int val; int i; unsigned long pc = mfspr(SPRN_SIAR); int is_kernel = (pc >= KERNELBASE); /* set the PMM bit (see comment below) */ mtmsrd(mfmsr() | MSR_PMM); for (i = 0; i < num_counters; ++i) { val = ctr_read(i); if (val < 0) { if (ctr[i].enabled) { oprofile_add_pc(pc, is_kernel, i); ctr_write(i, reset_value[i]); } else { ctr_write(i, 0); } } } mmcr0 = mfspr(SPRN_MMCR0); /* reset the perfmon trigger */ mmcr0 |= MMCR0_PMXE; /* * now clear the freeze bit, counting will not start until we * rfid from this exception, because only at that point will * the PMM bit be cleared */ mmcr0 &= ~MMCR0_FC; mtspr(SPRN_MMCR0, mmcr0); }
static void xenoprof_add_pc(xenoprof_buf_t *buf, int is_passive) { int head, tail, size; int tracing = 0; head = buf->event_head; tail = buf->event_tail; size = buf->event_size; while (tail != head) { if (xenoprof_is_escape(buf, tail) && xenoprof_get_event(buf, tail) == XENOPROF_TRACE_BEGIN) { tracing=1; oprofile_add_mode(buf->event_log[tail].mode); if (!is_passive) oprofile_samples++; else p_oprofile_samples++; } else { oprofile_add_pc(buf->event_log[tail].eip, buf->event_log[tail].mode, buf->event_log[tail].event); if (!tracing) { if (!is_passive) oprofile_samples++; else p_oprofile_samples++; } } tail++; if(tail==size) tail=0; } buf->event_tail = tail; }
static void ev67_handle_interrupt(unsigned long which, struct pt_regs *regs, struct op_counter_config *ctr) { unsigned long pmpc, pctr_ctl; int kern = !user_mode(regs); int mispredict = 0; union { unsigned long v; struct { unsigned reserved: 30; /* 0-29 */ unsigned overcount: 3; /* 30-32 */ unsigned icache_miss: 1; /* 33 */ unsigned trap_type: 4; /* 34-37 */ unsigned load_store: 1; /* 38 */ unsigned trap: 1; /* 39 */ unsigned mispredict: 1; /* 40 */ } fields; } i_stat; enum trap_types { TRAP_REPLAY, TRAP_INVALID0, TRAP_DTB_DOUBLE_MISS_3, TRAP_DTB_DOUBLE_MISS_4, TRAP_FP_DISABLED, TRAP_UNALIGNED, TRAP_DTB_SINGLE_MISS, TRAP_DSTREAM_FAULT, TRAP_OPCDEC, TRAP_INVALID1, TRAP_MACHINE_CHECK, TRAP_INVALID2, TRAP_ARITHMETIC, TRAP_INVALID3, TRAP_MT_FPCR, TRAP_RESET }; pmpc = wrperfmon(9, 0); /* ??? Don't know how to handle physical-mode PALcode address. */ if (pmpc & 1) return; pmpc &= ~2; /* clear reserved bit */ i_stat.v = wrperfmon(8, 0); if (i_stat.fields.trap) { switch (i_stat.fields.trap_type) { case TRAP_INVALID1: case TRAP_INVALID2: case TRAP_INVALID3: /* Pipeline redirection ocurred. PMPC points to PALcode. Recognize ITB miss by PALcode offset address, and get actual PC from EXC_ADDR. */ oprofile_add_pc(regs->pc, kern, which); if ((pmpc & ((1 << 15) - 1)) == 581) op_add_pm(regs->pc, kern, which, ctr, PM_ITB_MISS); /* Most other bit and counter values will be those for the first instruction in the fault handler, so we're done. */ return; case TRAP_REPLAY: op_add_pm(pmpc, kern, which, ctr, (i_stat.fields.load_store ? PM_LOAD_STORE : PM_REPLAY)); break; case TRAP_DTB_DOUBLE_MISS_3: case TRAP_DTB_DOUBLE_MISS_4: case TRAP_DTB_SINGLE_MISS: op_add_pm(pmpc, kern, which, ctr, PM_DTB_MISS); break; case TRAP_UNALIGNED: op_add_pm(pmpc, kern, which, ctr, PM_UNALIGNED); break; case TRAP_INVALID0: case TRAP_FP_DISABLED: case TRAP_DSTREAM_FAULT: case TRAP_OPCDEC: case TRAP_MACHINE_CHECK: case TRAP_ARITHMETIC: case TRAP_MT_FPCR: case TRAP_RESET: break; } /* ??? JSR/JMP/RET/COR or HW_JSR/HW_JMP/HW_RET/HW_COR mispredicts do not set this bit but can be recognized by the presence of one of these instructions at the PMPC location with bit 39 set. */ if (i_stat.fields.mispredict) { mispredict = 1; op_add_pm(pmpc, kern, which, ctr, PM_MISPREDICT); } } oprofile_add_pc(pmpc, kern, which); pctr_ctl = wrperfmon(5, 0); if (pctr_ctl & (1UL << 27)) op_add_pm(pmpc, kern, which, ctr, PM_STALLED); /* Unfortunately, TAK is undefined on mispredicted branches. ??? It is also undefined for non-cbranch insns, should check that. */ if (!mispredict && pctr_ctl & (1UL << 0)) op_add_pm(pmpc, kern, which, ctr, PM_TAKEN); }
static void ev67_handle_interrupt(unsigned long which, struct pt_regs *regs, struct op_counter_config *ctr) { unsigned long pmpc, pctr_ctl; int kern = !user_mode(regs); int mispredict = 0; union { unsigned long v; struct { unsigned reserved: 30; unsigned overcount: 3; unsigned icache_miss: 1; unsigned trap_type: 4; unsigned load_store: 1; unsigned trap: 1; unsigned mispredict: 1; } fields; } i_stat; enum trap_types { TRAP_REPLAY, TRAP_INVALID0, TRAP_DTB_DOUBLE_MISS_3, TRAP_DTB_DOUBLE_MISS_4, TRAP_FP_DISABLED, TRAP_UNALIGNED, TRAP_DTB_SINGLE_MISS, TRAP_DSTREAM_FAULT, TRAP_OPCDEC, TRAP_INVALID1, TRAP_MACHINE_CHECK, TRAP_INVALID2, TRAP_ARITHMETIC, TRAP_INVALID3, TRAP_MT_FPCR, TRAP_RESET }; pmpc = wrperfmon(9, 0); if (pmpc & 1) return; pmpc &= ~2; i_stat.v = wrperfmon(8, 0); if (i_stat.fields.trap) { switch (i_stat.fields.trap_type) { case TRAP_INVALID1: case TRAP_INVALID2: case TRAP_INVALID3: oprofile_add_pc(regs->pc, kern, which); if ((pmpc & ((1 << 15) - 1)) == 581) op_add_pm(regs->pc, kern, which, ctr, PM_ITB_MISS); return; case TRAP_REPLAY: op_add_pm(pmpc, kern, which, ctr, (i_stat.fields.load_store ? PM_LOAD_STORE : PM_REPLAY)); break; case TRAP_DTB_DOUBLE_MISS_3: case TRAP_DTB_DOUBLE_MISS_4: case TRAP_DTB_SINGLE_MISS: op_add_pm(pmpc, kern, which, ctr, PM_DTB_MISS); break; case TRAP_UNALIGNED: op_add_pm(pmpc, kern, which, ctr, PM_UNALIGNED); break; case TRAP_INVALID0: case TRAP_FP_DISABLED: case TRAP_DSTREAM_FAULT: case TRAP_OPCDEC: case TRAP_MACHINE_CHECK: case TRAP_ARITHMETIC: case TRAP_MT_FPCR: case TRAP_RESET: break; } if (i_stat.fields.mispredict) { mispredict = 1; op_add_pm(pmpc, kern, which, ctr, PM_MISPREDICT); } } oprofile_add_pc(pmpc, kern, which); pctr_ctl = wrperfmon(5, 0); if (pctr_ctl & (1UL << 27)) op_add_pm(pmpc, kern, which, ctr, PM_STALLED); if (!mispredict && pctr_ctl & (1UL << 0)) op_add_pm(pmpc, kern, which, ctr, PM_TAKEN); }