提交 7f788d2d 编写于 作者: D Deng-Cheng Zhu 提交者: Ralf Baechle

MIPS: add support for software performance events

Software events are required as part of the measurable stuff by the
Linux performance counter subsystem. Here is the list of events added by
this patch:
PERF_COUNT_SW_PAGE_FAULTS
PERF_COUNT_SW_PAGE_FAULTS_MIN
PERF_COUNT_SW_PAGE_FAULTS_MAJ
PERF_COUNT_SW_ALIGNMENT_FAULTS
PERF_COUNT_SW_EMULATION_FAULTS
Signed-off-by: NDeng-Cheng Zhu <dengcheng.zhu@gmail.com>
To: linux-mips@linux-mips.org
Cc: a.p.zijlstra@chello.nl
Cc: paulus@samba.org
Cc: mingo@elte.hu
Cc: acme@redhat.com
Cc: jamie.iles@picochip.com
Acked-by: NDavid Daney <ddaney@caviumnetworks.com>
Reviewed-by: NMatt Fleming <matt@console-pimps.org>
Patchwork: https://patchwork.linux-mips.org/patch/1686/Signed-off-by: NRalf Baechle <ralf@linux-mips.org>
上级 6dbd9728
...@@ -4,6 +4,8 @@ config MIPS ...@@ -4,6 +4,8 @@ config MIPS
select HAVE_GENERIC_DMA_COHERENT select HAVE_GENERIC_DMA_COHERENT
select HAVE_IDE select HAVE_IDE
select HAVE_OPROFILE select HAVE_OPROFILE
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select HAVE_ARCH_KGDB select HAVE_ARCH_KGDB
select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_FUNCTION_TRACE_MCOUNT_TEST
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/kdb.h> #include <linux/kdb.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/perf_event.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/branch.h> #include <asm/branch.h>
...@@ -576,10 +577,16 @@ static inline int simulate_sc(struct pt_regs *regs, unsigned int opcode) ...@@ -576,10 +577,16 @@ static inline int simulate_sc(struct pt_regs *regs, unsigned int opcode)
*/ */
static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) static int simulate_llsc(struct pt_regs *regs, unsigned int opcode)
{ {
if ((opcode & OPCODE) == LL) if ((opcode & OPCODE) == LL) {
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
1, 0, regs, 0);
return simulate_ll(regs, opcode); return simulate_ll(regs, opcode);
if ((opcode & OPCODE) == SC) }
if ((opcode & OPCODE) == SC) {
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
1, 0, regs, 0);
return simulate_sc(regs, opcode); return simulate_sc(regs, opcode);
}
return -1; /* Must be something else ... */ return -1; /* Must be something else ... */
} }
...@@ -595,6 +602,8 @@ static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode) ...@@ -595,6 +602,8 @@ static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode)
if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) {
int rd = (opcode & RD) >> 11; int rd = (opcode & RD) >> 11;
int rt = (opcode & RT) >> 16; int rt = (opcode & RT) >> 16;
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
1, 0, regs, 0);
switch (rd) { switch (rd) {
case 0: /* CPU number */ case 0: /* CPU number */
regs->regs[rt] = smp_processor_id(); regs->regs[rt] = smp_processor_id();
...@@ -630,8 +639,11 @@ static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode) ...@@ -630,8 +639,11 @@ static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode)
static int simulate_sync(struct pt_regs *regs, unsigned int opcode) static int simulate_sync(struct pt_regs *regs, unsigned int opcode)
{ {
if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC) if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC) {
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
1, 0, regs, 0);
return 0; return 0;
}
return -1; /* Must be something else ... */ return -1; /* Must be something else ... */
} }
......
...@@ -78,6 +78,8 @@ ...@@ -78,6 +78,8 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/perf_event.h>
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/branch.h> #include <asm/branch.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
...@@ -109,6 +111,9 @@ static void emulate_load_store_insn(struct pt_regs *regs, ...@@ -109,6 +111,9 @@ static void emulate_load_store_insn(struct pt_regs *regs,
unsigned long value; unsigned long value;
unsigned int res; unsigned int res;
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
1, 0, regs, 0);
/* /*
* This load never faults. * This load never faults.
*/ */
...@@ -511,6 +516,8 @@ asmlinkage void do_ade(struct pt_regs *regs) ...@@ -511,6 +516,8 @@ asmlinkage void do_ade(struct pt_regs *regs)
unsigned int __user *pc; unsigned int __user *pc;
mm_segment_t seg; mm_segment_t seg;
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
1, 0, regs, regs->cp0_badvaddr);
/* /*
* Did we catch a fault trying to load an instruction? * Did we catch a fault trying to load an instruction?
* Or are we running in MIPS16 mode? * Or are we running in MIPS16 mode?
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/perf_event.h>
#include <asm/inst.h> #include <asm/inst.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
...@@ -258,6 +259,8 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx) ...@@ -258,6 +259,8 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
} }
emul: emul:
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
1, 0, xcp, 0);
MIPS_FPU_EMU_INC_STATS(emulated); MIPS_FPU_EMU_INC_STATS(emulated);
switch (MIPSInst_OPCODE(ir)) { switch (MIPSInst_OPCODE(ir)) {
case ldc1_op:{ case ldc1_op:{
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/perf_event.h>
#include <asm/branch.h> #include <asm/branch.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
...@@ -144,6 +145,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ ...@@ -144,6 +145,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ
* the fault. * the fault.
*/ */
fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
if (unlikely(fault & VM_FAULT_ERROR)) { if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM) if (fault & VM_FAULT_OOM)
goto out_of_memory; goto out_of_memory;
...@@ -151,10 +153,15 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ ...@@ -151,10 +153,15 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ
goto do_sigbus; goto do_sigbus;
BUG(); BUG();
} }
if (fault & VM_FAULT_MAJOR) if (fault & VM_FAULT_MAJOR) {
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ,
1, 0, regs, address);
tsk->maj_flt++; tsk->maj_flt++;
else } else {
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN,
1, 0, regs, address);
tsk->min_flt++; tsk->min_flt++;
}
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
return; return;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册