oprof.c 4.8 KB

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