oprof.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /**
  2. * @file oprof.c
  3. *
  4. * @remark Copyright 2002 OProfile authors
  5. * @remark Read the file COPYING
  6. *
  7. * @author John Levon <levon@movementarian.org>
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/module.h>
  11. #include <linux/init.h>
  12. #include <linux/oprofile.h>
  13. #include <linux/moduleparam.h>
  14. #include <linux/workqueue.h>
  15. #include <linux/time.h>
  16. #include <asm/mutex.h>
  17. #include "oprof.h"
  18. #include "event_buffer.h"
  19. #include "cpu_buffer.h"
  20. #include "buffer_sync.h"
  21. #include "oprofile_stats.h"
  22. struct oprofile_operations oprofile_ops;
  23. unsigned long oprofile_started;
  24. unsigned long oprofile_backtrace_depth;
  25. static unsigned long is_setup;
  26. static DEFINE_MUTEX(start_mutex);
  27. #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
  28. static void switch_worker(struct work_struct *work);
  29. static DECLARE_DELAYED_WORK(switch_work, switch_worker);
  30. #endif
  31. /* timer
  32. 0 - use performance monitoring hardware if available
  33. 1 - use the timer int mechanism regardless
  34. */
  35. static int timer = 0;
  36. int oprofile_setup(void)
  37. {
  38. int err;
  39. mutex_lock(&start_mutex);
  40. if ((err = alloc_cpu_buffers()))
  41. goto out;
  42. if ((err = alloc_event_buffer()))
  43. goto out1;
  44. if (oprofile_ops.setup && (err = oprofile_ops.setup()))
  45. goto out2;
  46. /* Note even though this starts part of the
  47. * profiling overhead, it's necessary to prevent
  48. * us missing task deaths and eventually oopsing
  49. * when trying to process the event buffer.
  50. */
  51. if (oprofile_ops.sync_start) {
  52. int sync_ret = oprofile_ops.sync_start();
  53. switch (sync_ret) {
  54. case 0:
  55. goto post_sync;
  56. case 1:
  57. goto do_generic;
  58. case -1:
  59. goto out3;
  60. default:
  61. goto out3;
  62. }
  63. }
  64. do_generic:
  65. if ((err = sync_start()))
  66. goto out3;
  67. post_sync:
  68. is_setup = 1;
  69. mutex_unlock(&start_mutex);
  70. return 0;
  71. out3:
  72. if (oprofile_ops.shutdown)
  73. oprofile_ops.shutdown();
  74. out2:
  75. free_event_buffer();
  76. out1:
  77. free_cpu_buffers();
  78. out:
  79. mutex_unlock(&start_mutex);
  80. return err;
  81. }
  82. #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
  83. static void start_switch_worker(void)
  84. {
  85. schedule_delayed_work(&switch_work, oprofile_time_slice);
  86. }
  87. static void switch_worker(struct work_struct *work)
  88. {
  89. if (!oprofile_ops.switch_events())
  90. start_switch_worker();
  91. }
  92. #endif
  93. /* Actually start profiling (echo 1>/dev/oprofile/enable) */
  94. int oprofile_start(void)
  95. {
  96. int err = -EINVAL;
  97. mutex_lock(&start_mutex);
  98. if (!is_setup)
  99. goto out;
  100. err = 0;
  101. if (oprofile_started)
  102. goto out;
  103. oprofile_reset_stats();
  104. if ((err = oprofile_ops.start()))
  105. goto out;
  106. #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
  107. if (oprofile_ops.switch_events)
  108. start_switch_worker();
  109. #endif
  110. oprofile_started = 1;
  111. out:
  112. mutex_unlock(&start_mutex);
  113. return err;
  114. }
  115. /* echo 0>/dev/oprofile/enable */
  116. void oprofile_stop(void)
  117. {
  118. mutex_lock(&start_mutex);
  119. if (!oprofile_started)
  120. goto out;
  121. oprofile_ops.stop();
  122. oprofile_started = 0;
  123. #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
  124. cancel_delayed_work_sync(&switch_work);
  125. #endif
  126. /* wake up the daemon to read what remains */
  127. wake_up_buffer_waiter();
  128. out:
  129. mutex_unlock(&start_mutex);
  130. }
  131. void oprofile_shutdown(void)
  132. {
  133. mutex_lock(&start_mutex);
  134. if (oprofile_ops.sync_stop) {
  135. int sync_ret = oprofile_ops.sync_stop();
  136. switch (sync_ret) {
  137. case 0:
  138. goto post_sync;
  139. case 1:
  140. goto do_generic;
  141. default:
  142. goto post_sync;
  143. }
  144. }
  145. do_generic:
  146. sync_stop();
  147. post_sync:
  148. if (oprofile_ops.shutdown)
  149. oprofile_ops.shutdown();
  150. is_setup = 0;
  151. free_event_buffer();
  152. free_cpu_buffers();
  153. mutex_unlock(&start_mutex);
  154. }
  155. #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
  156. /* User inputs in ms, converts to jiffies */
  157. int oprofile_set_timeout(unsigned long val_msec)
  158. {
  159. int err = 0;
  160. unsigned long time_slice;
  161. mutex_lock(&start_mutex);
  162. if (oprofile_started) {
  163. err = -EBUSY;
  164. goto out;
  165. }
  166. if (!oprofile_ops.switch_events) {
  167. err = -EINVAL;
  168. goto out;
  169. }
  170. time_slice = msecs_to_jiffies(val_msec);
  171. if (time_slice == MAX_JIFFY_OFFSET) {
  172. err = -EINVAL;
  173. goto out;
  174. }
  175. oprofile_time_slice = time_slice;
  176. out:
  177. mutex_unlock(&start_mutex);
  178. return err;
  179. }
  180. #endif
  181. int oprofile_set_backtrace(unsigned long val)
  182. {
  183. int err = 0;
  184. mutex_lock(&start_mutex);
  185. if (oprofile_started) {
  186. err = -EBUSY;
  187. goto out;
  188. }
  189. if (!oprofile_ops.backtrace) {
  190. err = -EINVAL;
  191. goto out;
  192. }
  193. oprofile_backtrace_depth = val;
  194. out:
  195. mutex_unlock(&start_mutex);
  196. return err;
  197. }
  198. static int __init oprofile_init(void)
  199. {
  200. int err;
  201. err = oprofile_arch_init(&oprofile_ops);
  202. if (err < 0 || timer) {
  203. printk(KERN_INFO "oprofile: using timer interrupt.\n");
  204. oprofile_timer_init(&oprofile_ops);
  205. }
  206. err = oprofilefs_register();
  207. if (err)
  208. oprofile_arch_exit();
  209. return err;
  210. }
  211. static void __exit oprofile_exit(void)
  212. {
  213. oprofilefs_unregister();
  214. oprofile_arch_exit();
  215. }
  216. module_init(oprofile_init);
  217. module_exit(oprofile_exit);
  218. module_param_named(timer, timer, int, 0644);
  219. MODULE_PARM_DESC(timer, "force use of timer interrupt");
  220. MODULE_LICENSE("GPL");
  221. MODULE_AUTHOR("John Levon <levon@movementarian.org>");
  222. MODULE_DESCRIPTION("OProfile system profiler");