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 */
code_spu_profiling(struct transient * trans)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
code_spu_ctx_switch(struct transient * trans)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
cache_spu_context_info(struct transient * trans)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
update_trans_for_spu(struct transient * trans)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
opd_put_spu_sample(struct transient * trans,unsigned long long pc)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 */
process_spu_samples(struct transient * trans)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