blob: 76296a0d6925c34eba10775f399822c47134c17c [file] [log] [blame]
The Android Open Source Project10e23ee2009-03-03 19:30:30 -08001/**
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
34extern size_t kernel_pointer_size;
35
36
37void clear_trans_last(struct transient * trans)
38{
39 trans->last = NULL;
40 trans->last_anon = NULL;
41}
42
43
44void clear_trans_current(struct transient * trans)
45{
46 trans->current = NULL;
47 trans->anon = NULL;
48}
49
50
51uint64_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
74int 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
85static 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
126out:
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
135static void code_unknown(struct transient * trans __attribute__((unused)))
136{
137 fprintf(stderr, "Unknown code !\n");
138 abort();
139}
140
141
142static 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
169static 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
183static 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",
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700197 name, trans->cookie);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800198 }
199}
200
201
202static 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
215static 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
224static 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 */
238static void code_trace_begin(struct transient * trans)
239{
240 verbprintf(varcs, "TRACE_BEGIN\n");
241 trans->tracing = TRACING_START;
242}
243
244static 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;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700249 /* 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
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800254 * is modified to look in the Xen image also
255 */
256}
257
258extern void code_spu_profiling(struct transient * trans);
259extern void code_spu_ctx_switch(struct transient * trans);
260
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700261extern void code_ibs_fetch_sample(struct transient * trans);
262extern void code_ibs_op_sample(struct transient * trans);
263
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800264handler_t handlers[LAST_CODE + 1] = {
265 &code_unknown,
266 &code_ctx_switch,
267 &code_cpu_switch,
268 &code_cookie_switch,
269 &code_kernel_enter,
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700270 &code_user_enter,
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800271 &code_module_loaded,
272 /* tgid handled differently */
273 &code_unknown,
274 &code_trace_begin,
275 &code_unknown,
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700276 &code_xen_enter,
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800277#if defined(__powerpc__)
278 &code_spu_profiling,
279 &code_spu_ctx_switch,
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700280#else
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800281 &code_unknown,
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700282 &code_unknown,
283#endif
284 &code_ibs_fetch_sample,
285 &code_ibs_op_sample,
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800286};
287
288extern void (*special_processor)(struct transient *);
289
290void 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,
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700309 .tgid = -1,
310 .ext = NULL
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800311 };
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
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800324 while (trans.remaining) {
325 code = pop_buffer_value(&trans);
326
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800327 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
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800341 if (code >= LAST_CODE) {
342 fprintf(stderr, "Unknown code %llu\n", code);
343 abort();
344 }
345
346 handlers[code](&trans);
347 }
348}