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