Home | History | Annotate | Download | only in daemon
      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 (at) 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 
     37 void clear_trans_last(struct transient * trans)
     38 {
     39 	trans->last = NULL;
     40 	trans->last_anon = NULL;
     41 }
     42 
     43 
     44 void clear_trans_current(struct transient * trans)
     45 {
     46 	trans->current = NULL;
     47 	trans->anon = NULL;
     48 }
     49 
     50 
     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 
     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 
     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 
    135 static void code_unknown(struct transient * trans __attribute__((unused)))
    136 {
    137 	fprintf(stderr, "Unknown code !\n");
    138 	abort();
    139 }
    140 
    141 
    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 
    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 
    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 
    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 
    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 
    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  */
    238 static void code_trace_begin(struct transient * trans)
    239 {
    240 	verbprintf(varcs, "TRACE_BEGIN\n");
    241 	trans->tracing = TRACING_START;
    242 }
    243 
    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 
    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