perf_event.c 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /*
  2. * Linux performance counter support for MIPS.
  3. *
  4. * Copyright (C) 2010 MIPS Technologies, Inc.
  5. * Author: Deng-Cheng Zhu
  6. *
  7. * This code is based on the implementation for ARM, which is in turn
  8. * based on the sparc64 perf event code and the x86 code. Performance
  9. * counter access is based on the MIPS Oprofile code. And the callchain
  10. * support references the code of MIPS stacktrace.c.
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License version 2 as
  14. * published by the Free Software Foundation.
  15. */
  16. #include <linux/perf_event.h>
  17. #include <asm/stacktrace.h>
  18. /* Callchain handling code. */
  19. /*
  20. * Leave userspace callchain empty for now. When we find a way to trace
  21. * the user stack callchains, we will add it here.
  22. */
  23. static void save_raw_perf_callchain(struct perf_callchain_entry *entry,
  24. unsigned long reg29)
  25. {
  26. unsigned long *sp = (unsigned long *)reg29;
  27. unsigned long addr;
  28. while (!kstack_end(sp)) {
  29. addr = *sp++;
  30. if (__kernel_text_address(addr)) {
  31. perf_callchain_store(entry, addr);
  32. if (entry->nr >= PERF_MAX_STACK_DEPTH)
  33. break;
  34. }
  35. }
  36. }
  37. void perf_callchain_kernel(struct perf_callchain_entry *entry,
  38. struct pt_regs *regs)
  39. {
  40. unsigned long sp = regs->regs[29];
  41. #ifdef CONFIG_KALLSYMS
  42. unsigned long ra = regs->regs[31];
  43. unsigned long pc = regs->cp0_epc;
  44. if (raw_show_trace || !__kernel_text_address(pc)) {
  45. unsigned long stack_page =
  46. (unsigned long)task_stack_page(current);
  47. if (stack_page && sp >= stack_page &&
  48. sp <= stack_page + THREAD_SIZE - 32)
  49. save_raw_perf_callchain(entry, sp);
  50. return;
  51. }
  52. do {
  53. perf_callchain_store(entry, pc);
  54. if (entry->nr >= PERF_MAX_STACK_DEPTH)
  55. break;
  56. pc = unwind_stack(current, &sp, pc, &ra);
  57. } while (pc);
  58. #else
  59. save_raw_perf_callchain(entry, sp);
  60. #endif
  61. }