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