trace_functions.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * ring buffer based function tracer
  3. *
  4. * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
  5. * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
  6. *
  7. * Based on code from the latency_tracer, that is:
  8. *
  9. * Copyright (C) 2004-2006 Ingo Molnar
  10. * Copyright (C) 2004 William Lee Irwin III
  11. */
  12. #include <linux/debugfs.h>
  13. #include <linux/uaccess.h>
  14. #include <linux/ftrace.h>
  15. #include <linux/fs.h>
  16. #include "trace.h"
  17. static struct trace_array *func_trace;
  18. static void start_function_trace(struct trace_array *tr)
  19. {
  20. tr->cpu = get_cpu();
  21. tracing_reset_online_cpus(tr);
  22. put_cpu();
  23. tracing_start_cmdline_record();
  24. tracing_start_function_trace();
  25. }
  26. static void stop_function_trace(struct trace_array *tr)
  27. {
  28. tracing_stop_function_trace();
  29. tracing_stop_cmdline_record();
  30. }
  31. static int function_trace_init(struct trace_array *tr)
  32. {
  33. func_trace = tr;
  34. start_function_trace(tr);
  35. return 0;
  36. }
  37. static void function_trace_reset(struct trace_array *tr)
  38. {
  39. stop_function_trace(tr);
  40. }
  41. static void function_trace_start(struct trace_array *tr)
  42. {
  43. tracing_reset_online_cpus(tr);
  44. }
  45. static void
  46. function_stack_trace_call(unsigned long ip, unsigned long parent_ip)
  47. {
  48. struct trace_array *tr = func_trace;
  49. struct trace_array_cpu *data;
  50. unsigned long flags;
  51. long disabled;
  52. int cpu;
  53. int pc;
  54. if (unlikely(!ftrace_function_enabled))
  55. return;
  56. /*
  57. * Need to use raw, since this must be called before the
  58. * recursive protection is performed.
  59. */
  60. local_irq_save(flags);
  61. cpu = raw_smp_processor_id();
  62. data = tr->data[cpu];
  63. disabled = atomic_inc_return(&data->disabled);
  64. if (likely(disabled == 1)) {
  65. pc = preempt_count();
  66. /*
  67. * skip over 5 funcs:
  68. * __ftrace_trace_stack,
  69. * __trace_stack,
  70. * function_stack_trace_call
  71. * ftrace_list_func
  72. * ftrace_call
  73. */
  74. __trace_stack(tr, data, flags, 5, pc);
  75. }
  76. atomic_dec(&data->disabled);
  77. local_irq_restore(flags);
  78. }
  79. static struct ftrace_ops trace_stack_ops __read_mostly =
  80. {
  81. .func = function_stack_trace_call,
  82. };
  83. /* Our two options */
  84. enum {
  85. TRACE_FUNC_OPT_STACK = 0x1,
  86. };
  87. static struct tracer_opt func_opts[] = {
  88. #ifdef CONFIG_STACKTRACE
  89. { TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) },
  90. #endif
  91. { } /* Always set a last empty entry */
  92. };
  93. static struct tracer_flags func_flags = {
  94. .val = 0, /* By default: all flags disabled */
  95. .opts = func_opts
  96. };
  97. static int func_set_flag(u32 old_flags, u32 bit, int set)
  98. {
  99. if (bit == TRACE_FUNC_OPT_STACK) {
  100. /* do nothing if already set */
  101. if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK))
  102. return 0;
  103. if (set)
  104. register_ftrace_function(&trace_stack_ops);
  105. else
  106. unregister_ftrace_function(&trace_stack_ops);
  107. return 0;
  108. }
  109. return -EINVAL;
  110. }
  111. static struct tracer function_trace __read_mostly =
  112. {
  113. .name = "function",
  114. .init = function_trace_init,
  115. .reset = function_trace_reset,
  116. .start = function_trace_start,
  117. .flags = &func_flags,
  118. .set_flag = func_set_flag,
  119. #ifdef CONFIG_FTRACE_SELFTEST
  120. .selftest = trace_selftest_startup_function,
  121. #endif
  122. };
  123. static __init int init_function_trace(void)
  124. {
  125. return register_tracer(&function_trace);
  126. }
  127. device_initcall(init_function_trace);