BSD 4_4 release
[unix-history] / usr / src / lib / csu / vax.pcc / gmon.c
CommitLineData
ad787160
C
1/*-
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This module is believed to contain source code proprietary to AT&T.
6 * Use and redistribution is subject to the Berkeley Software License
7 * Agreement and your Software Agreement with AT&T (Western Electric).
586c39b1
DF
8 */
9
2ce81398 10#if defined(LIBC_SCCS) && !defined(lint)
ad787160
C
11static char sccsid[] = "@(#)gmon.c 5.5 (Berkeley) 4/12/91";
12#endif /* LIBC_SCCS and not lint */
50084e08 13
bb9c5045 14#ifdef DEBUG
50084e08 15#include <stdio.h>
ad787160 16#endif
50084e08 17
ee56ba6f 18#include "gmon.h"
387d0540
PK
19
20 /*
21 * froms is actually a bunch of unsigned shorts indexing tos
22 */
5a9da8d5 23static int profiling = 3;
50084e08
PK
24static unsigned short *froms;
25static struct tostruct *tos = 0;
019e8582 26static long tolimit = 0;
50084e08
PK
27static char *s_lowpc = 0;
28static char *s_highpc = 0;
3a2b18f4 29static unsigned long s_textsize = 0;
50084e08 30
387d0540 31static int ssiz;
37a37eeb 32static char *sbuf;
13c3ba68 33static int s_scale;
37a37eeb
PK
34 /* see profil(2) where this is describe (incorrectly) */
35#define SCALE_1_TO_1 0x10000L
50084e08 36
50084e08
PK
37#define MSG "No space for monitor buffer(s)\n"
38
ee56ba6f 39monstartup(lowpc, highpc)
387d0540
PK
40 char *lowpc;
41 char *highpc;
50084e08 42{
3a2b18f4
PK
43 int monsize;
44 char *buffer;
45 char *sbrk();
b8c5b964 46 extern char *minbrk;
50084e08 47
019e8582
PK
48 /*
49 * round lowpc and highpc to multiples of the density we're using
50 * so the rest of the scaling (here and in gprof) stays in ints.
51 */
52 lowpc = (char *)
53 ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
387d0540 54 s_lowpc = lowpc;
019e8582
PK
55 highpc = (char *)
56 ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
387d0540 57 s_highpc = highpc;
3a2b18f4 58 s_textsize = highpc - lowpc;
019e8582 59 monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
387d0540
PK
60 buffer = sbrk( monsize );
61 if ( buffer == (char *) -1 ) {
44be2432 62 write( 2 , MSG , sizeof(MSG) - 1 );
387d0540
PK
63 return;
64 }
f4d8fa4a 65 froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
387d0540 66 if ( froms == (unsigned short *) -1 ) {
44be2432 67 write( 2 , MSG , sizeof(MSG) - 1 );
387d0540
PK
68 froms = 0;
69 return;
70 }
5a9da8d5
KM
71 tolimit = s_textsize * ARCDENSITY / 100;
72 if ( tolimit < MINARCS ) {
73 tolimit = MINARCS;
74 } else if ( tolimit > 65534 ) {
75 tolimit = 65534;
4dff44be 76 }
5a9da8d5 77 tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
387d0540 78 if ( tos == (struct tostruct *) -1 ) {
44be2432 79 write( 2 , MSG , sizeof(MSG) - 1 );
387d0540
PK
80 froms = 0;
81 tos = 0;
82 return;
83 }
b8c5b964 84 minbrk = sbrk(0);
387d0540 85 tos[0].link = 0;
5a9da8d5 86 monitor( lowpc , highpc , buffer , monsize , tolimit );
50084e08
PK
87}
88
89_mcleanup()
90{
bb9c5045
KM
91 int fd;
92 int fromindex;
f4d8fa4a 93 int endfrom;
bb9c5045
KM
94 char *frompc;
95 int toindex;
96 struct rawarc rawarc;
50084e08 97
bb9c5045
KM
98 fd = creat( "gmon.out" , 0666 );
99 if ( fd < 0 ) {
387d0540 100 perror( "mcount: gmon.out" );
50084e08
PK
101 return;
102 }
387d0540
PK
103# ifdef DEBUG
104 fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
105# endif DEBUG
bb9c5045 106 write( fd , sbuf , ssiz );
f4d8fa4a
KM
107 endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
108 for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
50084e08
PK
109 if ( froms[fromindex] == 0 ) {
110 continue;
111 }
f4d8fa4a 112 frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
50084e08
PK
113 for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
114# ifdef DEBUG
22f3ec41
PK
115 fprintf( stderr ,
116 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
50084e08
PK
117 frompc , tos[toindex].selfpc , tos[toindex].count );
118# endif DEBUG
bb9c5045
KM
119 rawarc.raw_frompc = (unsigned long) frompc;
120 rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
121 rawarc.raw_count = tos[toindex].count;
122 write( fd , &rawarc , sizeof rawarc );
50084e08
PK
123 }
124 }
bb9c5045 125 close( fd );
50084e08
PK
126}
127
019e8582 128asm(".text");
13c3ba68 129asm(".align 2");
019e8582
PK
130asm("#the beginning of mcount()");
131asm(".data");
50084e08
PK
132mcount()
133{
019e8582
PK
134 register char *selfpc; /* r11 => r5 */
135 register unsigned short *frompcindex; /* r10 => r4 */
136 register struct tostruct *top; /* r9 => r3 */
137 register struct tostruct *prevtop; /* r8 => r2 */
138 register long toindex; /* r7 => r1 */
019e8582 139
50084e08 140 /*
785a53a1
PK
141 * find the return address for mcount,
142 * and the return address for mcount's caller.
50084e08 143 */
019e8582
PK
144 asm(" .text"); /* make sure we're in text space */
145 asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */
146 asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */
785a53a1
PK
147 /*
148 * check that we are profiling
387d0540 149 * and that we aren't recursively invoked.
785a53a1 150 */
019e8582
PK
151 if (profiling) {
152 goto out;
153 }
5a9da8d5 154 profiling++;
785a53a1
PK
155 /*
156 * check that frompcindex is a reasonable pc value.
157 * for example: signal catchers get called from the stack,
158 * not from text space. too bad.
159 */
019e8582
PK
160 frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
161 if ((unsigned long)frompcindex > s_textsize) {
162 goto done;
50084e08 163 }
019e8582 164 frompcindex =
f4d8fa4a 165 &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
019e8582
PK
166 toindex = *frompcindex;
167 if (toindex == 0) {
168 /*
169 * first time traversing this arc
170 */
171 toindex = ++tos[0].link;
172 if (toindex >= tolimit) {
173 goto overflow;
174 }
175 *frompcindex = toindex;
176 top = &tos[toindex];
177 top->selfpc = selfpc;
178 top->count = 1;
179 top->link = 0;
180 goto done;
50084e08 181 }
019e8582
PK
182 top = &tos[toindex];
183 if (top->selfpc == selfpc) {
184 /*
185 * arc at front of chain; usual case.
186 */
187 top->count++;
188 goto done;
189 }
190 /*
191 * have to go looking down chain for it.
192 * top points to what we are looking at,
193 * prevtop points to previous top.
194 * we know it is not at the head of the chain.
195 */
196 for (; /* goto done */; ) {
197 if (top->link == 0) {
198 /*
199 * top is end of the chain and none of the chain
200 * had top->selfpc == selfpc.
201 * so we allocate a new tostruct
202 * and link it to the head of the chain.
203 */
204 toindex = ++tos[0].link;
205 if (toindex >= tolimit) {
206 goto overflow;
207 }
208 top = &tos[toindex];
209 top->selfpc = selfpc;
210 top->count = 1;
211 top->link = *frompcindex;
212 *frompcindex = toindex;
213 goto done;
214 }
215 /*
216 * otherwise, check the next arc on the chain.
217 */
218 prevtop = top;
219 top = &tos[top->link];
220 if (top->selfpc == selfpc) {
221 /*
222 * there it is.
223 * increment its count
224 * move it to the head of the chain.
225 */
226 top->count++;
227 toindex = prevtop->link;
228 prevtop->link = top->link;
229 top->link = *frompcindex;
230 *frompcindex = toindex;
231 goto done;
232 }
233
50084e08 234 }
785a53a1 235done:
5a9da8d5 236 profiling--;
019e8582 237 /* and fall through */
50084e08 238out:
019e8582 239 asm(" rsb");
50084e08
PK
240
241overflow:
5a9da8d5 242 profiling++; /* halt further profiling */
50084e08 243# define TOLIMIT "mcount: tos overflow\n"
44be2432 244 write(2, TOLIMIT, sizeof(TOLIMIT) - 1);
019e8582 245 goto out;
50084e08 246}
019e8582
PK
247asm(".text");
248asm("#the end of mcount()");
249asm(".data");
50084e08 250
ee56ba6f
KM
251/*VARARGS1*/
252monitor( lowpc , highpc , buf , bufsiz , nfunc )
387d0540 253 char *lowpc;
387d0540 254 char *highpc;
37a37eeb
PK
255 char *buf; /* declared ``short buffer[]'' in monitor(3) */
256 int bufsiz;
ee56ba6f 257 int nfunc; /* not used, available for compatability only */
50084e08 258{
387d0540 259 register o;
50084e08 260
387d0540 261 if ( lowpc == 0 ) {
13c3ba68 262 moncontrol(0);
ee56ba6f 263 _mcleanup();
387d0540
PK
264 return;
265 }
266 sbuf = buf;
267 ssiz = bufsiz;
268 ( (struct phdr *) buf ) -> lpc = lowpc;
269 ( (struct phdr *) buf ) -> hpc = highpc;
270 ( (struct phdr *) buf ) -> ncnt = ssiz;
37a37eeb 271 bufsiz -= sizeof(struct phdr);
387d0540
PK
272 if ( bufsiz <= 0 )
273 return;
37a37eeb 274 o = highpc - lowpc;
387d0540 275 if( bufsiz < o )
37a37eeb 276 s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1;
387d0540 277 else
37a37eeb 278 s_scale = SCALE_1_TO_1;
13c3ba68
PK
279 moncontrol(1);
280}
281
282/*
283 * Control profiling
284 * profiling is what mcount checks to see if
285 * all the data structures are ready.
286 */
287moncontrol(mode)
288 int mode;
289{
290 if (mode) {
291 /* start */
292 profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr),
293 s_lowpc, s_scale);
294 profiling = 0;
295 } else {
296 /* stop */
297 profil((char *)0, 0, 0, 0);
298 profiling = 3;
299 }
50084e08 300}