opd_trans.c

Go to the documentation of this file.
00001 
00019 #include "opd_trans.h"
00020 #include "opd_kernel.h"
00021 #include "opd_sfile.h"
00022 #include "opd_anon.h"
00023 #include "opd_stats.h"
00024 #include "opd_printf.h"
00025 #include "opd_interface.h"
00026  
00027 #include <limits.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <stdint.h>
00031 #include <stdio.h>
00032 #include <errno.h>
00033 
00034 extern size_t kernel_pointer_size;
00035 
00036 
00037 void clear_trans_last(struct transient * trans)
00038 {
00039     trans->last = NULL;
00040     trans->last_anon = NULL;
00041 }
00042 
00043 
00044 void clear_trans_current(struct transient * trans)
00045 {
00046     trans->current = NULL;
00047     trans->anon = NULL;
00048 }
00049 
00050 
00051 uint64_t pop_buffer_value(struct transient * trans)
00052 {
00053     uint64_t val;
00054 
00055     if (!trans->remaining) {
00056         fprintf(stderr, "BUG: popping empty buffer !\n");
00057         abort();
00058     }
00059 
00060     if (kernel_pointer_size == 4) {
00061         uint32_t const * lbuf = (void const *)trans->buffer;
00062         val = *lbuf;
00063     } else {
00064         uint64_t const * lbuf = (void const *)trans->buffer;
00065         val = *lbuf;
00066     }
00067 
00068     trans->remaining--;
00069     trans->buffer += kernel_pointer_size;
00070     return val;
00071 }
00072 
00073 
00074 int enough_remaining(struct transient * trans, size_t size)
00075 {
00076     if (trans->remaining >= size)
00077         return 1;
00078 
00079     verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
00080     opd_stats[OPD_DANGLING_CODE]++;
00081     return 0;
00082 }
00083 
00084 
00085 static void opd_put_sample(struct transient * trans, unsigned long long pc)
00086 {
00087     unsigned long long event;
00088 
00089     if (!enough_remaining(trans, 1)) {
00090         trans->remaining = 0;
00091         return;
00092     }
00093 
00094     event = pop_buffer_value(trans);
00095 
00096     if (trans->tracing != TRACING_ON)
00097         trans->event = event;
00098 
00099     trans->pc = pc;
00100 
00101     /* sfile can change at each sample for kernel */
00102     if (trans->in_kernel != 0)
00103         clear_trans_current(trans);
00104 
00105     if (!trans->in_kernel && trans->cookie == NO_COOKIE)
00106         trans->anon = find_anon_mapping(trans);
00107 
00108     /* get the current sfile if needed */
00109     if (!trans->current)
00110         trans->current = sfile_find(trans);
00111 
00112     /*
00113      * can happen if kernel sample falls through the cracks, or if
00114      * it's a sample from an anon region we couldn't find
00115      */
00116     if (!trans->current)
00117         goto out;
00118 
00119     if (trans->tracing != TRACING_ON) {
00120         opd_stats[OPD_SAMPLES]++;
00121         opd_stats[trans->in_kernel == 1 ? OPD_KERNEL : OPD_PROCESS]++;
00122     }
00123 
00124 
00125     /* FIXME: this logic is perhaps too harsh? */
00126     if (trans->current->ignored || (trans->last && trans->last->ignored))
00127         goto out;
00128 
00129     /* log the sample or arc */
00130     sfile_log_sample(trans);
00131 
00132 out:
00133     /* switch to trace mode */
00134     if (trans->tracing == TRACING_START)
00135         trans->tracing = TRACING_ON;
00136 
00137     update_trans_last(trans);
00138 }
00139 
00140 
00141 static void code_unknown(struct transient * trans __attribute__((unused)))
00142 {
00143     fprintf(stderr, "Unknown code !\n");
00144     abort();
00145 }
00146 
00147 
00148 static void code_ctx_switch(struct transient * trans)
00149 {
00150     clear_trans_current(trans);
00151 
00152     if (!enough_remaining(trans, 5)) {
00153         trans->remaining = 0;
00154         return;
00155     }
00156 
00157     trans->tid = pop_buffer_value(trans);
00158     trans->app_cookie = pop_buffer_value(trans);
00159     /* must be ESCAPE_CODE, CTX_TGID_CODE, tgid. Like this
00160      * because tgid was added later in a compatible manner.
00161      */
00162     pop_buffer_value(trans);
00163     pop_buffer_value(trans);
00164     trans->tgid = pop_buffer_value(trans);
00165 
00166     if (vmisc) {
00167         char const * app = find_cookie(trans->app_cookie);
00168         printf("CTX_SWITCH to tid %lu, tgid %lu, cookie %llx(%s)\n",
00169                (unsigned long)trans->tid, (unsigned long)trans->tgid,
00170                trans->app_cookie, app ? app : "none");
00171     }
00172 }
00173 
00174 
00175 static void code_cpu_switch(struct transient * trans)
00176 {
00177     clear_trans_current(trans);
00178 
00179     if (!enough_remaining(trans, 1)) {
00180         trans->remaining = 0;
00181         return;
00182     }
00183 
00184     trans->cpu = pop_buffer_value(trans);
00185     verbprintf(vmisc, "CPU_SWITCH to %lu\n", trans->cpu);
00186 }
00187 
00188 
00189 static void code_cookie_switch(struct transient * trans)
00190 {
00191     clear_trans_current(trans);
00192 
00193     if (!enough_remaining(trans, 1)) {
00194         trans->remaining = 0;
00195         return;
00196     }
00197 
00198     trans->cookie = pop_buffer_value(trans);
00199 
00200     if (vmisc) {
00201         char const * name = verbose_cookie(trans->cookie);
00202         verbprintf(vmisc, "COOKIE_SWITCH to cookie %s(%llx)\n",
00203                name, trans->cookie);
00204     }
00205 }
00206 
00207 
00208 static void code_kernel_enter(struct transient * trans)
00209 {
00210     verbprintf(vmisc, "KERNEL_ENTER_SWITCH to kernel\n");
00211     trans->in_kernel = 1;
00212     clear_trans_current(trans);
00213     /* subtlety: we must keep trans->cookie cached,
00214      * even though it's meaningless for the kernel -
00215      * we won't necessarily get a cookie switch on
00216      * kernel exit. See comments in opd_sfile.c
00217      */
00218 }
00219 
00220 
00221 static void code_user_enter(struct transient * trans)
00222 {
00223     verbprintf(vmisc, "USER_ENTER_SWITCH to user-space\n");
00224     trans->in_kernel = 0;
00225     clear_trans_current(trans);
00226     clear_trans_last(trans);
00227 }
00228 
00229 
00230 static void code_module_loaded(struct transient * trans __attribute__((unused)))
00231 {
00232     verbprintf(vmodule, "MODULE_LOADED_CODE\n");
00233     opd_reread_module_info();
00234     clear_trans_current(trans);
00235     clear_trans_last(trans);
00236 }
00237 
00238 
00239 /*
00240  * This also implicitly signals the end of the previous
00241  * trace, so we never explicitly set TRACING_OFF when
00242  * processing a buffer.
00243  */
00244 static void code_trace_begin(struct transient * trans)
00245 {
00246     verbprintf(varcs, "TRACE_BEGIN\n");
00247     trans->tracing = TRACING_START;
00248 }
00249 
00250 static void code_xen_enter(struct transient * trans)
00251 {
00252     verbprintf(vmisc, "XEN_ENTER_SWITCH to xen\n");
00253     trans->in_kernel = 1;
00254     trans->current = NULL;
00255     /* subtlety: we must keep trans->cookie cached, even though it's
00256      * meaningless for Xen - we won't necessarily get a cookie switch
00257      * on Xen exit. See comments in opd_sfile.c. It seems that we can
00258      * get away with in_kernel = 1 as long as we supply the correct
00259      * Xen image, and its address range in startup find_kernel_image
00260      * is modified to look in the Xen image also
00261      */
00262 }
00263 
00264 extern void code_spu_profiling(struct transient * trans);
00265 extern void code_spu_ctx_switch(struct transient * trans);
00266 
00267 extern void code_ibs_fetch_sample(struct transient * trans);
00268 extern void code_ibs_op_sample(struct transient * trans);
00269 
00270 handler_t handlers[LAST_CODE + 1] = {
00271     &code_unknown,
00272     &code_ctx_switch,
00273     &code_cpu_switch,
00274     &code_cookie_switch,
00275     &code_kernel_enter,
00276     &code_user_enter,
00277     &code_module_loaded,
00278     /* tgid handled differently */
00279     &code_unknown,
00280     &code_trace_begin,
00281     &code_unknown,
00282     &code_xen_enter,
00283 #if defined(__powerpc__)
00284     &code_spu_profiling,
00285     &code_spu_ctx_switch,
00286 #else
00287     &code_unknown,
00288     &code_unknown,
00289 #endif
00290     &code_ibs_fetch_sample,
00291     &code_ibs_op_sample,
00292 };
00293 
00294 extern void (*special_processor)(struct transient *);
00295 
00296 void opd_process_samples(char const * buffer, size_t count)
00297 {
00298     struct transient trans = {
00299         .buffer = buffer,
00300         .remaining = count,
00301         .tracing = TRACING_OFF,
00302         .current = NULL,
00303         .last = NULL,
00304         .cookie = INVALID_COOKIE,
00305         .app_cookie = INVALID_COOKIE,
00306         .anon = NULL,
00307         .last_anon = NULL,
00308         .pc = 0,
00309         .last_pc = 0,
00310         .event = 0,
00311         .in_kernel = -1,
00312         .cpu = -1,
00313         .tid = -1,
00314         .embedded_offset = UNUSED_EMBEDDED_OFFSET,
00315         .tgid = -1,
00316         .ext = NULL
00317     };
00318 
00319     /* FIXME: was uint64_t but it can't compile on alpha where uint64_t
00320      * is an unsigned long and below the printf("..." %llu\n", code)
00321      * generate a warning, this look like a stopper to use c98 types :/
00322      */
00323     unsigned long long code;
00324 
00325     if (special_processor) {
00326         special_processor(&trans);
00327         return;
00328     }
00329 
00330     while (trans.remaining) {
00331         code = pop_buffer_value(&trans);
00332 
00333         if (!is_escape_code(code)) {
00334             opd_put_sample(&trans, code);
00335             continue;
00336         }
00337 
00338         if (!trans.remaining) {
00339             verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
00340             opd_stats[OPD_DANGLING_CODE]++;
00341             break;
00342         }
00343 
00344         // started with ESCAPE_CODE, next is type
00345         code = pop_buffer_value(&trans);
00346     
00347         if (code >= LAST_CODE) {
00348             fprintf(stderr, "Unknown code %llu\n", code);
00349             abort();
00350         }
00351 
00352         handlers[code](&trans);
00353     }
00354 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1