oprof.c 3.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/**
 * @file oprof.c
 *
 * @remark Copyright 2002 OProfile authors
 * @remark Read the file COPYING
 *
 * @author John Levon <levon@movementarian.org>
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/oprofile.h>
#include <linux/moduleparam.h>
15
#include <asm/mutex.h>
L
Linus Torvalds 已提交
16 17 18 19 20 21

#include "oprof.h"
#include "event_buffer.h"
#include "cpu_buffer.h"
#include "buffer_sync.h"
#include "oprofile_stats.h"
R
Robert Richter 已提交
22

L
Linus Torvalds 已提交
23 24 25 26
struct oprofile_operations oprofile_ops;

unsigned long oprofile_started;
unsigned long backtrace_depth;
27 28
static unsigned long is_setup;
static DEFINE_MUTEX(start_mutex);
L
Linus Torvalds 已提交
29 30 31 32 33 34 35 36 37 38

/* timer
   0 - use performance monitoring hardware if available
   1 - use the timer int mechanism regardless
 */
static int timer = 0;

int oprofile_setup(void)
{
	int err;
R
Robert Richter 已提交
39

40
	mutex_lock(&start_mutex);
L
Linus Torvalds 已提交
41 42 43 44 45 46

	if ((err = alloc_cpu_buffers()))
		goto out;

	if ((err = alloc_event_buffer()))
		goto out1;
R
Robert Richter 已提交
47

L
Linus Torvalds 已提交
48 49
	if (oprofile_ops.setup && (err = oprofile_ops.setup()))
		goto out2;
R
Robert Richter 已提交
50

L
Linus Torvalds 已提交
51 52 53 54 55
	/* Note even though this starts part of the
	 * profiling overhead, it's necessary to prevent
	 * us missing task deaths and eventually oopsing
	 * when trying to process the event buffer.
	 */
56 57 58 59 60 61 62 63 64 65 66 67 68 69
	if (oprofile_ops.sync_start) {
		int sync_ret = oprofile_ops.sync_start();
		switch (sync_ret) {
		case 0:
			goto post_sync;
		case 1:
			goto do_generic;
		case -1:
			goto out3;
		default:
			goto out3;
		}
	}
do_generic:
L
Linus Torvalds 已提交
70 71 72
	if ((err = sync_start()))
		goto out3;

73
post_sync:
L
Linus Torvalds 已提交
74
	is_setup = 1;
75
	mutex_unlock(&start_mutex);
L
Linus Torvalds 已提交
76
	return 0;
R
Robert Richter 已提交
77

L
Linus Torvalds 已提交
78 79 80 81 82 83 84 85
out3:
	if (oprofile_ops.shutdown)
		oprofile_ops.shutdown();
out2:
	free_event_buffer();
out1:
	free_cpu_buffers();
out:
86
	mutex_unlock(&start_mutex);
L
Linus Torvalds 已提交
87 88 89 90 91 92 93 94
	return err;
}


/* Actually start profiling (echo 1>/dev/oprofile/enable) */
int oprofile_start(void)
{
	int err = -EINVAL;
R
Robert Richter 已提交
95

96
	mutex_lock(&start_mutex);
97
 
L
Linus Torvalds 已提交
98 99 100
	if (!is_setup)
		goto out;

R
Robert Richter 已提交
101 102
	err = 0;

L
Linus Torvalds 已提交
103 104
	if (oprofile_started)
		goto out;
R
Robert Richter 已提交
105

L
Linus Torvalds 已提交
106 107 108 109 110 111 112
	oprofile_reset_stats();

	if ((err = oprofile_ops.start()))
		goto out;

	oprofile_started = 1;
out:
113
	mutex_unlock(&start_mutex);
L
Linus Torvalds 已提交
114 115 116
	return err;
}

R
Robert Richter 已提交
117

L
Linus Torvalds 已提交
118 119 120
/* echo 0>/dev/oprofile/enable */
void oprofile_stop(void)
{
121
	mutex_lock(&start_mutex);
L
Linus Torvalds 已提交
122 123 124 125 126 127 128
	if (!oprofile_started)
		goto out;
	oprofile_ops.stop();
	oprofile_started = 0;
	/* wake up the daemon to read what remains */
	wake_up_buffer_waiter();
out:
129
	mutex_unlock(&start_mutex);
L
Linus Torvalds 已提交
130 131 132 133 134
}


void oprofile_shutdown(void)
{
135
	mutex_lock(&start_mutex);
136 137 138 139 140 141 142 143 144 145 146 147
	if (oprofile_ops.sync_stop) {
		int sync_ret = oprofile_ops.sync_stop();
		switch (sync_ret) {
		case 0:
			goto post_sync;
		case 1:
			goto do_generic;
		default:
			goto post_sync;
		}
	}
do_generic:
L
Linus Torvalds 已提交
148
	sync_stop();
149
post_sync:
L
Linus Torvalds 已提交
150 151 152 153 154
	if (oprofile_ops.shutdown)
		oprofile_ops.shutdown();
	is_setup = 0;
	free_event_buffer();
	free_cpu_buffers();
155
	mutex_unlock(&start_mutex);
L
Linus Torvalds 已提交
156 157 158 159 160 161 162
}


int oprofile_set_backtrace(unsigned long val)
{
	int err = 0;

163
	mutex_lock(&start_mutex);
L
Linus Torvalds 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177

	if (oprofile_started) {
		err = -EBUSY;
		goto out;
	}

	if (!oprofile_ops.backtrace) {
		err = -EINVAL;
		goto out;
	}

	backtrace_depth = val;

out:
178
	mutex_unlock(&start_mutex);
L
Linus Torvalds 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
	return err;
}

static int __init oprofile_init(void)
{
	int err;

	err = oprofile_arch_init(&oprofile_ops);

	if (err < 0 || timer) {
		printk(KERN_INFO "oprofile: using timer interrupt.\n");
		oprofile_timer_init(&oprofile_ops);
	}

	err = oprofilefs_register();
	if (err)
		oprofile_arch_exit();

	return err;
}


static void __exit oprofile_exit(void)
{
	oprofilefs_unregister();
	oprofile_arch_exit();
}

R
Robert Richter 已提交
207

L
Linus Torvalds 已提交
208 209 210 211 212
module_init(oprofile_init);
module_exit(oprofile_exit);

module_param_named(timer, timer, int, 0644);
MODULE_PARM_DESC(timer, "force use of timer interrupt");
R
Robert Richter 已提交
213

L
Linus Torvalds 已提交
214 215 216
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Levon <levon@movementarian.org>");
MODULE_DESCRIPTION("OProfile system profiler");