view src/prof/prof.cpp @ 113:0831da75d2c5

completed frame-counting machine language program with dylan's help
author Robert McIntyre <rlm@mit.edu>
date Fri, 16 Mar 2012 00:43:28 -0500
parents f9f4f1b99eed
children
line wrap: on
line source
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
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.
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 */
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <memory.h>
54 #include "gmon.h"
55 #include "gmon_out.h"
57 #include "../common/System.h"
58 #include "../gba/GBA.h"
59 #include "../gba/GBAGlobals.h"
60 #include "../NLS.h"
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;
73 static int ssiz;
74 static char *sbuf;
75 static int s_scale;
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';
82 /* see profil(2) where this is describe (incorrectly) */
83 #define SCALE_1_TO_1 0x10000L
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 }
93 void profPut16(char *b, u16 v)
94 {
95 b[0] = v & 255;
96 b[1] = (v >> 8) & 255;
97 }
99 int profWrite8(FILE *f, u8 b)
100 {
101 if(fwrite(&b, 1, 1, f) != 1)
102 return 1;
103 return 0;
104 }
106 int profWrite32(FILE *f, u32 v)
107 {
108 char buf[4];
110 profPut32(buf, v);
111 if(fwrite(buf, 1, 4, f) != 4)
112 return 1;
113 return 0;
114 }
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 }
123 /* Control profiling;
124 profiling is what mcount checks to see if
125 all the data structures are ready. */
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 }
145 #define MSG N_("No space for profiling buffer(s)\n")
147 void profStartup(u32 lowpc, u32 highpc)
148 {
149 int monsize;
150 char *buffer;
151 int o;
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);
185 free(buffer);
186 buffer = NULL;
188 free(froms);
189 froms = NULL;
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 }
206 void profCleanup()
207 {
208 FILE *fd;
209 int fromindex;
210 int endfrom;
211 u32 frompc;
212 int toindex;
213 struct gmon_hdr ghdr;
215 profControl(0);
216 fd = fopen( "gmon.out" , "wb" );
217 if ( fd == NULL ) {
218 systemMessage( 0, "mcount: gmon.out" );
219 return;
220 }
222 memcpy(&ghdr.cookie[0], GMON_MAGIC, 4);
223 profPut32((char *)ghdr.version, GMON_VERSION);
225 if(fwrite(&ghdr, sizeof(ghdr), 1, fd) != 1) {
226 systemMessage(0, "mcount: gmon.out header");
227 fclose(fd);
228 return;
229 }
231 if(hz == 0)
232 hz = 100;
234 hist_num_bins = ssiz;
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;
249 u16 count;
250 int i;
252 for(i = 0; i < hist_num_bins; ++i) {
253 profPut16((char *)&count, hist_sample[i]);
255 if(fwrite(&count, sizeof(count), 1, fd) != 1) {
256 systemMessage(0, "mcount: gmon.out sample");
257 fclose(fd);
258 return;
259 }
260 }
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 }
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;
290 /*
291 * find the return address for mcount,
292 * and the return address for mcount's caller.
293 */
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 }
388 }
389 done:
390 profiling--;
391 /* and fall through */
392 out:
393 return; /* normal return restores saved registers */
395 overflow:
396 profiling++; /* halt further profiling */
397 #define TOLIMIT "mcount: tos overflow\n"
398 systemMessage(0, TOLIMIT);
399 goto out;
400 }
402 void profSetHertz(int h)
403 {
404 hz = h;
405 }