annotate src/prof/prof.cpp @ 237:ff37bc3004a7

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