Mercurial > vba-linux
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/prof/prof.cpp Sat Mar 03 10:31:27 2012 -0600 1.3 @@ -0,0 +1,405 @@ 1.4 +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. 1.5 +// Copyright (C) 1999-2003 Forgotten 1.6 +// Copyright (C) 2004 Forgotten and the VBA development team 1.7 + 1.8 +// This program is free software; you can redistribute it and/or modify 1.9 +// it under the terms of the GNU General Public License as published by 1.10 +// the Free Software Foundation; either version 2, or(at your option) 1.11 +// any later version. 1.12 +// 1.13 +// This program is distributed in the hope that it will be useful, 1.14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +// GNU General Public License for more details. 1.17 +// 1.18 +// You should have received a copy of the GNU General Public License 1.19 +// along with this program; if not, write to the Free Software Foundation, 1.20 +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1.21 + 1.22 +// adapted from gmon.c 1.23 +/*- 1.24 + * Copyright (c) 1991, 1998 The Regents of the University of California. 1.25 + * All rights reserved. 1.26 + * 1.27 + * Redistribution and use in source and binary forms, with or without 1.28 + * modification, are permitted provided that the following conditions 1.29 + * are met: 1.30 + * 1. Redistributions of source code must retain the above copyright 1.31 + * notice, this list of conditions and the following disclaimer. 1.32 + * 2. Redistributions in binary form must reproduce the above copyright 1.33 + * notice, this list of conditions and the following disclaimer in the 1.34 + * documentation and/or other materials provided with the distribution. 1.35 + * 3. [rescinded 22 July 1999] 1.36 + * 4. Neither the name of the University nor the names of its contributors 1.37 + * may be used to endorse or promote products derived from this software 1.38 + * without specific prior written permission. 1.39 + * 1.40 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1.41 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.42 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.43 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1.44 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1.45 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1.46 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1.47 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1.48 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1.49 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1.50 + * SUCH DAMAGE. 1.51 + */ 1.52 + 1.53 +#include <stdlib.h> 1.54 +#include <stdio.h> 1.55 +#include <memory.h> 1.56 + 1.57 +#include "gmon.h" 1.58 +#include "gmon_out.h" 1.59 + 1.60 +#include "../common/System.h" 1.61 +#include "../gba/GBA.h" 1.62 +#include "../gba/GBAGlobals.h" 1.63 +#include "../NLS.h" 1.64 + 1.65 +/* 1.66 + * froms is actually a bunch of unsigned shorts indexing tos 1.67 + */ 1.68 +static int profiling = 3; 1.69 +static unsigned short *froms; 1.70 +static struct tostruct *tos = 0; 1.71 +static long tolimit = 0; 1.72 +static u32 s_lowpc = 0; 1.73 +static u32 s_highpc = 0; 1.74 +static unsigned long s_textsize = 0; 1.75 + 1.76 +static int ssiz; 1.77 +static char *sbuf; 1.78 +static int s_scale; 1.79 + 1.80 +static int hz = 0; 1.81 +static int hist_num_bins = 0; 1.82 +static char hist_dimension[16] = "seconds"; 1.83 +static char hist_dimension_abbrev = 's'; 1.84 + 1.85 +/* see profil(2) where this is describe (incorrectly) */ 1.86 +#define SCALE_1_TO_1 0x10000L 1.87 + 1.88 +void profPut32(char *b, u32 v) 1.89 +{ 1.90 + b[0] = v & 255; 1.91 + b[1] = (v >> 8) & 255; 1.92 + b[2] = (v >> 16) & 255; 1.93 + b[3] = (v >> 24) & 255; 1.94 +} 1.95 + 1.96 +void profPut16(char *b, u16 v) 1.97 +{ 1.98 + b[0] = v & 255; 1.99 + b[1] = (v >> 8) & 255; 1.100 +} 1.101 + 1.102 +int profWrite8(FILE *f, u8 b) 1.103 +{ 1.104 + if(fwrite(&b, 1, 1, f) != 1) 1.105 + return 1; 1.106 + return 0; 1.107 +} 1.108 + 1.109 +int profWrite32(FILE *f, u32 v) 1.110 +{ 1.111 + char buf[4]; 1.112 + 1.113 + profPut32(buf, v); 1.114 + if(fwrite(buf, 1, 4, f) != 4) 1.115 + return 1; 1.116 + return 0; 1.117 +} 1.118 + 1.119 +int profWrite(FILE *f, char *buf, unsigned int n) 1.120 +{ 1.121 + if(fwrite(buf, 1, n, f) != n) 1.122 + return 1; 1.123 + return 0; 1.124 +} 1.125 + 1.126 +/* Control profiling; 1.127 + profiling is what mcount checks to see if 1.128 + all the data structures are ready. */ 1.129 + 1.130 +void profControl(int mode) 1.131 +{ 1.132 + if (mode) { 1.133 + /* start */ 1.134 +#ifdef PROFILING 1.135 + cpuProfil(sbuf, ssiz, (u32)s_lowpc, s_scale); 1.136 +#endif 1.137 + profiling = 0; 1.138 + } else { 1.139 + /* stop */ 1.140 +#ifdef PROFILING 1.141 + cpuProfil(NULL, 0, 0, 0); 1.142 +#endif 1.143 + profiling = 3; 1.144 + } 1.145 +} 1.146 + 1.147 + 1.148 +#define MSG N_("No space for profiling buffer(s)\n") 1.149 + 1.150 +void profStartup(u32 lowpc, u32 highpc) 1.151 +{ 1.152 + int monsize; 1.153 + char *buffer; 1.154 + int o; 1.155 + 1.156 + /* 1.157 + * round lowpc and highpc to multiples of the density we're using 1.158 + * so the rest of the scaling (here and in gprof) stays in ints. 1.159 + */ 1.160 + lowpc = ROUNDDOWN(lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 1.161 + s_lowpc = lowpc; 1.162 + highpc = ROUNDUP(highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 1.163 + s_highpc = highpc; 1.164 + s_textsize = highpc - lowpc; 1.165 + monsize = (s_textsize / HISTFRACTION); 1.166 + buffer = (char *)calloc(1, 2*monsize ); 1.167 + if ( buffer == NULL ) { 1.168 + systemMessage(0, MSG); 1.169 + return; 1.170 + } 1.171 + froms = (unsigned short *) calloc(1, 4*s_textsize / HASHFRACTION ); 1.172 + if ( froms == NULL ) { 1.173 + systemMessage(0, MSG); 1.174 + free(buffer); 1.175 + buffer = NULL; 1.176 + return; 1.177 + } 1.178 + tolimit = s_textsize * ARCDENSITY / 100; 1.179 + if ( tolimit < MINARCS ) { 1.180 + tolimit = MINARCS; 1.181 + } else if ( tolimit > 65534 ) { 1.182 + tolimit = 65534; 1.183 + } 1.184 + tos = (struct tostruct *) calloc(1, tolimit * sizeof( struct tostruct ) ); 1.185 + if ( tos == NULL ) { 1.186 + systemMessage(0, MSG); 1.187 + 1.188 + free(buffer); 1.189 + buffer = NULL; 1.190 + 1.191 + free(froms); 1.192 + froms = NULL; 1.193 + 1.194 + return; 1.195 + } 1.196 + tos[0].link = 0; 1.197 + sbuf = buffer; 1.198 + ssiz = monsize; 1.199 + if ( monsize <= 0 ) 1.200 + return; 1.201 + o = highpc - lowpc; 1.202 + if( monsize < o ) 1.203 + s_scale = (int)(( (float) monsize / o ) * SCALE_1_TO_1); 1.204 + else 1.205 + s_scale = SCALE_1_TO_1; 1.206 + profControl(1); 1.207 +} 1.208 + 1.209 +void profCleanup() 1.210 +{ 1.211 + FILE *fd; 1.212 + int fromindex; 1.213 + int endfrom; 1.214 + u32 frompc; 1.215 + int toindex; 1.216 + struct gmon_hdr ghdr; 1.217 + 1.218 + profControl(0); 1.219 + fd = fopen( "gmon.out" , "wb" ); 1.220 + if ( fd == NULL ) { 1.221 + systemMessage( 0, "mcount: gmon.out" ); 1.222 + return; 1.223 + } 1.224 + 1.225 + memcpy(&ghdr.cookie[0], GMON_MAGIC, 4); 1.226 + profPut32((char *)ghdr.version, GMON_VERSION); 1.227 + 1.228 + if(fwrite(&ghdr, sizeof(ghdr), 1, fd) != 1) { 1.229 + systemMessage(0, "mcount: gmon.out header"); 1.230 + fclose(fd); 1.231 + return; 1.232 + } 1.233 + 1.234 + if(hz == 0) 1.235 + hz = 100; 1.236 + 1.237 + hist_num_bins = ssiz; 1.238 + 1.239 + if(profWrite8(fd, GMON_TAG_TIME_HIST) || 1.240 + profWrite32(fd, (u32)s_lowpc) || 1.241 + profWrite32(fd, (u32)s_highpc) || 1.242 + profWrite32(fd, hist_num_bins) || 1.243 + profWrite32(fd, hz) || 1.244 + profWrite(fd, hist_dimension, 15) || 1.245 + profWrite(fd, &hist_dimension_abbrev, 1)) { 1.246 + systemMessage(0, "mcount: gmon.out hist"); 1.247 + fclose(fd); 1.248 + return; 1.249 + } 1.250 + u16 *hist_sample = (u16 *)sbuf; 1.251 + 1.252 + u16 count; 1.253 + int i; 1.254 + 1.255 + for(i = 0; i < hist_num_bins; ++i) { 1.256 + profPut16((char *)&count, hist_sample[i]); 1.257 + 1.258 + if(fwrite(&count, sizeof(count), 1, fd) != 1) { 1.259 + systemMessage(0, "mcount: gmon.out sample"); 1.260 + fclose(fd); 1.261 + return; 1.262 + } 1.263 + } 1.264 + 1.265 + endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 1.266 + for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 1.267 + if ( froms[fromindex] == 0 ) { 1.268 + continue; 1.269 + } 1.270 + frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 1.271 + for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1.272 + if(profWrite8(fd, GMON_TAG_CG_ARC) || 1.273 + profWrite32(fd, (u32)frompc) || 1.274 + profWrite32(fd, (u32)tos[toindex].selfpc) || 1.275 + profWrite32(fd, tos[toindex].count)) { 1.276 + systemMessage(0, "mcount: arc"); 1.277 + fclose(fd); 1.278 + return; 1.279 + } 1.280 + } 1.281 + } 1.282 + fclose(fd); 1.283 +} 1.284 + 1.285 +void profCount() 1.286 +{ 1.287 + register u32 selfpc; 1.288 + register unsigned short *frompcindex; 1.289 + register struct tostruct *top; 1.290 + register struct tostruct *prevtop; 1.291 + register long toindex; 1.292 + 1.293 + /* 1.294 + * find the return address for mcount, 1.295 + * and the return address for mcount's caller. 1.296 + */ 1.297 + 1.298 + /* selfpc = pc pushed by mcount call. 1.299 + This identifies the function that was just entered. */ 1.300 + selfpc = (u32) reg[14].I; 1.301 + /* frompcindex = pc in preceding frame. 1.302 + This identifies the caller of the function just entered. */ 1.303 + frompcindex = (unsigned short *) reg[12].I; 1.304 + /* 1.305 + * check that we are profiling 1.306 + * and that we aren't recursively invoked. 1.307 + */ 1.308 + if (profiling) { 1.309 + goto out; 1.310 + } 1.311 + profiling++; 1.312 + /* 1.313 + * check that frompcindex is a reasonable pc value. 1.314 + * for example: signal catchers get called from the stack, 1.315 + * not from text space. too bad. 1.316 + */ 1.317 + frompcindex = (unsigned short *) ((long) frompcindex - (long) s_lowpc); 1.318 + if ((unsigned long) frompcindex > s_textsize) { 1.319 + goto done; 1.320 + } 1.321 + frompcindex = 1.322 + &froms[((long) frompcindex) / (HASHFRACTION * sizeof(*froms))]; 1.323 + toindex = *frompcindex; 1.324 + if (toindex == 0) { 1.325 + /* 1.326 + * first time traversing this arc 1.327 + */ 1.328 + toindex = ++tos[0].link; 1.329 + if (toindex >= tolimit) { 1.330 + goto overflow; 1.331 + } 1.332 + *frompcindex = (unsigned short)toindex; 1.333 + top = &tos[toindex]; 1.334 + top->selfpc = selfpc; 1.335 + top->count = 1; 1.336 + top->link = 0; 1.337 + goto done; 1.338 + } 1.339 + top = &tos[toindex]; 1.340 + if (top->selfpc == selfpc) { 1.341 + /* 1.342 + * arc at front of chain; usual case. 1.343 + */ 1.344 + top->count++; 1.345 + goto done; 1.346 + } 1.347 + /* 1.348 + * have to go looking down chain for it. 1.349 + * top points to what we are looking at, 1.350 + * prevtop points to previous top. 1.351 + * we know it is not at the head of the chain. 1.352 + */ 1.353 + for (; /* goto done */; ) { 1.354 + if (top->link == 0) { 1.355 + /* 1.356 + * top is end of the chain and none of the chain 1.357 + * had top->selfpc == selfpc. 1.358 + * so we allocate a new tostruct 1.359 + * and link it to the head of the chain. 1.360 + */ 1.361 + toindex = ++tos[0].link; 1.362 + if (toindex >= tolimit) { 1.363 + goto overflow; 1.364 + } 1.365 + top = &tos[toindex]; 1.366 + top->selfpc = selfpc; 1.367 + top->count = 1; 1.368 + top->link = *frompcindex; 1.369 + *frompcindex = (unsigned short)toindex; 1.370 + goto done; 1.371 + } 1.372 + /* 1.373 + * otherwise, check the next arc on the chain. 1.374 + */ 1.375 + prevtop = top; 1.376 + top = &tos[top->link]; 1.377 + if (top->selfpc == selfpc) { 1.378 + /* 1.379 + * there it is. 1.380 + * increment its count 1.381 + * move it to the head of the chain. 1.382 + */ 1.383 + top->count++; 1.384 + toindex = prevtop->link; 1.385 + prevtop->link = top->link; 1.386 + top->link = *frompcindex; 1.387 + *frompcindex = (unsigned short)toindex; 1.388 + goto done; 1.389 + } 1.390 + 1.391 + } 1.392 + done: 1.393 + profiling--; 1.394 + /* and fall through */ 1.395 + out: 1.396 + return; /* normal return restores saved registers */ 1.397 + 1.398 + overflow: 1.399 + profiling++; /* halt further profiling */ 1.400 +#define TOLIMIT "mcount: tos overflow\n" 1.401 + systemMessage(0, TOLIMIT); 1.402 + goto out; 1.403 +} 1.404 + 1.405 +void profSetHertz(int h) 1.406 +{ 1.407 + hz = h; 1.408 +}