Mercurial > vba-clojure
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 Forgotten3 // Copyright (C) 2004 Forgotten and the VBA development team5 // This program is free software; you can redistribute it and/or modify6 // it under the terms of the GNU General Public License as published by7 // 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 of12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13 // GNU General Public License for more details.14 //15 // You should have received a copy of the GNU General Public License16 // 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.c20 /*-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 without25 * modification, are permitted provided that the following conditions26 * are met:27 * 1. Redistributions of source code must retain the above copyright28 * notice, this list of conditions and the following disclaimer.29 * 2. Redistributions in binary form must reproduce the above copyright30 * notice, this list of conditions and the following disclaimer in the31 * 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 contributors34 * may be used to endorse or promote products derived from this software35 * without specific prior written permission.36 *37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF47 * 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 tos64 */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 0x10000L85 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 if125 all the data structures are ready. */127 void profControl(int mode)128 {129 if (mode) {130 /* start */131 #ifdef PROFILING132 cpuProfil(sbuf, ssiz, (u32)s_lowpc, s_scale);133 #endif134 profiling = 0;135 } else {136 /* stop */137 #ifdef PROFILING138 cpuProfil(NULL, 0, 0, 0);139 #endif140 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 using155 * 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 else202 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 profiling303 * 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 arc324 */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 chain354 * had top->selfpc == selfpc.355 * so we allocate a new tostruct356 * 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 count378 * 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 }