File: rtl_tracer.c

package info (click to toggle)
rtlinux 3.1pre3-2
  • links: PTS
  • area: non-free
  • in suites: sarge, woody
  • size: 4,892 kB
  • ctags: 4,228
  • sloc: ansic: 26,204; sh: 2,069; makefile: 1,414; perl: 855; tcl: 489; asm: 380; cpp: 42
file content (280 lines) | stat: -rw-r--r-- 6,791 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
 * (C) Finite State Machine Labs Inc. 1999-2000 <business@fsmlabs.com>
 *
 * Released under the terms of GPL 2.
 * Open RTLinux makes use of a patented process described in
 * US Patent 5,995,745. Use of this process is governed
 * by the Open RTLinux Patent License which can be obtained from
 * www.fsmlabs.com/PATENT or by sending email to
 * licensequestions@fsmlabs.com
 */

#define RTL_NOWRAP

#include <rtl_conf.h>
#ifndef CONFIG_RTL_TRACER
#error Please enable CONFIG_RTL_TRACER option and copy new rtl.mk to this directory
#endif

#include <linux/kernel.h>
#include <linux/module.h>
#include <rtl_sync.h>
#include <rtl_time.h>
#include <rtl_core.h>
#include <rtl_tracer.h>
#include <mbuff.h>

static unsigned eventmask;
static int timestamp;

struct rtl_event_descriptor_struct {
	unsigned class;
} rtl_event_descriptor[RTL_TRACE_MAX_EVENTS];

int rtl_trace_seteventclass (int event, unsigned classmask)
{
	if ((unsigned) event >= RTL_TRACE_MAX_EVENTS) {
		return -1;
	}

	rtl_event_descriptor[event].class = classmask;
	return 0;
}

static struct rtl_trace_eventinfo_struct *rtl_trace_event_info = 0;

int rtl_trace_seteventname (int event, char *name)
{
	if ((unsigned) event >= RTL_TRACE_MAX_EVENTS) {
		return -1;
	}

	strncpy(rtl_trace_event_info[event].name, name, RTL_TRACER_NAMELEN - 1);
	rtl_trace_event_info[event].name[RTL_TRACER_NAMELEN - 1] = 0;
	return 0;
}

unsigned rtl_trace_settracemask (unsigned mask)
{
	unsigned oldmask = eventmask;
	eventmask = mask;
	rtl_printf("%x\n", eventmask);
	return oldmask;
}

static struct rtl_trace_buffer *buffers;
static struct rtl_trace_buffer *cbuf;
#define CBUF (*cbuf)
static spinlock_t buffspin;

static void (*save_rtl_trace)(int event_id, long event_data, void * eip);

static int len;
static struct rtl_trace_record *cur;
static struct rtl_trace_record *ebp;
static struct rtl_trace_record *sbp;

int rtl_trace_finalize (int id);

/* #include <asm/msr.h> */
static void rtl_do_trace(int event_id, long event_data, void *eip)
{
	rtl_irqstate_t flags;
	static int in_trace = 0;
	int cpu = rtl_getcpuid();

/*	if ((unsigned) event_id >= RTL_TRACE_MAX_EVENTS) {
		return;
	} */

	if (event_id == RTL_TRACE_FINALIZE) {
		rtl_trace_finalize(1);
		return;
	}
	rtl_no_interrupts(flags);
	if (test_and_set_bit (cpu, &in_trace)) {
		/* an attempt to call rtl_do_trace recursively */
		rtl_restore_interrupts (flags);
		return;
	}

	if (rtl_event_descriptor[event_id].class & eventmask) {
		spin_lock (&buffspin);

		cur->timestamp = gethrtime();
/* 		rdtscll(cur->timestamp); */
		cur->event_id = event_id;
		cur->eip = (long) eip;
		cur->event_data = event_data;
		cur->cpu = cpu;

		++cur;
		if (len < RTL_TNRECORDS) {
			len ++;
		}
		if (cur >= ebp) {
			cur = sbp;
		}
		
		spin_unlock (&buffspin);
	}
	clear_bit (cpu, &in_trace);
	rtl_restore_interrupts (flags);
}



static inline void init_current_buffer(void)
{
	struct rtl_trace_buffer *buff = &CBUF;
	buff->state = 0;
	len = 0;
	sbp = cur = &(buff->trace[0]);
	ebp = sbp + RTL_TNRECORDS;
}

/*
static void start_trace(void)
{
	if (rtl_trace_buffer != rtl_do_trace) {
	}
}

static void stop_trace(void)
{
	rtl_trace_buffer = save_rtl_trace;
}
*/

int rtl_trace_init (void *start)
{
	int i;

	for (i = 0; i < RTL_TRACE_MAX_EVENTS; i ++) {
		rtl_trace_seteventclass(i, RTL_TRACE_CLASS_DEFAULT);
	}
	for (i = RTL_TRACE_HARD_CLI; i < RTL_TRACE_SCHED_IN; i++) {
		rtl_trace_seteventclass(i, RTL_TRACE_CLASS_INTERRUPTS);
	}
	for (i = RTL_TRACE_SCHED_IN; i <= RTL_TRACE_SCHED_CTX_SWITCH; i++) {
		rtl_trace_seteventclass(i, RTL_TRACE_CLASS_SCHEDULER);
	}
	rtl_trace_seteventclass(RTL_TRACE_USER, RTL_TRACE_CLASS_USER);

	for (i = 0; i < RTL_TRACE_MAX_EVENTS; i ++) {
		rtl_trace_seteventname(i, "unknown");
	}

	rtl_trace_seteventname(RTL_TRACE_HARD_CLI, "hard cli");
	rtl_trace_seteventname(RTL_TRACE_HARD_STI, "hard sti");
	rtl_trace_seteventname(RTL_TRACE_HARD_SAVE_FLAGS, "rtl_hard_save_flags");
	rtl_trace_seteventname(RTL_TRACE_HARD_RESTORE_FLAGS, "rtl_restore_interrupts");
	rtl_trace_seteventname(RTL_TRACE_HARD_SAVEF_AND_CLI, "rtl_no_interrupts");
	rtl_trace_seteventname(RTL_TRACE_LOCAL_INTERCEPT, "local_intercept entry");
	rtl_trace_seteventname(RTL_TRACE_LOCAL_INTERCEPT_EXIT, "local_intercept exit");
	rtl_trace_seteventname(RTL_TRACE_USER, "user");
	rtl_trace_seteventname(RTL_TRACE_SPIN_LOCK, "rtl_spin_lock");
	rtl_trace_seteventname(RTL_TRACE_SPIN_UNLOCK, "rtl_spin_unlock");
	rtl_trace_seteventname(RTL_TRACE_INTERCEPT, "rtl_intercept entry");
	rtl_trace_seteventname(RTL_TRACE_INTERCEPT_EXIT, "rtl_intercept exit");
	rtl_trace_seteventname(RTL_TRACE_SCHED_IN, "scheduler in");
	rtl_trace_seteventname(RTL_TRACE_SCHED_OUT, "scheduler out");
	rtl_trace_seteventname(RTL_TRACE_SCHED_CTX_SWITCH, "rtl_switch_to");
	rtl_trace_seteventname(RTL_TRACE_FINALIZE, "trace finalize");

	eventmask = 0xffffffff;
	timestamp = 0;
	spin_lock_init (&buffspin);
	buffers = (struct rtl_trace_buffer *) start;
	for (i = 0; i < RTL_TNBUFFERS; i++) {
		buffers [i] . state = 0;
	}
	cbuf = &buffers[0];
	init_current_buffer ();
	save_rtl_trace = rtl_trace;
	rtl_trace = rtl_do_trace;
	return 0;
}

void rtl_trace_destroy (void)
{
	rtl_trace = save_rtl_trace;
}


/* fails if no more buffers available */
int rtl_trace_finalize (int id)
{
	struct rtl_trace_buffer *b;
	rtl_irqstate_t flags;

	rtl_no_interrupts (flags);
	spin_lock (&buffspin);

	++timestamp;
	for (b = buffers; b < &buffers[RTL_TNBUFFERS]; b ++) {
		if (b != cbuf && !b->state) {
			break;
		}
	}
	
	if (b == &buffers[RTL_TNBUFFERS]) {
		init_current_buffer (); /* start all over again */
		spin_unlock (&buffspin);
		rtl_restore_interrupts (flags);
		return -1;
	}

	CBUF.id = id;
	CBUF.timestamp = timestamp;
	CBUF.len = len;
	CBUF.pos = cur - sbp;
	mb();
	CBUF.state = 1;

	cbuf = b;
	init_current_buffer ();

	spin_unlock (&buffspin);
	rtl_restore_interrupts (flags);
	return 0;
}



#ifdef MODULE

/* struct rtl_trace_buffer traces[RTL_TNBUFFERS]; */

void * shmem_ptr;

int init_module(void)
{

	shmem_ptr = mbuff_alloc (RTL_TRACER_SHMEM, sizeof(struct rtl_trace_buffer) * RTL_TNBUFFERS);
	if (!shmem_ptr) {
		printk("RTLinux Tracer: failed to allocate trace buffer\n");
		return -1;
	}
	rtl_trace_event_info = (struct rtl_trace_eventinfo_struct *) mbuff_alloc (RTL_TRACER_SHMEM_INFO, sizeof(struct rtl_trace_eventinfo_struct) * RTL_TRACE_MAX_EVENTS);
	if (!rtl_trace_event_info) {
		printk("RTLinux Tracer: failed to allocate event info buffer\n");
		mbuff_free (RTL_TRACER_SHMEM, shmem_ptr);
		return -1;
	}
/* 	printk("%x %d\n", (unsigned) shmem_ptr, sizeof(struct rtl_trace_buffer)); */

	rtl_trace_init(shmem_ptr);
	return 0;
}

void cleanup_module(void)
{
	rtl_trace_destroy();
	mbuff_free (RTL_TRACER_SHMEM, shmem_ptr);
	mbuff_free (RTL_TRACER_SHMEM_INFO, (void *) rtl_trace_event_info);
}

#endif