trace_workqueue.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * Workqueue statistical tracer.
  3. *
  4. * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
  5. *
  6. */
  7. #include <trace/workqueue.h>
  8. #include <linux/list.h>
  9. #include "trace_stat.h"
  10. #include "trace.h"
  11. /* A cpu workqueue thread */
  12. struct cpu_workqueue_stats {
  13. struct list_head list;
  14. /* Useful to know if we print the cpu headers */
  15. bool first_entry;
  16. int cpu;
  17. pid_t pid;
  18. /* Can be inserted from interrupt or user context, need to be atomic */
  19. atomic_t inserted;
  20. /*
  21. * Don't need to be atomic, works are serialized in a single workqueue thread
  22. * on a single CPU.
  23. */
  24. unsigned int executed;
  25. };
  26. /* List of workqueue threads on one cpu */
  27. struct workqueue_global_stats {
  28. struct list_head list;
  29. spinlock_t lock;
  30. };
  31. /* Don't need a global lock because allocated before the workqueues, and
  32. * never freed.
  33. */
  34. static struct workqueue_global_stats *all_workqueue_stat;
  35. /* Insertion of a work */
  36. static void
  37. probe_workqueue_insertion(struct task_struct *wq_thread,
  38. struct work_struct *work)
  39. {
  40. int cpu = cpumask_first(&wq_thread->cpus_allowed);
  41. struct cpu_workqueue_stats *node, *next;
  42. unsigned long flags;
  43. spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags);
  44. list_for_each_entry_safe(node, next, &all_workqueue_stat[cpu].list,
  45. list) {
  46. if (node->pid == wq_thread->pid) {
  47. atomic_inc(&node->inserted);
  48. goto found;
  49. }
  50. }
  51. pr_debug("trace_workqueue: entry not found\n");
  52. found:
  53. spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags);
  54. }
  55. /* Execution of a work */
  56. static void
  57. probe_workqueue_execution(struct task_struct *wq_thread,
  58. struct work_struct *work)
  59. {
  60. int cpu = cpumask_first(&wq_thread->cpus_allowed);
  61. struct cpu_workqueue_stats *node, *next;
  62. unsigned long flags;
  63. spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags);
  64. list_for_each_entry_safe(node, next, &all_workqueue_stat[cpu].list,
  65. list) {
  66. if (node->pid == wq_thread->pid) {
  67. node->executed++;
  68. goto found;
  69. }
  70. }
  71. pr_debug("trace_workqueue: entry not found\n");
  72. found:
  73. spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags);
  74. }
  75. /* Creation of a cpu workqueue thread */
  76. static void probe_workqueue_creation(struct task_struct *wq_thread, int cpu)
  77. {
  78. struct cpu_workqueue_stats *cws;
  79. unsigned long flags;
  80. WARN_ON(cpu < 0 || cpu >= num_possible_cpus());
  81. /* Workqueues are sometimes created in atomic context */
  82. cws = kzalloc(sizeof(struct cpu_workqueue_stats), GFP_ATOMIC);
  83. if (!cws) {
  84. pr_warning("trace_workqueue: not enough memory\n");
  85. return;
  86. }
  87. tracing_record_cmdline(wq_thread);
  88. INIT_LIST_HEAD(&cws->list);
  89. cws->cpu = cpu;
  90. cws->pid = wq_thread->pid;
  91. spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags);
  92. if (list_empty(&all_workqueue_stat[cpu].list))
  93. cws->first_entry = true;
  94. list_add_tail(&cws->list, &all_workqueue_stat[cpu].list);
  95. spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags);
  96. }
  97. /* Destruction of a cpu workqueue thread */
  98. static void probe_workqueue_destruction(struct task_struct *wq_thread)
  99. {
  100. /* Workqueue only execute on one cpu */
  101. int cpu = cpumask_first(&wq_thread->cpus_allowed);
  102. struct cpu_workqueue_stats *node, *next;
  103. unsigned long flags;
  104. spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags);
  105. list_for_each_entry_safe(node, next, &all_workqueue_stat[cpu].list,
  106. list) {
  107. if (node->pid == wq_thread->pid) {
  108. list_del(&node->list);
  109. kfree(node);
  110. goto found;
  111. }
  112. }
  113. pr_debug("trace_workqueue: don't find workqueue to destroy\n");
  114. found:
  115. spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags);
  116. }
  117. static struct cpu_workqueue_stats *workqueue_stat_start_cpu(int cpu)
  118. {
  119. unsigned long flags;
  120. struct cpu_workqueue_stats *ret = NULL;
  121. spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags);
  122. if (!list_empty(&all_workqueue_stat[cpu].list))
  123. ret = list_entry(all_workqueue_stat[cpu].list.next,
  124. struct cpu_workqueue_stats, list);
  125. spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags);
  126. return ret;
  127. }
  128. static void *workqueue_stat_start(void)
  129. {
  130. int cpu;
  131. void *ret = NULL;
  132. for_each_possible_cpu(cpu) {
  133. ret = workqueue_stat_start_cpu(cpu);
  134. if (ret)
  135. return ret;
  136. }
  137. return NULL;
  138. }
  139. static void *workqueue_stat_next(void *prev, int idx)
  140. {
  141. struct cpu_workqueue_stats *prev_cws = prev;
  142. int cpu = prev_cws->cpu;
  143. unsigned long flags;
  144. void *ret = NULL;
  145. spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags);
  146. if (list_is_last(&prev_cws->list, &all_workqueue_stat[cpu].list)) {
  147. spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags);
  148. for (++cpu ; cpu < num_possible_cpus(); cpu++) {
  149. ret = workqueue_stat_start_cpu(cpu);
  150. if (ret)
  151. return ret;
  152. }
  153. return NULL;
  154. }
  155. spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags);
  156. return list_entry(prev_cws->list.next, struct cpu_workqueue_stats,
  157. list);
  158. }
  159. static int workqueue_stat_show(struct seq_file *s, void *p)
  160. {
  161. struct cpu_workqueue_stats *cws = p;
  162. unsigned long flags;
  163. int cpu = cws->cpu;
  164. seq_printf(s, "%3d %6d %6u %s\n", cws->cpu,
  165. atomic_read(&cws->inserted),
  166. cws->executed,
  167. trace_find_cmdline(cws->pid));
  168. spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags);
  169. if (&cws->list == all_workqueue_stat[cpu].list.next)
  170. seq_printf(s, "\n");
  171. spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags);
  172. return 0;
  173. }
  174. static int workqueue_stat_headers(struct seq_file *s)
  175. {
  176. seq_printf(s, "# CPU INSERTED EXECUTED NAME\n");
  177. seq_printf(s, "# | | | |\n\n");
  178. return 0;
  179. }
  180. struct tracer_stat workqueue_stats __read_mostly = {
  181. .name = "workqueues",
  182. .stat_start = workqueue_stat_start,
  183. .stat_next = workqueue_stat_next,
  184. .stat_show = workqueue_stat_show,
  185. .stat_headers = workqueue_stat_headers
  186. };
  187. int __init stat_workqueue_init(void)
  188. {
  189. if (register_stat_tracer(&workqueue_stats)) {
  190. pr_warning("Unable to register workqueue stat tracer\n");
  191. return 1;
  192. }
  193. return 0;
  194. }
  195. fs_initcall(stat_workqueue_init);
  196. /*
  197. * Workqueues are created very early, just after pre-smp initcalls.
  198. * So we must register our tracepoints at this stage.
  199. */
  200. int __init trace_workqueue_early_init(void)
  201. {
  202. int ret, cpu;
  203. ret = register_trace_workqueue_insertion(probe_workqueue_insertion);
  204. if (ret)
  205. goto out;
  206. ret = register_trace_workqueue_execution(probe_workqueue_execution);
  207. if (ret)
  208. goto no_insertion;
  209. ret = register_trace_workqueue_creation(probe_workqueue_creation);
  210. if (ret)
  211. goto no_execution;
  212. ret = register_trace_workqueue_destruction(probe_workqueue_destruction);
  213. if (ret)
  214. goto no_creation;
  215. all_workqueue_stat = kmalloc(sizeof(struct workqueue_global_stats)
  216. * num_possible_cpus(), GFP_KERNEL);
  217. if (!all_workqueue_stat) {
  218. pr_warning("trace_workqueue: not enough memory\n");
  219. goto no_creation;
  220. }
  221. for_each_possible_cpu(cpu) {
  222. spin_lock_init(&all_workqueue_stat[cpu].lock);
  223. INIT_LIST_HEAD(&all_workqueue_stat[cpu].list);
  224. }
  225. return 0;
  226. no_creation:
  227. unregister_trace_workqueue_creation(probe_workqueue_creation);
  228. no_execution:
  229. unregister_trace_workqueue_execution(probe_workqueue_execution);
  230. no_insertion:
  231. unregister_trace_workqueue_insertion(probe_workqueue_insertion);
  232. out:
  233. pr_warning("trace_workqueue: unable to trace workqueues\n");
  234. return 1;
  235. }
  236. early_initcall(trace_workqueue_early_init);