trace_boot.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * ring buffer based initcalls tracer
  3. *
  4. * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
  5. *
  6. */
  7. #include <linux/init.h>
  8. #include <linux/debugfs.h>
  9. #include <linux/ftrace.h>
  10. #include <linux/kallsyms.h>
  11. #include "trace.h"
  12. static struct trace_array *boot_trace;
  13. static bool pre_initcalls_finished;
  14. /* Tells the boot tracer that the pre_smp_initcalls are finished.
  15. * So we are ready .
  16. * It doesn't enable sched events tracing however.
  17. * You have to call enable_boot_trace to do so.
  18. */
  19. void start_boot_trace(void)
  20. {
  21. pre_initcalls_finished = true;
  22. }
  23. void enable_boot_trace(void)
  24. {
  25. if (pre_initcalls_finished)
  26. tracing_start_sched_switch_record();
  27. }
  28. void disable_boot_trace(void)
  29. {
  30. if (pre_initcalls_finished)
  31. tracing_stop_sched_switch_record();
  32. }
  33. static void reset_boot_trace(struct trace_array *tr)
  34. {
  35. int cpu;
  36. tr->time_start = ftrace_now(tr->cpu);
  37. for_each_online_cpu(cpu)
  38. tracing_reset(tr, cpu);
  39. }
  40. static int boot_trace_init(struct trace_array *tr)
  41. {
  42. int cpu;
  43. boot_trace = tr;
  44. for_each_cpu_mask(cpu, cpu_possible_map)
  45. tracing_reset(tr, cpu);
  46. tracing_sched_switch_assign_trace(tr);
  47. return 0;
  48. }
  49. static enum print_line_t
  50. initcall_call_print_line(struct trace_iterator *iter)
  51. {
  52. struct trace_entry *entry = iter->ent;
  53. struct trace_seq *s = &iter->seq;
  54. struct trace_boot_call *field;
  55. struct boot_trace_call *call;
  56. u64 ts;
  57. unsigned long nsec_rem;
  58. int ret;
  59. trace_assign_type(field, entry);
  60. call = &field->boot_call;
  61. ts = iter->ts;
  62. nsec_rem = do_div(ts, 1000000000);
  63. ret = trace_seq_printf(s, "[%5ld.%09ld] calling %s @ %i\n",
  64. (unsigned long)ts, nsec_rem, call->func, call->caller);
  65. if (!ret)
  66. return TRACE_TYPE_PARTIAL_LINE;
  67. else
  68. return TRACE_TYPE_HANDLED;
  69. }
  70. static enum print_line_t
  71. initcall_ret_print_line(struct trace_iterator *iter)
  72. {
  73. struct trace_entry *entry = iter->ent;
  74. struct trace_seq *s = &iter->seq;
  75. struct trace_boot_ret *field;
  76. struct boot_trace_ret *init_ret;
  77. u64 ts;
  78. unsigned long nsec_rem;
  79. int ret;
  80. trace_assign_type(field, entry);
  81. init_ret = &field->boot_ret;
  82. ts = iter->ts;
  83. nsec_rem = do_div(ts, 1000000000);
  84. ret = trace_seq_printf(s, "[%5ld.%09ld] initcall %s "
  85. "returned %d after %llu msecs\n",
  86. (unsigned long) ts,
  87. nsec_rem,
  88. init_ret->func, init_ret->result, init_ret->duration);
  89. if (!ret)
  90. return TRACE_TYPE_PARTIAL_LINE;
  91. else
  92. return TRACE_TYPE_HANDLED;
  93. }
  94. static enum print_line_t initcall_print_line(struct trace_iterator *iter)
  95. {
  96. struct trace_entry *entry = iter->ent;
  97. switch (entry->type) {
  98. case TRACE_BOOT_CALL:
  99. return initcall_call_print_line(iter);
  100. case TRACE_BOOT_RET:
  101. return initcall_ret_print_line(iter);
  102. default:
  103. return TRACE_TYPE_UNHANDLED;
  104. }
  105. }
  106. struct tracer boot_tracer __read_mostly =
  107. {
  108. .name = "initcall",
  109. .init = boot_trace_init,
  110. .reset = reset_boot_trace,
  111. .print_line = initcall_print_line,
  112. };
  113. void trace_boot_call(struct boot_trace_call *bt, initcall_t fn)
  114. {
  115. struct ring_buffer_event *event;
  116. struct trace_boot_call *entry;
  117. unsigned long irq_flags;
  118. struct trace_array *tr = boot_trace;
  119. if (!pre_initcalls_finished)
  120. return;
  121. /* Get its name now since this function could
  122. * disappear because it is in the .init section.
  123. */
  124. sprint_symbol(bt->func, (unsigned long)fn);
  125. preempt_disable();
  126. event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
  127. &irq_flags);
  128. if (!event)
  129. goto out;
  130. entry = ring_buffer_event_data(event);
  131. tracing_generic_entry_update(&entry->ent, 0, 0);
  132. entry->ent.type = TRACE_BOOT_CALL;
  133. entry->boot_call = *bt;
  134. ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
  135. trace_wake_up();
  136. out:
  137. preempt_enable();
  138. }
  139. void trace_boot_ret(struct boot_trace_ret *bt, initcall_t fn)
  140. {
  141. struct ring_buffer_event *event;
  142. struct trace_boot_ret *entry;
  143. unsigned long irq_flags;
  144. struct trace_array *tr = boot_trace;
  145. if (!pre_initcalls_finished)
  146. return;
  147. sprint_symbol(bt->func, (unsigned long)fn);
  148. preempt_disable();
  149. event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
  150. &irq_flags);
  151. if (!event)
  152. goto out;
  153. entry = ring_buffer_event_data(event);
  154. tracing_generic_entry_update(&entry->ent, 0, 0);
  155. entry->ent.type = TRACE_BOOT_RET;
  156. entry->boot_ret = *bt;
  157. ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
  158. trace_wake_up();
  159. out:
  160. preempt_enable();
  161. }