Home | History | Annotate | Download | only in daemon
      1 /**
      2  * @file daemon/opd_spu.c
      3  * Processing the sample buffer for Cell BE SPU profile
      4  *
      5  * @remark Copyright 2007 OProfile authors
      6  * @remark Read the file COPYING
      7  *
      8  * @author Maynard Johnson
      9  * (C) Copyright IBM Corporation 2007
     10  */
     11 
     12 #include "opd_interface.h"
     13 #include "opd_printf.h"
     14 #include "opd_sfile.h"
     15 #include "opd_stats.h"
     16 #include "opd_trans.h"
     17 #include "op_libiberty.h"
     18 
     19 #include <stdlib.h>
     20 #include <stdio.h>
     21 
     22 struct spu_context_info {
     23 	pid_t tid;
     24 	pid_t tgid;
     25 	cookie_t app_cookie;
     26 	uint64_t embedded_offset;
     27 	cookie_t spu_cookie;
     28 };
     29 
     30 static struct spu_context_info * spu_context_cache;
     31 
     32 /* Forward declaration */
     33 static void process_spu_samples(struct transient * trans);
     34 
     35 void (*special_processor)(struct transient *);
     36 
     37 /*
     38  * This function is called when the first value found in the
     39  * buffer (after the beginning ESCAPE_CODE) is SPU_PROFILING_CODE.
     40  * Once we get here, the rest of the processing of the buffer is
     41  * Cell-SPU-specific, so we do not need to return until the
     42  * trans.buffer is empty.
     43  */
     44 void code_spu_profiling(struct transient * trans)
     45 {
     46 	/* Next value in buffer is the number of SPUs. */
     47 	unsigned long long num_spus = pop_buffer_value(trans);
     48 	/* Free the cache from previous run */
     49 	free(spu_context_cache);
     50 	spu_context_cache = xmalloc(sizeof(struct spu_context_info) * num_spus);
     51 	special_processor = process_spu_samples;
     52 	process_spu_samples(trans);
     53 }
     54 
     55 void code_spu_ctx_switch(struct transient * trans)
     56 {
     57 	clear_trans_current(trans);
     58 
     59 	if (!enough_remaining(trans, 6)) {
     60 		trans->remaining = 0;
     61 		return;
     62 	}
     63 
     64 	/* First value in the buffer for an SPU context switch is
     65 	 * the SPU number.  For SPU profiling, 'cpu' = 'spu'.
     66 	 */
     67 	trans->cpu = pop_buffer_value(trans);
     68 	trans->tid = pop_buffer_value(trans);
     69 	trans->tgid = pop_buffer_value(trans);
     70 	trans->app_cookie = pop_buffer_value(trans);
     71 
     72 	if (vmisc) {
     73 		char const * app = find_cookie(trans->app_cookie);
     74 		printf("SPU_CTX_SWITCH to tid %lu, tgid %lu, cookie %llx(%s)\n",
     75 		       (unsigned long)trans->tid, (unsigned long)trans->tgid,
     76 		       trans->app_cookie, app ? app : "none");
     77 	}
     78 
     79 	/* The trans->cookie will point to the binary file where the SPU ELF
     80 	 * can be found.  If the SPU ELF is embedded, it may be embedded in
     81 	 * either the executable application binary or a shared lib.  If shared
     82 	 * library, then trans->cookie will differ from the previously obtained
     83 	 * trans->app_cookie.  For the non-embedded case, trans->cookie always
     84 	 * points to a separate binary file.
     85 	 */
     86 	trans->cookie = pop_buffer_value(trans);
     87 	trans->embedded_offset = pop_buffer_value(trans);
     88 }
     89 
     90 
     91 static void cache_spu_context_info(struct transient * trans)
     92 {
     93 	int i = trans->cpu;
     94 	spu_context_cache[i].tid = trans->tid;
     95 	spu_context_cache[i].tgid = trans->tgid;
     96 	spu_context_cache[i].app_cookie = trans->app_cookie;
     97 	spu_context_cache[i].embedded_offset = trans->embedded_offset;
     98 	spu_context_cache[i].spu_cookie = trans->cookie;
     99 }
    100 
    101 static void update_trans_for_spu(struct transient * trans)
    102 {
    103 	int i = trans->cpu;
    104 	trans->tid = spu_context_cache[i].tid;
    105 	trans->tgid = spu_context_cache[i].tgid;
    106 	trans->app_cookie = spu_context_cache[i].app_cookie;
    107 	trans->embedded_offset = spu_context_cache[i].embedded_offset;
    108 	trans->cookie = spu_context_cache[i].spu_cookie;
    109 }
    110 #define SPU_NUM_MASK 0xFFFFFFFF00000000ULL
    111 #define SPU_CYCLES_COUNTER 0
    112 
    113 static void opd_put_spu_sample
    114 (struct transient * trans, unsigned long long pc)
    115 {
    116 	unsigned long spu_number = (pc & SPU_NUM_MASK) >> 32;
    117 	if (trans->cpu != spu_number) {
    118 		trans->cpu = spu_number;
    119 	        clear_trans_current(trans);
    120 		update_trans_for_spu(trans);
    121 	}
    122 	/* get the current sfile if needed */
    123 	if (!trans->current)
    124 		trans->current = sfile_find(trans);
    125 
    126 	if (trans->tracing != TRACING_ON)
    127 		trans->event = SPU_CYCLES_COUNTER;
    128 
    129 	trans->pc = (pc & ~SPU_NUM_MASK);
    130 	/* log the sample or arc */
    131 	sfile_log_sample(trans);
    132 
    133 	/* switch to trace mode */
    134 	if (trans->tracing == TRACING_START)
    135 		trans->tracing = TRACING_ON;
    136 
    137 	update_trans_last(trans);
    138 }
    139 
    140 /*
    141  * This function processes SPU context switches and
    142  * SPU program counter samples.  After processing a
    143  * context switch (via handlers[code)), we cache the
    144  * SPU context information that has been temporarily
    145  * stored in trans.
    146  */
    147 static void process_spu_samples(struct transient * trans)
    148 {
    149 	unsigned long long code;
    150 	trans->in_kernel = 0;
    151 	while (trans->remaining) {
    152 		code = pop_buffer_value(trans);
    153 
    154 		if (!is_escape_code(code)) {
    155 			opd_put_spu_sample(trans, code);
    156 			continue;
    157 		}
    158 
    159 		if (!trans->remaining) {
    160 			verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
    161 			opd_stats[OPD_DANGLING_CODE]++;
    162 			break;
    163 		}
    164 
    165 		/* started with ESCAPE_CODE, next is type */
    166 		code = pop_buffer_value(trans);
    167 
    168 		if (code >= LAST_CODE) {
    169 			fprintf(stderr, "Unknown code %llu\n", code);
    170 			abort();
    171 		}
    172 
    173 		handlers[code](trans);
    174 		cache_spu_context_info(trans);
    175 	}
    176 }
    177