1 /*- 2 * Copyright (c) 1983 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)gmon.c 5.9 (Berkeley) 03/03/92"; 10 #endif /* not lint */ 11 12 #include <unistd.h> 13 #include <sys/types.h> 14 #include <sys/time.h> 15 #include <sys/kinfo.h> 16 17 #ifdef DEBUG 18 #include <stdio.h> 19 #endif 20 21 #include "gmon.h" 22 23 extern char *minbrk asm ("minbrk"); 24 25 /* 26 * froms is actually a bunch of unsigned shorts indexing tos 27 */ 28 static int profiling = 3; 29 static unsigned short *froms; 30 static struct tostruct *tos = 0; 31 static long tolimit = 0; 32 static char *s_lowpc = 0; 33 static char *s_highpc = 0; 34 static unsigned long s_textsize = 0; 35 36 static int ssiz; 37 static char *sbuf; 38 static int s_scale; 39 /* see profil(2) where this is describe (incorrectly) */ 40 #define SCALE_1_TO_1 0x10000L 41 42 #define MSG "No space for profiling buffer(s)\n" 43 44 monstartup(lowpc, highpc) 45 char *lowpc; 46 char *highpc; 47 { 48 int monsize; 49 char *buffer; 50 register int o; 51 struct clockinfo clockinfo; 52 int size; 53 54 /* 55 * round lowpc and highpc to multiples of the density we're using 56 * so the rest of the scaling (here and in gprof) stays in ints. 57 */ 58 lowpc = (char *) 59 ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 60 s_lowpc = lowpc; 61 highpc = (char *) 62 ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 63 s_highpc = highpc; 64 s_textsize = highpc - lowpc; 65 monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 66 buffer = sbrk( monsize ); 67 if ( buffer == (char *) -1 ) { 68 write( 2 , MSG , sizeof(MSG) ); 69 return; 70 } 71 froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 72 if ( froms == (unsigned short *) -1 ) { 73 write( 2 , MSG , sizeof(MSG) ); 74 froms = 0; 75 return; 76 } 77 tolimit = s_textsize * ARCDENSITY / 100; 78 if ( tolimit < MINARCS ) { 79 tolimit = MINARCS; 80 } else if ( tolimit > 65534 ) { 81 tolimit = 65534; 82 } 83 tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 84 if ( tos == (struct tostruct *) -1 ) { 85 write( 2 , MSG , sizeof(MSG) ); 86 froms = 0; 87 tos = 0; 88 return; 89 } 90 minbrk = sbrk(0); 91 tos[0].link = 0; 92 sbuf = buffer; 93 ssiz = monsize; 94 ( (struct phdr *) buffer ) -> lpc = lowpc; 95 ( (struct phdr *) buffer ) -> hpc = highpc; 96 ( (struct phdr *) buffer ) -> ncnt = ssiz; 97 ( (struct phdr *) buffer ) -> version = GMONVERSION; 98 monsize -= sizeof(struct phdr); 99 if ( monsize <= 0 ) 100 return; 101 o = highpc - lowpc; 102 if( monsize < o ) 103 #ifndef hp300 104 s_scale = ( (float) monsize / o ) * SCALE_1_TO_1; 105 #else /* avoid floating point */ 106 { 107 int quot = o / monsize; 108 109 if (quot >= 0x10000) 110 s_scale = 1; 111 else if (quot >= 0x100) 112 s_scale = 0x10000 / quot; 113 else if (o >= 0x800000) 114 s_scale = 0x1000000 / (o / (monsize >> 8)); 115 else 116 s_scale = 0x1000000 / ((o << 8) / monsize); 117 } 118 #endif 119 else 120 s_scale = SCALE_1_TO_1; 121 moncontrol(1); 122 size = sizeof( clockinfo ); 123 if ( getkerninfo( KINFO_CLOCKRATE , &clockinfo , &size , 0 ) < 0 ) { 124 /* 125 * Best guess 126 */ 127 clockinfo.profhz = hertz(); 128 } else if ( clockinfo.profhz == 0 ) { 129 if ( clockinfo.hz != 0 ) 130 clockinfo.profhz = clockinfo.hz; 131 else 132 clockinfo.profhz = hertz(); 133 } 134 ( (struct phdr *) buffer ) -> profrate = clockinfo.profhz; 135 } 136 137 _mcleanup() 138 { 139 int fd; 140 int fromindex; 141 int endfrom; 142 char *frompc; 143 int toindex; 144 struct rawarc rawarc; 145 146 moncontrol(0); 147 fd = creat( "gmon.out" , 0666 ); 148 if ( fd < 0 ) { 149 perror( "mcount: gmon.out" ); 150 return; 151 } 152 # ifdef DEBUG 153 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 154 # endif DEBUG 155 write( fd , sbuf , ssiz ); 156 endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 157 for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 158 if ( froms[fromindex] == 0 ) { 159 continue; 160 } 161 frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 162 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 163 # ifdef DEBUG 164 fprintf( stderr , 165 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 166 frompc , tos[toindex].selfpc , tos[toindex].count ); 167 # endif DEBUG 168 rawarc.raw_frompc = (unsigned long) frompc; 169 rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 170 rawarc.raw_count = tos[toindex].count; 171 write( fd , &rawarc , sizeof rawarc ); 172 } 173 } 174 close( fd ); 175 } 176 177 /* 178 * Control profiling 179 * profiling is what mcount checks to see if 180 * all the data structures are ready. 181 */ 182 moncontrol(mode) 183 int mode; 184 { 185 if (mode) { 186 /* start */ 187 profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 188 (int)s_lowpc, s_scale); 189 profiling = 0; 190 } else { 191 /* stop */ 192 profil((char *)0, 0, 0, 0); 193 profiling = 3; 194 } 195 } 196 197 /* 198 * discover the tick frequency of the machine 199 * if something goes wrong, we return 0, an impossible hertz. 200 */ 201 202 hertz() 203 { 204 struct itimerval tim; 205 206 tim.it_interval.tv_sec = 0; 207 tim.it_interval.tv_usec = 1; 208 tim.it_value.tv_sec = 0; 209 tim.it_value.tv_usec = 0; 210 setitimer(ITIMER_REAL, &tim, 0); 211 setitimer(ITIMER_REAL, 0, &tim); 212 if (tim.it_interval.tv_usec < 2) 213 return(0); 214 return (1000000 / tim.it_interval.tv_usec); 215 } 216