123380Smckusick /* 229100Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 341966Smckusick * All rights reserved. 423380Smckusick * 541966Smckusick * %sccs.include.redist.c% 641966Smckusick * 7*42348Smckusick * @(#)subr_prof.c 7.8 (Berkeley) 05/25/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 2941966Smckusick #if defined(hp300) 3041966Smckusick char *s_lowpc = (char *)0x00000000; 3141966Smckusick #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 /* 9241966Smckusick * Special, non-profiled versions 9341966Smckusick */ 94*42348Smckusick #if defined(hp300) && !defined(__GNUC__) 9541966Smckusick #define splhigh _splhigh 9641966Smckusick #define splx _splx 9741966Smckusick #endif 9841966Smckusick 9941966Smckusick /* 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 */ 12941966Smckusick #ifdef __GNUC__ 13029946Skarels #if defined(vax) 13141966Smckusick Fix Me!! 13241966Smckusick #endif 13341966Smckusick #if defined(tahoe) 13441966Smckusick Fix Me!! 13541966Smckusick #endif 13641966Smckusick #if defined(hp300) 13741966Smckusick /* 13841966Smckusick * selfpc = pc pushed by mcount jsr, 13941966Smckusick * frompcindex = pc pushed by jsr into self. 14041966Smckusick * In GCC the caller's stack frame has already been built so we 14141966Smckusick * have to chase a6 to find caller's raddr. This assumes that all 14241966Smckusick * routines we are profiling were built with GCC and that all 14341966Smckusick * profiled routines use link/unlk. 14441966Smckusick */ 14541966Smckusick asm("movl a6@(4),%0" : "=r" (selfpc)); 14641966Smckusick asm("movl a6@(0)@(4),%0" : "=r" (frompcindex)); 14741966Smckusick #endif 14841966Smckusick #else 14941966Smckusick #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 15841966Smckusick #if defined(hp300) 15941966Smckusick asm(" .text"); /* make sure we're in text space */ 16041966Smckusick asm(" movl a6@(4),a5"); /* selfpc = pc pushed by mcount jsr */ 16141966Smckusick asm(" movl a6@(8),a4"); /* frompcindex = pc pushed by jsr into 16241966Smckusick self, stack frame not yet built */ 16329946Skarels #endif 16441966Smckusick #endif /* not __GNUC__ */ 16541966Smckusick #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 */ 171*42348Smckusick #if defined(hp300) && defined(__GNUC__) 172*42348Smckusick asm("movw sr,%0" : "=g" (s)); 173*42348Smckusick asm("movw #0x2700,sr"); 174*42348Smckusick #else 17516924Smckusick s = splhigh(); 176*42348Smckusick #endif 17716924Smckusick /* 17829946Skarels * Check that frompcindex is a reasonable pc value. 17929946Skarels * For example: signal catchers get called from the stack, 18029946Skarels * not from text space. too bad. 1817332Ssam */ 18229946Skarels frompcindex = (u_short *)((long)frompcindex - (long)s_lowpc); 18329946Skarels if ((u_long)frompcindex > s_textsize) 1847332Ssam goto done; 18510292Smckusick frompcindex = 18629946Skarels &froms[((long)frompcindex) / (HASHFRACTION * sizeof (*froms))]; 18710292Smckusick toindex = *frompcindex; 18810292Smckusick if (toindex == 0) { 18910292Smckusick /* 19029946Skarels * First time traversing this arc 19110292Smckusick */ 19210292Smckusick toindex = ++tos[0].link; 19329946Skarels if (toindex >= tolimit) 1947332Ssam goto overflow; 19510292Smckusick *frompcindex = toindex; 19610292Smckusick top = &tos[toindex]; 1977332Ssam top->selfpc = selfpc; 19810292Smckusick top->count = 1; 1997332Ssam top->link = 0; 20010292Smckusick goto done; 2017332Ssam } 20210292Smckusick top = &tos[toindex]; 20310292Smckusick if (top->selfpc == selfpc) { 20410292Smckusick /* 20529946Skarels * Arc at front of chain; usual case. 20610292Smckusick */ 20710292Smckusick top->count++; 20810292Smckusick goto done; 20910292Smckusick } 21010292Smckusick /* 21129946Skarels * Have to go looking down chain for it. 21229946Skarels * Top points to what we are looking at, 21329946Skarels * prevtop points to previous top. 21429946Skarels * We know it is not at the head of the chain. 21510292Smckusick */ 21610292Smckusick for (; /* goto done */; ) { 21710292Smckusick if (top->link == 0) { 21810292Smckusick /* 21929946Skarels * Top is end of the chain and none of the chain 22029946Skarels * had top->selfpc == selfpc. 22129946Skarels * So we allocate a new tostruct 22229946Skarels * and link it to the head of the chain. 22310292Smckusick */ 22410292Smckusick toindex = ++tos[0].link; 22529946Skarels if (toindex >= tolimit) 22610292Smckusick goto overflow; 22710292Smckusick top = &tos[toindex]; 22810292Smckusick top->selfpc = selfpc; 22910292Smckusick top->count = 1; 23010292Smckusick top->link = *frompcindex; 23110292Smckusick *frompcindex = toindex; 23210292Smckusick goto done; 23310292Smckusick } 23410292Smckusick /* 23529946Skarels * Otherwise, check the next arc on the chain. 23610292Smckusick */ 23710292Smckusick prevtop = top; 23810292Smckusick top = &tos[top->link]; 2397332Ssam if (top->selfpc == selfpc) { 24010292Smckusick /* 24129946Skarels * There it is, increment its count and 24229946Skarels * move it to the head of the chain. 24310292Smckusick */ 2447332Ssam top->count++; 24510292Smckusick toindex = prevtop->link; 24610292Smckusick prevtop->link = top->link; 24710292Smckusick top->link = *frompcindex; 24810292Smckusick *frompcindex = toindex; 24910292Smckusick goto done; 2507332Ssam } 25110292Smckusick 2527332Ssam } 2537332Ssam done: 254*42348Smckusick #if defined(hp300) && defined(__GNUC__) 255*42348Smckusick asm("movw %0,sr" : : "g" (s)); 256*42348Smckusick #else 25716924Smckusick splx(s); 258*42348Smckusick #endif 2597332Ssam /* and fall through */ 2607332Ssam out: 26129946Skarels #if defined(vax) 2627332Ssam asm(" rsb"); 26329946Skarels #endif 26429946Skarels return; 2657332Ssam overflow: 26610292Smckusick profiling = 3; 2677332Ssam printf("mcount: tos overflow\n"); 2687332Ssam goto out; 2697332Ssam } 27010292Smckusick asm(".text"); 27110292Smckusick asm("#the end of mcount()"); 27210292Smckusick asm(".data"); 27329946Skarels #endif 274