• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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