123380Smckusick /* 229100Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 3*41966Smckusick * All rights reserved. 423380Smckusick * 5*41966Smckusick * %sccs.include.redist.c% 6*41966Smckusick * 7*41966Smckusick * @(#)subr_prof.c 7.7 (Berkeley) 05/15/90 823380Smckusick */ 97332Ssam 107332Ssam #ifdef GPROF 1117094Sbloom #include "gprof.h" 1217094Sbloom #include "param.h" 1317094Sbloom #include "systm.h" 1431433Smckusick #include "malloc.h" 157332Ssam 167332Ssam /* 177332Ssam * Froms is actually a bunch of unsigned shorts indexing tos 187332Ssam */ 1929946Skarels int profiling = 3; 2029946Skarels u_short *froms; 2129946Skarels struct tostruct *tos = 0; 2229946Skarels long tolimit = 0; 2329946Skarels #if defined(vax) 247332Ssam char *s_lowpc = (char *)0x80000000; 259758Ssam #endif 2629946Skarels #if defined(tahoe) 2729946Skarels char *s_lowpc = (char *)0xc0000000; 2829946Skarels #endif 29*41966Smckusick #if defined(hp300) 30*41966Smckusick char *s_lowpc = (char *)0x00000000; 31*41966Smckusick #endif 3229946Skarels extern char etext; 3329946Skarels char *s_highpc = &etext; 347332Ssam u_long s_textsize = 0; 3529946Skarels int ssiz; 367332Ssam u_short *sbuf; 377332Ssam u_short *kcount; 387332Ssam 397332Ssam kmstartup() 407332Ssam { 4129946Skarels u_long fromssize, tossize; 427332Ssam 4310292Smckusick /* 4429946Skarels * Round lowpc and highpc to multiples of the density we're using 4529946Skarels * so the rest of the scaling (here and in gprof) stays in ints. 4610292Smckusick */ 4710292Smckusick s_lowpc = (char *) 4829946Skarels ROUNDDOWN((unsigned)s_lowpc, HISTFRACTION*sizeof (HISTCOUNTER)); 4910292Smckusick s_highpc = (char *) 5029946Skarels ROUNDUP((unsigned)s_highpc, HISTFRACTION*sizeof (HISTCOUNTER)); 517332Ssam s_textsize = s_highpc - s_lowpc; 527332Ssam printf("Profiling kernel, s_textsize=%d [%x..%x]\n", 537332Ssam s_textsize, s_lowpc, s_highpc); 5429946Skarels ssiz = (s_textsize / HISTFRACTION) + sizeof (struct phdr); 5531433Smckusick sbuf = (u_short *)malloc(ssiz, M_GPROF, M_WAITOK); 567332Ssam if (sbuf == 0) { 577332Ssam printf("No space for monitor buffer(s)\n"); 587332Ssam return; 597332Ssam } 6031922Smckusick bzero(sbuf, ssiz); 6110292Smckusick fromssize = s_textsize / HASHFRACTION; 6231433Smckusick froms = (u_short *)malloc(fromssize, M_GPROF, M_WAITOK); 637332Ssam if (froms == 0) { 647332Ssam printf("No space for monitor buffer(s)\n"); 6531433Smckusick free(sbuf, M_GPROF); 667332Ssam sbuf = 0; 677332Ssam return; 687332Ssam } 6937535Smckusick bzero(froms, fromssize); 7010292Smckusick tolimit = s_textsize * ARCDENSITY / 100; 7129946Skarels if (tolimit < MINARCS) 7210292Smckusick tolimit = MINARCS; 7329946Skarels else if (tolimit > (0xffff - 1)) 7429946Skarels tolimit = 0xffff - 1; 7529946Skarels tossize = tolimit * sizeof (struct tostruct); 7631433Smckusick tos = (struct tostruct *)malloc(tossize, M_GPROF, M_WAITOK); 777332Ssam if (tos == 0) { 787332Ssam printf("No space for monitor buffer(s)\n"); 7931433Smckusick free(sbuf, M_GPROF), sbuf = 0; 8031433Smckusick free(froms, M_GPROF), froms = 0; 817332Ssam return; 827332Ssam } 8331922Smckusick bzero(tos, tossize); 847332Ssam tos[0].link = 0; 857332Ssam ((struct phdr *)sbuf)->lpc = s_lowpc; 867332Ssam ((struct phdr *)sbuf)->hpc = s_highpc; 877332Ssam ((struct phdr *)sbuf)->ncnt = ssiz; 8829946Skarels kcount = (u_short *)(((int)sbuf) + sizeof (struct phdr)); 897332Ssam } 907332Ssam 917332Ssam /* 92*41966Smckusick * Special, non-profiled versions 93*41966Smckusick */ 94*41966Smckusick #if defined(hp300) 95*41966Smckusick #define splhigh _splhigh 96*41966Smckusick #define splx _splx 97*41966Smckusick #endif 98*41966Smckusick 99*41966Smckusick /* 10029946Skarels * This routine is massaged so that it may be jsb'ed to on vax. 1017332Ssam */ 10210292Smckusick asm(".text"); 10310292Smckusick asm("#the beginning of mcount()"); 10410292Smckusick asm(".data"); 1057332Ssam mcount() 1067332Ssam { 10729946Skarels register char *selfpc; /* r11 => r5 */ 10829946Skarels register u_short *frompcindex; /* r10 => r4 */ 10929946Skarels register struct tostruct *top; /* r9 => r3 */ 11029946Skarels register struct tostruct *prevtop; /* r8 => r2 */ 11129946Skarels register long toindex; /* r7 => r1 */ 11216924Smckusick static int s; 1137332Ssam 11429946Skarels asm(" .text"); /* make sure we're in text space */ 11529946Skarels /* 11629946Skarels * Check that we are profiling. 11729946Skarels */ 11829946Skarels if (profiling) 11929946Skarels goto out; 12029946Skarels /* 12129946Skarels * Find the return address for mcount, 12229946Skarels * and the return address for mcount's caller. 12329946Skarels */ 1247332Ssam #ifdef lint 12510292Smckusick selfpc = (char *)0; 1267332Ssam frompcindex = 0; 12729946Skarels #else 12833366Smckusick ; /* avoid label botch */ 129*41966Smckusick #ifdef __GNUC__ 13029946Skarels #if defined(vax) 131*41966Smckusick Fix Me!! 132*41966Smckusick #endif 133*41966Smckusick #if defined(tahoe) 134*41966Smckusick Fix Me!! 135*41966Smckusick #endif 136*41966Smckusick #if defined(hp300) 137*41966Smckusick /* 138*41966Smckusick * selfpc = pc pushed by mcount jsr, 139*41966Smckusick * frompcindex = pc pushed by jsr into self. 140*41966Smckusick * In GCC the caller's stack frame has already been built so we 141*41966Smckusick * have to chase a6 to find caller's raddr. This assumes that all 142*41966Smckusick * routines we are profiling were built with GCC and that all 143*41966Smckusick * profiled routines use link/unlk. 144*41966Smckusick */ 145*41966Smckusick asm("movl a6@(4),%0" : "=r" (selfpc)); 146*41966Smckusick asm("movl a6@(0)@(4),%0" : "=r" (frompcindex)); 147*41966Smckusick #endif 148*41966Smckusick #else 149*41966Smckusick #if defined(vax) 1507332Ssam asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ 1517332Ssam asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ 15229946Skarels #endif 15329946Skarels #if defined(tahoe) 15429946Skarels asm(" movl -8(fp),r12"); /* selfpc = callf frame */ 15529946Skarels asm(" movl (fp),r11"); 15629946Skarels asm(" movl -8(r11),r11"); /* frompcindex = 1 callf frame back */ 15729946Skarels #endif 158*41966Smckusick #if defined(hp300) 159*41966Smckusick asm(" .text"); /* make sure we're in text space */ 160*41966Smckusick asm(" movl a6@(4),a5"); /* selfpc = pc pushed by mcount jsr */ 161*41966Smckusick asm(" movl a6@(8),a4"); /* frompcindex = pc pushed by jsr into 162*41966Smckusick self, stack frame not yet built */ 16329946Skarels #endif 164*41966Smckusick #endif /* not __GNUC__ */ 165*41966Smckusick #endif /* not lint */ 1667332Ssam /* 16729946Skarels * Insure that we cannot be recursively invoked. 16829946Skarels * this requires that splhigh() and splx() below 16929946Skarels * do NOT call mcount! 1707332Ssam */ 17116924Smckusick s = splhigh(); 17216924Smckusick /* 17329946Skarels * Check that frompcindex is a reasonable pc value. 17429946Skarels * For example: signal catchers get called from the stack, 17529946Skarels * not from text space. too bad. 1767332Ssam */ 17729946Skarels frompcindex = (u_short *)((long)frompcindex - (long)s_lowpc); 17829946Skarels if ((u_long)frompcindex > s_textsize) 1797332Ssam goto done; 18010292Smckusick frompcindex = 18129946Skarels &froms[((long)frompcindex) / (HASHFRACTION * sizeof (*froms))]; 18210292Smckusick toindex = *frompcindex; 18310292Smckusick if (toindex == 0) { 18410292Smckusick /* 18529946Skarels * First time traversing this arc 18610292Smckusick */ 18710292Smckusick toindex = ++tos[0].link; 18829946Skarels if (toindex >= tolimit) 1897332Ssam goto overflow; 19010292Smckusick *frompcindex = toindex; 19110292Smckusick top = &tos[toindex]; 1927332Ssam top->selfpc = selfpc; 19310292Smckusick top->count = 1; 1947332Ssam top->link = 0; 19510292Smckusick goto done; 1967332Ssam } 19710292Smckusick top = &tos[toindex]; 19810292Smckusick if (top->selfpc == selfpc) { 19910292Smckusick /* 20029946Skarels * Arc at front of chain; usual case. 20110292Smckusick */ 20210292Smckusick top->count++; 20310292Smckusick goto done; 20410292Smckusick } 20510292Smckusick /* 20629946Skarels * Have to go looking down chain for it. 20729946Skarels * Top points to what we are looking at, 20829946Skarels * prevtop points to previous top. 20929946Skarels * We know it is not at the head of the chain. 21010292Smckusick */ 21110292Smckusick for (; /* goto done */; ) { 21210292Smckusick if (top->link == 0) { 21310292Smckusick /* 21429946Skarels * Top is end of the chain and none of the chain 21529946Skarels * had top->selfpc == selfpc. 21629946Skarels * So we allocate a new tostruct 21729946Skarels * and link it to the head of the chain. 21810292Smckusick */ 21910292Smckusick toindex = ++tos[0].link; 22029946Skarels if (toindex >= tolimit) 22110292Smckusick goto overflow; 22210292Smckusick top = &tos[toindex]; 22310292Smckusick top->selfpc = selfpc; 22410292Smckusick top->count = 1; 22510292Smckusick top->link = *frompcindex; 22610292Smckusick *frompcindex = toindex; 22710292Smckusick goto done; 22810292Smckusick } 22910292Smckusick /* 23029946Skarels * Otherwise, check the next arc on the chain. 23110292Smckusick */ 23210292Smckusick prevtop = top; 23310292Smckusick top = &tos[top->link]; 2347332Ssam if (top->selfpc == selfpc) { 23510292Smckusick /* 23629946Skarels * There it is, increment its count and 23729946Skarels * move it to the head of the chain. 23810292Smckusick */ 2397332Ssam top->count++; 24010292Smckusick toindex = prevtop->link; 24110292Smckusick prevtop->link = top->link; 24210292Smckusick top->link = *frompcindex; 24310292Smckusick *frompcindex = toindex; 24410292Smckusick goto done; 2457332Ssam } 24610292Smckusick 2477332Ssam } 2487332Ssam done: 24916924Smckusick splx(s); 2507332Ssam /* and fall through */ 2517332Ssam out: 25229946Skarels #if defined(vax) 2537332Ssam asm(" rsb"); 25429946Skarels #endif 25529946Skarels return; 2567332Ssam overflow: 25710292Smckusick profiling = 3; 2587332Ssam printf("mcount: tos overflow\n"); 2597332Ssam goto out; 2607332Ssam } 26110292Smckusick asm(".text"); 26210292Smckusick asm("#the end of mcount()"); 26310292Smckusick asm(".data"); 26429946Skarels #endif 265