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 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/init.h> 13#include <linux/oprofile.h> 14#include <linux/moduleparam.h> 15#include <asm/mutex.h> 16 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 23struct oprofile_operations oprofile_ops; 24 25unsigned long oprofile_started; 26unsigned long backtrace_depth; 27static unsigned long is_setup; 28static DEFINE_MUTEX(start_mutex); 29 30/* timer 31 0 - use performance monitoring hardware if available 32 1 - use the timer int mechanism regardless 33 */ 34static int timer = 0; 35 36int oprofile_setup(void) 37{ 38 int err; 39 40 mutex_lock(&start_mutex); 41 42 if ((err = alloc_cpu_buffers())) 43 goto out; 44 45 if ((err = alloc_event_buffer())) 46 goto out1; 47 48 if (oprofile_ops.setup && (err = oprofile_ops.setup())) 49 goto out2; 50 51 /* Note even though this starts part of the 52 * profiling overhead, it's necessary to prevent 53 * us missing task deaths and eventually oopsing 54 * when trying to process the event buffer. 55 */ 56 if ((err = sync_start())) 57 goto out3; 58 59 is_setup = 1; 60 mutex_unlock(&start_mutex); 61 return 0; 62 63out3: 64 if (oprofile_ops.shutdown) 65 oprofile_ops.shutdown(); 66out2: 67 free_event_buffer(); 68out1: 69 free_cpu_buffers(); 70out: 71 mutex_unlock(&start_mutex); 72 return err; 73} 74 75 76/* Actually start profiling (echo 1>/dev/oprofile/enable) */ 77int oprofile_start(void) 78{ 79 int err = -EINVAL; 80 81 mutex_lock(&start_mutex); 82 83 if (!is_setup) 84 goto out; 85 86 err = 0; 87 88 if (oprofile_started) 89 goto out; 90 91 oprofile_reset_stats(); 92 93 if ((err = oprofile_ops.start())) 94 goto out; 95 96 oprofile_started = 1; 97out: 98 mutex_unlock(&start_mutex); 99 return err; 100} 101 102 103/* echo 0>/dev/oprofile/enable */ 104void oprofile_stop(void) 105{ 106 mutex_lock(&start_mutex); 107 if (!oprofile_started) 108 goto out; 109 oprofile_ops.stop(); 110 oprofile_started = 0; 111 /* wake up the daemon to read what remains */ 112 wake_up_buffer_waiter(); 113out: 114 mutex_unlock(&start_mutex); 115} 116 117 118void oprofile_shutdown(void) 119{ 120 mutex_lock(&start_mutex); 121 sync_stop(); 122 if (oprofile_ops.shutdown) 123 oprofile_ops.shutdown(); 124 is_setup = 0; 125 free_event_buffer(); 126 free_cpu_buffers(); 127 mutex_unlock(&start_mutex); 128} 129 130 131int oprofile_set_backtrace(unsigned long val) 132{ 133 int err = 0; 134 135 mutex_lock(&start_mutex); 136 137 if (oprofile_started) { 138 err = -EBUSY; 139 goto out; 140 } 141 142 if (!oprofile_ops.backtrace) { 143 err = -EINVAL; 144 goto out; 145 } 146 147 backtrace_depth = val; 148 149out: 150 mutex_unlock(&start_mutex); 151 return err; 152} 153 154static int __init oprofile_init(void) 155{ 156 int err; 157 158 err = oprofile_arch_init(&oprofile_ops); 159 160 if (err < 0 || timer) { 161 printk(KERN_INFO "oprofile: using timer interrupt.\n"); 162 oprofile_timer_init(&oprofile_ops); 163 } 164 165 err = oprofilefs_register(); 166 if (err) 167 oprofile_arch_exit(); 168 169 return err; 170} 171 172 173static void __exit oprofile_exit(void) 174{ 175 oprofilefs_unregister(); 176 oprofile_arch_exit(); 177} 178 179 180module_init(oprofile_init); 181module_exit(oprofile_exit); 182 183module_param_named(timer, timer, int, 0644); 184MODULE_PARM_DESC(timer, "force use of timer interrupt"); 185 186MODULE_LICENSE("GPL"); 187MODULE_AUTHOR("John Levon <levon@movementarian.org>"); 188MODULE_DESCRIPTION("OProfile system profiler"); 189