opd_spu.c

Go to the documentation of this file.
00001 
00012 #include "opd_interface.h"
00013 #include "opd_printf.h"
00014 #include "opd_sfile.h"
00015 #include "opd_stats.h"
00016 #include "opd_trans.h"
00017 #include "op_libiberty.h"
00018 
00019 #include <stdlib.h>
00020 #include <stdio.h>
00021 
00022 struct spu_context_info {
00023     pid_t tid;
00024     pid_t tgid;
00025     cookie_t app_cookie;
00026     uint64_t embedded_offset;
00027     cookie_t spu_cookie;
00028 };
00029 
00030 static struct spu_context_info * spu_context_cache;
00031 
00032 /* Forward declaration */
00033 static void process_spu_samples(struct transient * trans);
00034 
00035 void (*special_processor)(struct transient *);
00036 
00037 /*
00038  * This function is called when the first value found in the
00039  * buffer (after the beginning ESCAPE_CODE) is SPU_PROFILING_CODE.
00040  * Once we get here, the rest of the processing of the buffer is
00041  * Cell-SPU-specific, so we do not need to return until the
00042  * trans.buffer is empty.
00043  */
00044 void code_spu_profiling(struct transient * trans)
00045 {
00046     /* Next value in buffer is the number of SPUs. */
00047     unsigned long long num_spus = pop_buffer_value(trans);
00048     /* Free the cache from previous run */
00049     free(spu_context_cache);
00050     spu_context_cache = xmalloc(sizeof(struct spu_context_info) * num_spus);
00051     special_processor = process_spu_samples;
00052     process_spu_samples(trans);
00053 }
00054 
00055 void code_spu_ctx_switch(struct transient * trans)
00056 {
00057     clear_trans_current(trans);
00058 
00059     if (!enough_remaining(trans, 6)) {
00060         trans->remaining = 0;
00061         return;
00062     }
00063 
00064     /* First value in the buffer for an SPU context switch is
00065      * the SPU number.  For SPU profiling, 'cpu' = 'spu'.
00066      */
00067     trans->cpu = pop_buffer_value(trans);
00068     trans->tid = pop_buffer_value(trans);
00069     trans->tgid = pop_buffer_value(trans);
00070     trans->app_cookie = pop_buffer_value(trans);
00071 
00072     if (vmisc) {
00073         char const * app = find_cookie(trans->app_cookie);
00074         printf("SPU_CTX_SWITCH to tid %lu, tgid %lu, cookie %llx(%s)\n",
00075                (unsigned long)trans->tid, (unsigned long)trans->tgid,
00076                trans->app_cookie, app ? app : "none");
00077     }
00078 
00079     /* The trans->cookie will point to the binary file where the SPU ELF
00080      * can be found.  If the SPU ELF is embedded, it may be embedded in
00081      * either the executable application binary or a shared lib.  If shared
00082      * library, then trans->cookie will differ from the previously obtained
00083      * trans->app_cookie.  For the non-embedded case, trans->cookie always
00084      * points to a separate binary file.
00085      */
00086     trans->cookie = pop_buffer_value(trans);
00087     trans->embedded_offset = pop_buffer_value(trans);
00088 }
00089 
00090 
00091 static void cache_spu_context_info(struct transient * trans)
00092 {
00093     int i = trans->cpu;
00094     spu_context_cache[i].tid = trans->tid;
00095     spu_context_cache[i].tgid = trans->tgid;
00096     spu_context_cache[i].app_cookie = trans->app_cookie;
00097     spu_context_cache[i].embedded_offset = trans->embedded_offset;
00098     spu_context_cache[i].spu_cookie = trans->cookie;
00099 }
00100 
00101 static void update_trans_for_spu(struct transient * trans)
00102 {
00103     int i = trans->cpu;
00104     trans->tid = spu_context_cache[i].tid;
00105     trans->tgid = spu_context_cache[i].tgid;
00106     trans->app_cookie = spu_context_cache[i].app_cookie;
00107     trans->embedded_offset = spu_context_cache[i].embedded_offset;
00108     trans->cookie = spu_context_cache[i].spu_cookie;
00109 }
00110 #define SPU_NUM_MASK 0xFFFFFFFF00000000ULL
00111 #define SPU_CYCLES_COUNTER 0
00112 
00113 static void opd_put_spu_sample
00114 (struct transient * trans, unsigned long long pc)
00115 {
00116     unsigned long spu_number = (pc & SPU_NUM_MASK) >> 32;
00117     if (trans->cpu != spu_number) {
00118         trans->cpu = spu_number;
00119             clear_trans_current(trans);
00120         update_trans_for_spu(trans);
00121     }
00122     /* get the current sfile if needed */
00123     if (!trans->current)
00124         trans->current = sfile_find(trans);
00125 
00126     if (trans->tracing != TRACING_ON)
00127         trans->event = SPU_CYCLES_COUNTER;
00128 
00129     trans->pc = (pc & ~SPU_NUM_MASK);
00130     /* log the sample or arc */
00131     sfile_log_sample(trans);
00132 
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  * This function processes SPU context switches and
00142  * SPU program counter samples.  After processing a
00143  * context switch (via handlers[code)), we cache the
00144  * SPU context information that has been temporarily
00145  * stored in trans.
00146  */
00147 static void process_spu_samples(struct transient * trans)
00148 {
00149     unsigned long long code;
00150     trans->in_kernel = 0;
00151     while (trans->remaining) {
00152         code = pop_buffer_value(trans);
00153 
00154         if (!is_escape_code(code)) {
00155             opd_put_spu_sample(trans, code);
00156             continue;
00157         }
00158 
00159         if (!trans->remaining) {
00160             verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
00161             opd_stats[OPD_DANGLING_CODE]++;
00162             break;
00163         }
00164 
00165         /* started with ESCAPE_CODE, next is type */
00166         code = pop_buffer_value(trans);
00167 
00168         if (code >= LAST_CODE) {
00169             fprintf(stderr, "Unknown code %llu\n", code);
00170             abort();
00171         }
00172 
00173         handlers[code](trans);
00174         cache_spu_context_info(trans);
00175     }
00176 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1