• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file daemon/opd_trans.c
3  * Processing the sample buffer
4  *
5  * @remark Copyright 2002 OProfile authors
6  * @remark Read the file COPYING
7  *
8  * @author John Levon
9  * @author Philippe Elie
10  * Modified by Aravind Menon for Xen
11  * These modifications are:
12  * Copyright (C) 2005 Hewlett-Packard Co.
13  *
14  * Modified by Maynard Johnson <maynardj@us.ibm.com>
15  * These modifications are:
16  * (C) Copyright IBM Corporation 2007
17  */
18 
19 #include "opd_trans.h"
20 #include "opd_kernel.h"
21 #include "opd_sfile.h"
22 #include "opd_anon.h"
23 #include "opd_stats.h"
24 #include "opd_printf.h"
25 #include "opd_interface.h"
26 
27 #include <limits.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <stdio.h>
32 #include <errno.h>
33 
34 extern size_t kernel_pointer_size;
35 
36 
clear_trans_last(struct transient * trans)37 void clear_trans_last(struct transient * trans)
38 {
39 	trans->last = NULL;
40 	trans->last_anon = NULL;
41 }
42 
43 
clear_trans_current(struct transient * trans)44 void clear_trans_current(struct transient * trans)
45 {
46 	trans->current = NULL;
47 	trans->anon = NULL;
48 }
49 
50 
pop_buffer_value(struct transient * trans)51 uint64_t pop_buffer_value(struct transient * trans)
52 {
53 	uint64_t val;
54 
55 	if (!trans->remaining) {
56 		fprintf(stderr, "BUG: popping empty buffer !\n");
57 		abort();
58 	}
59 
60 	if (kernel_pointer_size == 4) {
61 		uint32_t const * lbuf = (void const *)trans->buffer;
62 		val = *lbuf;
63 	} else {
64 		uint64_t const * lbuf = (void const *)trans->buffer;
65 		val = *lbuf;
66 	}
67 
68 	trans->remaining--;
69 	trans->buffer += kernel_pointer_size;
70 	return val;
71 }
72 
73 
enough_remaining(struct transient * trans,size_t size)74 int enough_remaining(struct transient * trans, size_t size)
75 {
76 	if (trans->remaining >= size)
77 		return 1;
78 
79 	verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
80 	opd_stats[OPD_DANGLING_CODE]++;
81 	return 0;
82 }
83 
84 
opd_put_sample(struct transient * trans,unsigned long long pc)85 static void opd_put_sample(struct transient * trans, unsigned long long pc)
86 {
87 	unsigned long long event;
88 
89 	if (!enough_remaining(trans, 1)) {
90 		trans->remaining = 0;
91 		return;
92 	}
93 
94 	event = pop_buffer_value(trans);
95 
96 	if (trans->tracing != TRACING_ON)
97 		trans->event = event;
98 
99 	trans->pc = pc;
100 
101 	/* sfile can change at each sample for kernel */
102 	if (trans->in_kernel != 0)
103 		clear_trans_current(trans);
104 
105 	if (!trans->in_kernel && trans->cookie == NO_COOKIE)
106 		trans->anon = find_anon_mapping(trans);
107 
108 	/* get the current sfile if needed */
109 	if (!trans->current)
110 		trans->current = sfile_find(trans);
111 
112 	/*
113 	 * can happen if kernel sample falls through the cracks, or if
114 	 * it's a sample from an anon region we couldn't find
115 	 */
116 	if (!trans->current)
117 		goto out;
118 
119 	/* FIXME: this logic is perhaps too harsh? */
120 	if (trans->current->ignored || (trans->last && trans->last->ignored))
121 		goto out;
122 
123 	/* log the sample or arc */
124 	sfile_log_sample(trans);
125 
126 out:
127 	/* switch to trace mode */
128 	if (trans->tracing == TRACING_START)
129 		trans->tracing = TRACING_ON;
130 
131 	update_trans_last(trans);
132 }
133 
134 
code_unknown(struct transient * trans)135 static void code_unknown(struct transient * trans __attribute__((unused)))
136 {
137 	fprintf(stderr, "Unknown code !\n");
138 	abort();
139 }
140 
141 
code_ctx_switch(struct transient * trans)142 static void code_ctx_switch(struct transient * trans)
143 {
144 	clear_trans_current(trans);
145 
146 	if (!enough_remaining(trans, 5)) {
147 		trans->remaining = 0;
148 		return;
149 	}
150 
151 	trans->tid = pop_buffer_value(trans);
152 	trans->app_cookie = pop_buffer_value(trans);
153 	/* must be ESCAPE_CODE, CTX_TGID_CODE, tgid. Like this
154 	 * because tgid was added later in a compatible manner.
155 	 */
156 	pop_buffer_value(trans);
157 	pop_buffer_value(trans);
158 	trans->tgid = pop_buffer_value(trans);
159 
160 	if (vmisc) {
161 		char const * app = find_cookie(trans->app_cookie);
162 		printf("CTX_SWITCH to tid %lu, tgid %lu, cookie %llx(%s)\n",
163 		       (unsigned long)trans->tid, (unsigned long)trans->tgid,
164 		       trans->app_cookie, app ? app : "none");
165 	}
166 }
167 
168 
code_cpu_switch(struct transient * trans)169 static void code_cpu_switch(struct transient * trans)
170 {
171 	clear_trans_current(trans);
172 
173 	if (!enough_remaining(trans, 1)) {
174 		trans->remaining = 0;
175 		return;
176 	}
177 
178 	trans->cpu = pop_buffer_value(trans);
179 	verbprintf(vmisc, "CPU_SWITCH to %lu\n", trans->cpu);
180 }
181 
182 
code_cookie_switch(struct transient * trans)183 static void code_cookie_switch(struct transient * trans)
184 {
185 	clear_trans_current(trans);
186 
187 	if (!enough_remaining(trans, 1)) {
188 		trans->remaining = 0;
189 		return;
190 	}
191 
192 	trans->cookie = pop_buffer_value(trans);
193 
194 	if (vmisc) {
195 		char const * name = verbose_cookie(trans->cookie);
196 		verbprintf(vmisc, "COOKIE_SWITCH to cookie %s(%llx)\n",
197 			   name, trans->cookie);
198 	}
199 }
200 
201 
code_kernel_enter(struct transient * trans)202 static void code_kernel_enter(struct transient * trans)
203 {
204 	verbprintf(vmisc, "KERNEL_ENTER_SWITCH to kernel\n");
205 	trans->in_kernel = 1;
206 	clear_trans_current(trans);
207 	/* subtlety: we must keep trans->cookie cached,
208 	 * even though it's meaningless for the kernel -
209 	 * we won't necessarily get a cookie switch on
210 	 * kernel exit. See comments in opd_sfile.c
211 	 */
212 }
213 
214 
code_user_enter(struct transient * trans)215 static void code_user_enter(struct transient * trans)
216 {
217 	verbprintf(vmisc, "USER_ENTER_SWITCH to user-space\n");
218 	trans->in_kernel = 0;
219 	clear_trans_current(trans);
220 	clear_trans_last(trans);
221 }
222 
223 
code_module_loaded(struct transient * trans)224 static void code_module_loaded(struct transient * trans __attribute__((unused)))
225 {
226 	verbprintf(vmodule, "MODULE_LOADED_CODE\n");
227 	opd_reread_module_info();
228 	clear_trans_current(trans);
229 	clear_trans_last(trans);
230 }
231 
232 
233 /*
234  * This also implicitly signals the end of the previous
235  * trace, so we never explicitly set TRACING_OFF when
236  * processing a buffer.
237  */
code_trace_begin(struct transient * trans)238 static void code_trace_begin(struct transient * trans)
239 {
240 	verbprintf(varcs, "TRACE_BEGIN\n");
241 	trans->tracing = TRACING_START;
242 }
243 
code_xen_enter(struct transient * trans)244 static void code_xen_enter(struct transient * trans)
245 {
246 	verbprintf(vmisc, "XEN_ENTER_SWITCH to xen\n");
247 	trans->in_kernel = 1;
248 	trans->current = NULL;
249 	/* subtlety: we must keep trans->cookie cached, even though it's
250 	 * meaningless for Xen - we won't necessarily get a cookie switch
251 	 * on Xen exit. See comments in opd_sfile.c. It seems that we can
252 	 * get away with in_kernel = 1 as long as we supply the correct
253 	 * Xen image, and its address range in startup find_kernel_image
254 	 * is modified to look in the Xen image also
255 	 */
256 }
257 
258 extern void code_spu_profiling(struct transient * trans);
259 extern void code_spu_ctx_switch(struct transient * trans);
260 
261 extern void code_ibs_fetch_sample(struct transient * trans);
262 extern void code_ibs_op_sample(struct transient * trans);
263 
264 handler_t handlers[LAST_CODE + 1] = {
265 	&code_unknown,
266 	&code_ctx_switch,
267 	&code_cpu_switch,
268 	&code_cookie_switch,
269 	&code_kernel_enter,
270 	&code_user_enter,
271 	&code_module_loaded,
272 	/* tgid handled differently */
273 	&code_unknown,
274 	&code_trace_begin,
275 	&code_unknown,
276 	&code_xen_enter,
277 #if defined(__powerpc__)
278 	&code_spu_profiling,
279 	&code_spu_ctx_switch,
280 #else
281 	&code_unknown,
282 	&code_unknown,
283 #endif
284 	&code_ibs_fetch_sample,
285 	&code_ibs_op_sample,
286 };
287 
288 extern void (*special_processor)(struct transient *);
289 
opd_process_samples(char const * buffer,size_t count)290 void opd_process_samples(char const * buffer, size_t count)
291 {
292 	struct transient trans = {
293 		.buffer = buffer,
294 		.remaining = count,
295 		.tracing = TRACING_OFF,
296 		.current = NULL,
297 		.last = NULL,
298 		.cookie = INVALID_COOKIE,
299 		.app_cookie = INVALID_COOKIE,
300 		.anon = NULL,
301 		.last_anon = NULL,
302 		.pc = 0,
303 		.last_pc = 0,
304 		.event = 0,
305 		.in_kernel = -1,
306 		.cpu = -1,
307 		.tid = -1,
308 		.embedded_offset = UNUSED_EMBEDDED_OFFSET,
309 		.tgid = -1,
310 		.ext = NULL
311 	};
312 
313 	/* FIXME: was uint64_t but it can't compile on alpha where uint64_t
314 	 * is an unsigned long and below the printf("..." %llu\n", code)
315 	 * generate a warning, this look like a stopper to use c98 types :/
316 	 */
317 	unsigned long long code;
318 
319 	if (special_processor) {
320 		special_processor(&trans);
321 		return;
322 	}
323 
324 	while (trans.remaining) {
325 		code = pop_buffer_value(&trans);
326 
327 		if (!is_escape_code(code)) {
328 			opd_put_sample(&trans, code);
329 			continue;
330 		}
331 
332 		if (!trans.remaining) {
333 			verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
334 			opd_stats[OPD_DANGLING_CODE]++;
335 			break;
336 		}
337 
338 		// started with ESCAPE_CODE, next is type
339 		code = pop_buffer_value(&trans);
340 
341 		if (code >= LAST_CODE) {
342 			fprintf(stderr, "Unknown code %llu\n", code);
343 			abort();
344 		}
345 
346 		handlers[code](&trans);
347 	}
348 }
349