trace_sched_wakeup.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. * trace task wakeup timings
  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/module.h>
  13. #include <linux/fs.h>
  14. #include <linux/debugfs.h>
  15. #include <linux/kallsyms.h>
  16. #include <linux/uaccess.h>
  17. #include <linux/ftrace.h>
  18. #include <trace/sched.h>
  19. #include "trace.h"
  20. static struct trace_array *wakeup_trace;
  21. static int __read_mostly tracer_enabled;
  22. static struct task_struct *wakeup_task;
  23. static int wakeup_cpu;
  24. static unsigned wakeup_prio = -1;
  25. static int wakeup_rt;
  26. static raw_spinlock_t wakeup_lock =
  27. (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
  28. static void __wakeup_reset(struct trace_array *tr);
  29. #ifdef CONFIG_FUNCTION_TRACER
  30. /*
  31. * irqsoff uses its own tracer function to keep the overhead down:
  32. */
  33. static void
  34. wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
  35. {
  36. struct trace_array *tr = wakeup_trace;
  37. struct trace_array_cpu *data;
  38. unsigned long flags;
  39. long disabled;
  40. int resched;
  41. int cpu;
  42. int pc;
  43. if (likely(!wakeup_task))
  44. return;
  45. pc = preempt_count();
  46. resched = ftrace_preempt_disable();
  47. cpu = raw_smp_processor_id();
  48. data = tr->data[cpu];
  49. disabled = atomic_inc_return(&data->disabled);
  50. if (unlikely(disabled != 1))
  51. goto out;
  52. local_irq_save(flags);
  53. __raw_spin_lock(&wakeup_lock);
  54. if (unlikely(!wakeup_task))
  55. goto unlock;
  56. /*
  57. * The task can't disappear because it needs to
  58. * wake up first, and we have the wakeup_lock.
  59. */
  60. if (task_cpu(wakeup_task) != cpu)
  61. goto unlock;
  62. trace_function(tr, ip, parent_ip, flags, pc);
  63. unlock:
  64. __raw_spin_unlock(&wakeup_lock);
  65. local_irq_restore(flags);
  66. out:
  67. atomic_dec(&data->disabled);
  68. ftrace_preempt_enable(resched);
  69. }
  70. static struct ftrace_ops trace_ops __read_mostly =
  71. {
  72. .func = wakeup_tracer_call,
  73. };
  74. #endif /* CONFIG_FUNCTION_TRACER */
  75. /*
  76. * Should this new latency be reported/recorded?
  77. */
  78. static int report_latency(cycle_t delta)
  79. {
  80. if (tracing_thresh) {
  81. if (delta < tracing_thresh)
  82. return 0;
  83. } else {
  84. if (delta <= tracing_max_latency)
  85. return 0;
  86. }
  87. return 1;
  88. }
  89. static void notrace
  90. probe_wakeup_sched_switch(struct rq *rq, struct task_struct *prev,
  91. struct task_struct *next)
  92. {
  93. unsigned long latency = 0, t0 = 0, t1 = 0;
  94. struct trace_array_cpu *data;
  95. cycle_t T0, T1, delta;
  96. unsigned long flags;
  97. long disabled;
  98. int cpu;
  99. int pc;
  100. tracing_record_cmdline(prev);
  101. if (unlikely(!tracer_enabled))
  102. return;
  103. /*
  104. * When we start a new trace, we set wakeup_task to NULL
  105. * and then set tracer_enabled = 1. We want to make sure
  106. * that another CPU does not see the tracer_enabled = 1
  107. * and the wakeup_task with an older task, that might
  108. * actually be the same as next.
  109. */
  110. smp_rmb();
  111. if (next != wakeup_task)
  112. return;
  113. pc = preempt_count();
  114. /* The task we are waiting for is waking up */
  115. data = wakeup_trace->data[wakeup_cpu];
  116. /* disable local data, not wakeup_cpu data */
  117. cpu = raw_smp_processor_id();
  118. disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled);
  119. if (likely(disabled != 1))
  120. goto out;
  121. local_irq_save(flags);
  122. __raw_spin_lock(&wakeup_lock);
  123. /* We could race with grabbing wakeup_lock */
  124. if (unlikely(!tracer_enabled || next != wakeup_task))
  125. goto out_unlock;
  126. trace_function(wakeup_trace, CALLER_ADDR1, CALLER_ADDR2, flags, pc);
  127. tracing_sched_switch_trace(wakeup_trace, prev, next, flags, pc);
  128. /*
  129. * usecs conversion is slow so we try to delay the conversion
  130. * as long as possible:
  131. */
  132. T0 = data->preempt_timestamp;
  133. T1 = ftrace_now(cpu);
  134. delta = T1-T0;
  135. if (!report_latency(delta))
  136. goto out_unlock;
  137. latency = nsecs_to_usecs(delta);
  138. tracing_max_latency = delta;
  139. t0 = nsecs_to_usecs(T0);
  140. t1 = nsecs_to_usecs(T1);
  141. update_max_tr(wakeup_trace, wakeup_task, wakeup_cpu);
  142. out_unlock:
  143. __wakeup_reset(wakeup_trace);
  144. __raw_spin_unlock(&wakeup_lock);
  145. local_irq_restore(flags);
  146. out:
  147. atomic_dec(&wakeup_trace->data[cpu]->disabled);
  148. }
  149. static void __wakeup_reset(struct trace_array *tr)
  150. {
  151. int cpu;
  152. for_each_possible_cpu(cpu)
  153. tracing_reset(tr, cpu);
  154. wakeup_cpu = -1;
  155. wakeup_prio = -1;
  156. if (wakeup_task)
  157. put_task_struct(wakeup_task);
  158. wakeup_task = NULL;
  159. }
  160. static void wakeup_reset(struct trace_array *tr)
  161. {
  162. unsigned long flags;
  163. local_irq_save(flags);
  164. __raw_spin_lock(&wakeup_lock);
  165. __wakeup_reset(tr);
  166. __raw_spin_unlock(&wakeup_lock);
  167. local_irq_restore(flags);
  168. }
  169. static void
  170. probe_wakeup(struct rq *rq, struct task_struct *p, int success)
  171. {
  172. struct trace_array_cpu *data;
  173. int cpu = smp_processor_id();
  174. unsigned long flags;
  175. long disabled;
  176. int pc;
  177. if (likely(!tracer_enabled))
  178. return;
  179. tracing_record_cmdline(p);
  180. tracing_record_cmdline(current);
  181. if ((wakeup_rt && !rt_task(p)) ||
  182. p->prio >= wakeup_prio ||
  183. p->prio >= current->prio)
  184. return;
  185. pc = preempt_count();
  186. disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled);
  187. if (unlikely(disabled != 1))
  188. goto out;
  189. /* interrupts should be off from try_to_wake_up */
  190. __raw_spin_lock(&wakeup_lock);
  191. /* check for races. */
  192. if (!tracer_enabled || p->prio >= wakeup_prio)
  193. goto out_locked;
  194. /* reset the trace */
  195. __wakeup_reset(wakeup_trace);
  196. wakeup_cpu = task_cpu(p);
  197. wakeup_prio = p->prio;
  198. wakeup_task = p;
  199. get_task_struct(wakeup_task);
  200. local_save_flags(flags);
  201. data = wakeup_trace->data[wakeup_cpu];
  202. data->preempt_timestamp = ftrace_now(cpu);
  203. tracing_sched_wakeup_trace(wakeup_trace, p, current, flags, pc);
  204. trace_function(wakeup_trace, CALLER_ADDR1, CALLER_ADDR2, flags, pc);
  205. out_locked:
  206. __raw_spin_unlock(&wakeup_lock);
  207. out:
  208. atomic_dec(&wakeup_trace->data[cpu]->disabled);
  209. }
  210. static void start_wakeup_tracer(struct trace_array *tr)
  211. {
  212. int ret;
  213. ret = register_trace_sched_wakeup(probe_wakeup);
  214. if (ret) {
  215. pr_info("wakeup trace: Couldn't activate tracepoint"
  216. " probe to kernel_sched_wakeup\n");
  217. return;
  218. }
  219. ret = register_trace_sched_wakeup_new(probe_wakeup);
  220. if (ret) {
  221. pr_info("wakeup trace: Couldn't activate tracepoint"
  222. " probe to kernel_sched_wakeup_new\n");
  223. goto fail_deprobe;
  224. }
  225. ret = register_trace_sched_switch(probe_wakeup_sched_switch);
  226. if (ret) {
  227. pr_info("sched trace: Couldn't activate tracepoint"
  228. " probe to kernel_sched_switch\n");
  229. goto fail_deprobe_wake_new;
  230. }
  231. wakeup_reset(tr);
  232. /*
  233. * Don't let the tracer_enabled = 1 show up before
  234. * the wakeup_task is reset. This may be overkill since
  235. * wakeup_reset does a spin_unlock after setting the
  236. * wakeup_task to NULL, but I want to be safe.
  237. * This is a slow path anyway.
  238. */
  239. smp_wmb();
  240. register_ftrace_function(&trace_ops);
  241. if (tracing_is_enabled())
  242. tracer_enabled = 1;
  243. else
  244. tracer_enabled = 0;
  245. return;
  246. fail_deprobe_wake_new:
  247. unregister_trace_sched_wakeup_new(probe_wakeup);
  248. fail_deprobe:
  249. unregister_trace_sched_wakeup(probe_wakeup);
  250. }
  251. static void stop_wakeup_tracer(struct trace_array *tr)
  252. {
  253. tracer_enabled = 0;
  254. unregister_ftrace_function(&trace_ops);
  255. unregister_trace_sched_switch(probe_wakeup_sched_switch);
  256. unregister_trace_sched_wakeup_new(probe_wakeup);
  257. unregister_trace_sched_wakeup(probe_wakeup);
  258. }
  259. static int __wakeup_tracer_init(struct trace_array *tr)
  260. {
  261. tracing_max_latency = 0;
  262. wakeup_trace = tr;
  263. start_wakeup_tracer(tr);
  264. return 0;
  265. }
  266. static int wakeup_tracer_init(struct trace_array *tr)
  267. {
  268. wakeup_rt = 0;
  269. return __wakeup_tracer_init(tr);
  270. }
  271. static int wakeup_rt_tracer_init(struct trace_array *tr)
  272. {
  273. wakeup_rt = 1;
  274. return __wakeup_tracer_init(tr);
  275. }
  276. static void wakeup_tracer_reset(struct trace_array *tr)
  277. {
  278. stop_wakeup_tracer(tr);
  279. /* make sure we put back any tasks we are tracing */
  280. wakeup_reset(tr);
  281. }
  282. static void wakeup_tracer_start(struct trace_array *tr)
  283. {
  284. wakeup_reset(tr);
  285. tracer_enabled = 1;
  286. }
  287. static void wakeup_tracer_stop(struct trace_array *tr)
  288. {
  289. tracer_enabled = 0;
  290. }
  291. static struct tracer wakeup_tracer __read_mostly =
  292. {
  293. .name = "wakeup",
  294. .init = wakeup_tracer_init,
  295. .reset = wakeup_tracer_reset,
  296. .start = wakeup_tracer_start,
  297. .stop = wakeup_tracer_stop,
  298. .print_max = 1,
  299. #ifdef CONFIG_FTRACE_SELFTEST
  300. .selftest = trace_selftest_startup_wakeup,
  301. #endif
  302. };
  303. static struct tracer wakeup_rt_tracer __read_mostly =
  304. {
  305. .name = "wakeup_rt",
  306. .init = wakeup_rt_tracer_init,
  307. .reset = wakeup_tracer_reset,
  308. .start = wakeup_tracer_start,
  309. .stop = wakeup_tracer_stop,
  310. .print_max = 1,
  311. #ifdef CONFIG_FTRACE_SELFTEST
  312. .selftest = trace_selftest_startup_wakeup,
  313. #endif
  314. };
  315. __init static int init_wakeup_tracer(void)
  316. {
  317. int ret;
  318. ret = register_tracer(&wakeup_tracer);
  319. if (ret)
  320. return ret;
  321. ret = register_tracer(&wakeup_rt_tracer);
  322. if (ret)
  323. return ret;
  324. return 0;
  325. }
  326. device_initcall(init_wakeup_tracer);