perf_event.c 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  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 <linux/sched/task_stack.h>
  18. #include <asm/stacktrace.h>
  19. /* Callchain handling code. */
  20. /*
  21. * Leave userspace callchain empty for now. When we find a way to trace
  22. * the user stack callchains, we will add it here.
  23. */
  24. static void save_raw_perf_callchain(struct perf_callchain_entry_ctx *entry,
  25. unsigned long reg29)
  26. {
  27. unsigned long *sp = (unsigned long *)reg29;
  28. unsigned long addr;
  29. while (!kstack_end(sp)) {
  30. addr = *sp++;
  31. if (__kernel_text_address(addr)) {
  32. perf_callchain_store(entry, addr);
  33. if (entry->nr >= entry->max_stack)
  34. break;
  35. }
  36. }
  37. }
  38. void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
  39. struct pt_regs *regs)
  40. {
  41. unsigned long sp = regs->regs[29];
  42. #ifdef CONFIG_KALLSYMS
  43. unsigned long ra = regs->regs[31];
  44. unsigned long pc = regs->cp0_epc;
  45. if (raw_show_trace || !__kernel_text_address(pc)) {
  46. unsigned long stack_page =
  47. (unsigned long)task_stack_page(current);
  48. if (stack_page && sp >= stack_page &&
  49. sp <= stack_page + THREAD_SIZE - 32)
  50. save_raw_perf_callchain(entry, sp);
  51. return;
  52. }
  53. do {
  54. perf_callchain_store(entry, pc);
  55. if (entry->nr >= entry->max_stack)
  56. break;
  57. pc = unwind_stack(current, &sp, pc, &ra);
  58. } while (pc);
  59. #else
  60. save_raw_perf_callchain(entry, sp);
  61. #endif
  62. }