Mercurial > vba-linux
comparison src/prof/prof.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. | |
2 // Copyright (C) 1999-2003 Forgotten | |
3 // Copyright (C) 2004 Forgotten and the VBA development team | |
4 | |
5 // This program is free software; you can redistribute it and/or modify | |
6 // it under the terms of the GNU General Public License as published by | |
7 // the Free Software Foundation; either version 2, or(at your option) | |
8 // any later version. | |
9 // | |
10 // This program is distributed in the hope that it will be useful, | |
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 // GNU General Public License for more details. | |
14 // | |
15 // You should have received a copy of the GNU General Public License | |
16 // along with this program; if not, write to the Free Software Foundation, | |
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 | |
19 // adapted from gmon.c | |
20 /*- | |
21 * Copyright (c) 1991, 1998 The Regents of the University of California. | |
22 * All rights reserved. | |
23 * | |
24 * Redistribution and use in source and binary forms, with or without | |
25 * modification, are permitted provided that the following conditions | |
26 * are met: | |
27 * 1. Redistributions of source code must retain the above copyright | |
28 * notice, this list of conditions and the following disclaimer. | |
29 * 2. Redistributions in binary form must reproduce the above copyright | |
30 * notice, this list of conditions and the following disclaimer in the | |
31 * documentation and/or other materials provided with the distribution. | |
32 * 3. [rescinded 22 July 1999] | |
33 * 4. Neither the name of the University nor the names of its contributors | |
34 * may be used to endorse or promote products derived from this software | |
35 * without specific prior written permission. | |
36 * | |
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
47 * SUCH DAMAGE. | |
48 */ | |
49 | |
50 #include <stdlib.h> | |
51 #include <stdio.h> | |
52 #include <memory.h> | |
53 | |
54 #include "gmon.h" | |
55 #include "gmon_out.h" | |
56 | |
57 #include "../common/System.h" | |
58 #include "../gba/GBA.h" | |
59 #include "../gba/GBAGlobals.h" | |
60 #include "../NLS.h" | |
61 | |
62 /* | |
63 * froms is actually a bunch of unsigned shorts indexing tos | |
64 */ | |
65 static int profiling = 3; | |
66 static unsigned short *froms; | |
67 static struct tostruct *tos = 0; | |
68 static long tolimit = 0; | |
69 static u32 s_lowpc = 0; | |
70 static u32 s_highpc = 0; | |
71 static unsigned long s_textsize = 0; | |
72 | |
73 static int ssiz; | |
74 static char *sbuf; | |
75 static int s_scale; | |
76 | |
77 static int hz = 0; | |
78 static int hist_num_bins = 0; | |
79 static char hist_dimension[16] = "seconds"; | |
80 static char hist_dimension_abbrev = 's'; | |
81 | |
82 /* see profil(2) where this is describe (incorrectly) */ | |
83 #define SCALE_1_TO_1 0x10000L | |
84 | |
85 void profPut32(char *b, u32 v) | |
86 { | |
87 b[0] = v & 255; | |
88 b[1] = (v >> 8) & 255; | |
89 b[2] = (v >> 16) & 255; | |
90 b[3] = (v >> 24) & 255; | |
91 } | |
92 | |
93 void profPut16(char *b, u16 v) | |
94 { | |
95 b[0] = v & 255; | |
96 b[1] = (v >> 8) & 255; | |
97 } | |
98 | |
99 int profWrite8(FILE *f, u8 b) | |
100 { | |
101 if(fwrite(&b, 1, 1, f) != 1) | |
102 return 1; | |
103 return 0; | |
104 } | |
105 | |
106 int profWrite32(FILE *f, u32 v) | |
107 { | |
108 char buf[4]; | |
109 | |
110 profPut32(buf, v); | |
111 if(fwrite(buf, 1, 4, f) != 4) | |
112 return 1; | |
113 return 0; | |
114 } | |
115 | |
116 int profWrite(FILE *f, char *buf, unsigned int n) | |
117 { | |
118 if(fwrite(buf, 1, n, f) != n) | |
119 return 1; | |
120 return 0; | |
121 } | |
122 | |
123 /* Control profiling; | |
124 profiling is what mcount checks to see if | |
125 all the data structures are ready. */ | |
126 | |
127 void profControl(int mode) | |
128 { | |
129 if (mode) { | |
130 /* start */ | |
131 #ifdef PROFILING | |
132 cpuProfil(sbuf, ssiz, (u32)s_lowpc, s_scale); | |
133 #endif | |
134 profiling = 0; | |
135 } else { | |
136 /* stop */ | |
137 #ifdef PROFILING | |
138 cpuProfil(NULL, 0, 0, 0); | |
139 #endif | |
140 profiling = 3; | |
141 } | |
142 } | |
143 | |
144 | |
145 #define MSG N_("No space for profiling buffer(s)\n") | |
146 | |
147 void profStartup(u32 lowpc, u32 highpc) | |
148 { | |
149 int monsize; | |
150 char *buffer; | |
151 int o; | |
152 | |
153 /* | |
154 * round lowpc and highpc to multiples of the density we're using | |
155 * so the rest of the scaling (here and in gprof) stays in ints. | |
156 */ | |
157 lowpc = ROUNDDOWN(lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); | |
158 s_lowpc = lowpc; | |
159 highpc = ROUNDUP(highpc, HISTFRACTION*sizeof(HISTCOUNTER)); | |
160 s_highpc = highpc; | |
161 s_textsize = highpc - lowpc; | |
162 monsize = (s_textsize / HISTFRACTION); | |
163 buffer = (char *)calloc(1, 2*monsize ); | |
164 if ( buffer == NULL ) { | |
165 systemMessage(0, MSG); | |
166 return; | |
167 } | |
168 froms = (unsigned short *) calloc(1, 4*s_textsize / HASHFRACTION ); | |
169 if ( froms == NULL ) { | |
170 systemMessage(0, MSG); | |
171 free(buffer); | |
172 buffer = NULL; | |
173 return; | |
174 } | |
175 tolimit = s_textsize * ARCDENSITY / 100; | |
176 if ( tolimit < MINARCS ) { | |
177 tolimit = MINARCS; | |
178 } else if ( tolimit > 65534 ) { | |
179 tolimit = 65534; | |
180 } | |
181 tos = (struct tostruct *) calloc(1, tolimit * sizeof( struct tostruct ) ); | |
182 if ( tos == NULL ) { | |
183 systemMessage(0, MSG); | |
184 | |
185 free(buffer); | |
186 buffer = NULL; | |
187 | |
188 free(froms); | |
189 froms = NULL; | |
190 | |
191 return; | |
192 } | |
193 tos[0].link = 0; | |
194 sbuf = buffer; | |
195 ssiz = monsize; | |
196 if ( monsize <= 0 ) | |
197 return; | |
198 o = highpc - lowpc; | |
199 if( monsize < o ) | |
200 s_scale = (int)(( (float) monsize / o ) * SCALE_1_TO_1); | |
201 else | |
202 s_scale = SCALE_1_TO_1; | |
203 profControl(1); | |
204 } | |
205 | |
206 void profCleanup() | |
207 { | |
208 FILE *fd; | |
209 int fromindex; | |
210 int endfrom; | |
211 u32 frompc; | |
212 int toindex; | |
213 struct gmon_hdr ghdr; | |
214 | |
215 profControl(0); | |
216 fd = fopen( "gmon.out" , "wb" ); | |
217 if ( fd == NULL ) { | |
218 systemMessage( 0, "mcount: gmon.out" ); | |
219 return; | |
220 } | |
221 | |
222 memcpy(&ghdr.cookie[0], GMON_MAGIC, 4); | |
223 profPut32((char *)ghdr.version, GMON_VERSION); | |
224 | |
225 if(fwrite(&ghdr, sizeof(ghdr), 1, fd) != 1) { | |
226 systemMessage(0, "mcount: gmon.out header"); | |
227 fclose(fd); | |
228 return; | |
229 } | |
230 | |
231 if(hz == 0) | |
232 hz = 100; | |
233 | |
234 hist_num_bins = ssiz; | |
235 | |
236 if(profWrite8(fd, GMON_TAG_TIME_HIST) || | |
237 profWrite32(fd, (u32)s_lowpc) || | |
238 profWrite32(fd, (u32)s_highpc) || | |
239 profWrite32(fd, hist_num_bins) || | |
240 profWrite32(fd, hz) || | |
241 profWrite(fd, hist_dimension, 15) || | |
242 profWrite(fd, &hist_dimension_abbrev, 1)) { | |
243 systemMessage(0, "mcount: gmon.out hist"); | |
244 fclose(fd); | |
245 return; | |
246 } | |
247 u16 *hist_sample = (u16 *)sbuf; | |
248 | |
249 u16 count; | |
250 int i; | |
251 | |
252 for(i = 0; i < hist_num_bins; ++i) { | |
253 profPut16((char *)&count, hist_sample[i]); | |
254 | |
255 if(fwrite(&count, sizeof(count), 1, fd) != 1) { | |
256 systemMessage(0, "mcount: gmon.out sample"); | |
257 fclose(fd); | |
258 return; | |
259 } | |
260 } | |
261 | |
262 endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); | |
263 for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { | |
264 if ( froms[fromindex] == 0 ) { | |
265 continue; | |
266 } | |
267 frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); | |
268 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { | |
269 if(profWrite8(fd, GMON_TAG_CG_ARC) || | |
270 profWrite32(fd, (u32)frompc) || | |
271 profWrite32(fd, (u32)tos[toindex].selfpc) || | |
272 profWrite32(fd, tos[toindex].count)) { | |
273 systemMessage(0, "mcount: arc"); | |
274 fclose(fd); | |
275 return; | |
276 } | |
277 } | |
278 } | |
279 fclose(fd); | |
280 } | |
281 | |
282 void profCount() | |
283 { | |
284 register u32 selfpc; | |
285 register unsigned short *frompcindex; | |
286 register struct tostruct *top; | |
287 register struct tostruct *prevtop; | |
288 register long toindex; | |
289 | |
290 /* | |
291 * find the return address for mcount, | |
292 * and the return address for mcount's caller. | |
293 */ | |
294 | |
295 /* selfpc = pc pushed by mcount call. | |
296 This identifies the function that was just entered. */ | |
297 selfpc = (u32) reg[14].I; | |
298 /* frompcindex = pc in preceding frame. | |
299 This identifies the caller of the function just entered. */ | |
300 frompcindex = (unsigned short *) reg[12].I; | |
301 /* | |
302 * check that we are profiling | |
303 * and that we aren't recursively invoked. | |
304 */ | |
305 if (profiling) { | |
306 goto out; | |
307 } | |
308 profiling++; | |
309 /* | |
310 * check that frompcindex is a reasonable pc value. | |
311 * for example: signal catchers get called from the stack, | |
312 * not from text space. too bad. | |
313 */ | |
314 frompcindex = (unsigned short *) ((long) frompcindex - (long) s_lowpc); | |
315 if ((unsigned long) frompcindex > s_textsize) { | |
316 goto done; | |
317 } | |
318 frompcindex = | |
319 &froms[((long) frompcindex) / (HASHFRACTION * sizeof(*froms))]; | |
320 toindex = *frompcindex; | |
321 if (toindex == 0) { | |
322 /* | |
323 * first time traversing this arc | |
324 */ | |
325 toindex = ++tos[0].link; | |
326 if (toindex >= tolimit) { | |
327 goto overflow; | |
328 } | |
329 *frompcindex = (unsigned short)toindex; | |
330 top = &tos[toindex]; | |
331 top->selfpc = selfpc; | |
332 top->count = 1; | |
333 top->link = 0; | |
334 goto done; | |
335 } | |
336 top = &tos[toindex]; | |
337 if (top->selfpc == selfpc) { | |
338 /* | |
339 * arc at front of chain; usual case. | |
340 */ | |
341 top->count++; | |
342 goto done; | |
343 } | |
344 /* | |
345 * have to go looking down chain for it. | |
346 * top points to what we are looking at, | |
347 * prevtop points to previous top. | |
348 * we know it is not at the head of the chain. | |
349 */ | |
350 for (; /* goto done */; ) { | |
351 if (top->link == 0) { | |
352 /* | |
353 * top is end of the chain and none of the chain | |
354 * had top->selfpc == selfpc. | |
355 * so we allocate a new tostruct | |
356 * and link it to the head of the chain. | |
357 */ | |
358 toindex = ++tos[0].link; | |
359 if (toindex >= tolimit) { | |
360 goto overflow; | |
361 } | |
362 top = &tos[toindex]; | |
363 top->selfpc = selfpc; | |
364 top->count = 1; | |
365 top->link = *frompcindex; | |
366 *frompcindex = (unsigned short)toindex; | |
367 goto done; | |
368 } | |
369 /* | |
370 * otherwise, check the next arc on the chain. | |
371 */ | |
372 prevtop = top; | |
373 top = &tos[top->link]; | |
374 if (top->selfpc == selfpc) { | |
375 /* | |
376 * there it is. | |
377 * increment its count | |
378 * move it to the head of the chain. | |
379 */ | |
380 top->count++; | |
381 toindex = prevtop->link; | |
382 prevtop->link = top->link; | |
383 top->link = *frompcindex; | |
384 *frompcindex = (unsigned short)toindex; | |
385 goto done; | |
386 } | |
387 | |
388 } | |
389 done: | |
390 profiling--; | |
391 /* and fall through */ | |
392 out: | |
393 return; /* normal return restores saved registers */ | |
394 | |
395 overflow: | |
396 profiling++; /* halt further profiling */ | |
397 #define TOLIMIT "mcount: tos overflow\n" | |
398 systemMessage(0, TOLIMIT); | |
399 goto out; | |
400 } | |
401 | |
402 void profSetHertz(int h) | |
403 { | |
404 hz = h; | |
405 } |