|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /*- ! 27: * Copyright (c) 1982, 1986, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)subr_prof.c 8.3 (Berkeley) 9/23/93 ! 59: */ ! 60: ! 61: #include <sys/param.h> ! 62: #include <sys/systm.h> ! 63: #include <sys/kernel.h> ! 64: #include <sys/proc.h> ! 65: #include <sys/user.h> ! 66: #include <machine/spl.h> ! 67: ! 68: #include <sys/mount.h> ! 69: ! 70: #include <machine/cpu.h> ! 71: ! 72: #ifdef GPROF ! 73: #include <sys/malloc.h> ! 74: #include <sys/gmon.h> ! 75: #include <kern/mach_header.h> ! 76: #include <machine/profile.h> ! 77: ! 78: /* ! 79: * Froms is actually a bunch of unsigned shorts indexing tos ! 80: */ ! 81: struct gmonparam _gmonparam = { GMON_PROF_OFF }; ! 82: ! 83: kmstartup() ! 84: { ! 85: char *cp; ! 86: u_long fromssize, tossize; ! 87: struct segment_command *sgp; ! 88: struct gmonparam *p = &_gmonparam; ! 89: ! 90: sgp = getsegbyname("__TEXT"); ! 91: p->lowpc = (u_long)sgp->vmaddr; ! 92: p->highpc = (u_long)(sgp->vmaddr + sgp->vmsize); ! 93: ! 94: /* ! 95: * Round lowpc and highpc to multiples of the density we're using ! 96: * so the rest of the scaling (here and in gprof) stays in ints. ! 97: */ ! 98: p->lowpc = ROUNDDOWN(p->lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); ! 99: p->highpc = ROUNDUP(p->highpc, HISTFRACTION * sizeof(HISTCOUNTER)); ! 100: p->textsize = p->highpc - p->lowpc; ! 101: printf("Profiling kernel, textsize=%d [0x%08x..0x%08x]\n", ! 102: p->textsize, p->lowpc, p->highpc); ! 103: p->kcountsize = p->textsize / HISTFRACTION; ! 104: p->hashfraction = HASHFRACTION; ! 105: p->fromssize = p->textsize / HASHFRACTION; ! 106: p->tolimit = p->textsize * ARCDENSITY / 100; ! 107: if (p->tolimit < MINARCS) ! 108: p->tolimit = MINARCS; ! 109: else if (p->tolimit > MAXARCS) ! 110: p->tolimit = MAXARCS; ! 111: p->tossize = p->tolimit * sizeof(struct tostruct); ! 112: /* Why not use MALLOC with M_GPROF ? */ ! 113: cp = (char *)kalloc(p->kcountsize + p->fromssize + p->tossize); ! 114: if (cp == 0) { ! 115: printf("No memory for profiling.\n"); ! 116: return; ! 117: } ! 118: bzero(cp, p->kcountsize + p->tossize + p->fromssize); ! 119: p->tos = (struct tostruct *)cp; ! 120: cp += p->tossize; ! 121: p->kcount = (u_short *)cp; ! 122: cp += p->kcountsize; ! 123: p->froms = (u_short *)cp; ! 124: } ! 125: ! 126: /* ! 127: * Return kernel profiling information. ! 128: */ ! 129: sysctl_doprof(name, namelen, oldp, oldlenp, newp, newlen, p) ! 130: int *name; ! 131: u_int namelen; ! 132: void *oldp; ! 133: size_t *oldlenp; ! 134: void *newp; ! 135: size_t newlen; ! 136: { ! 137: struct gmonparam *gp = &_gmonparam; ! 138: int error; ! 139: ! 140: /* all sysctl names at this level are terminal */ ! 141: if (namelen != 1) ! 142: return (ENOTDIR); /* overloaded */ ! 143: ! 144: switch (name[0]) { ! 145: case GPROF_STATE: ! 146: error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state); ! 147: if (error) ! 148: return (error); ! 149: if (gp->state == GMON_PROF_OFF) ! 150: stopprofclock(kernproc); ! 151: else ! 152: startprofclock(kernproc); ! 153: return (0); ! 154: case GPROF_COUNT: ! 155: return (sysctl_struct(oldp, oldlenp, newp, newlen, ! 156: gp->kcount, gp->kcountsize)); ! 157: case GPROF_FROMS: ! 158: return (sysctl_struct(oldp, oldlenp, newp, newlen, ! 159: gp->froms, gp->fromssize)); ! 160: case GPROF_TOS: ! 161: return (sysctl_struct(oldp, oldlenp, newp, newlen, ! 162: gp->tos, gp->tossize)); ! 163: case GPROF_GMONPARAM: ! 164: return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp)); ! 165: default: ! 166: return (EOPNOTSUPP); ! 167: } ! 168: /* NOTREACHED */ ! 169: } ! 170: ! 171: ! 172: /* ! 173: * mcount() called with interrupts disabled. ! 174: */ ! 175: void ! 176: mcount( ! 177: register u_long frompc, ! 178: register u_long selfpc ! 179: ) ! 180: { ! 181: unsigned short *frompcindex; ! 182: register struct tostruct *top, *prevtop; ! 183: struct gmonparam *p = &_gmonparam; ! 184: register long toindex; ! 185: MCOUNT_INIT; ! 186: ! 187: /* ! 188: * check that we are profiling ! 189: * and that we aren't recursively invoked. ! 190: */ ! 191: if (p->state != GMON_PROF_ON) ! 192: return; ! 193: ! 194: MCOUNT_ENTER; ! 195: ! 196: /* ! 197: * check that frompcindex is a reasonable pc value. ! 198: * for example: signal catchers get called from the stack, ! 199: * not from text space. too bad. ! 200: */ ! 201: frompc -= p->lowpc; ! 202: if (frompc > p->textsize) ! 203: goto done; ! 204: ! 205: frompcindex = &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))]; ! 206: toindex = *frompcindex; ! 207: if (toindex == 0) { ! 208: /* ! 209: * first time traversing this arc ! 210: */ ! 211: toindex = ++p->tos[0].link; ! 212: if (toindex >= p->tolimit) { ! 213: /* halt further profiling */ ! 214: goto overflow; ! 215: } ! 216: *frompcindex = toindex; ! 217: top = &p->tos[toindex]; ! 218: top->selfpc = selfpc; ! 219: top->count = 1; ! 220: top->link = 0; ! 221: goto done; ! 222: } ! 223: top = &p->tos[toindex]; ! 224: if (top->selfpc == selfpc) { ! 225: /* ! 226: * arc at front of chain; usual case. ! 227: */ ! 228: top->count++; ! 229: goto done; ! 230: } ! 231: /* ! 232: * have to go looking down chain for it. ! 233: * top points to what we are looking at, ! 234: * prevtop points to previous top. ! 235: * we know it is not at the head of the chain. ! 236: */ ! 237: for (; /* goto done */; ) { ! 238: if (top->link == 0) { ! 239: /* ! 240: * top is end of the chain and none of the chain ! 241: * had top->selfpc == selfpc. ! 242: * so we allocate a new tostruct ! 243: * and link it to the head of the chain. ! 244: */ ! 245: toindex = ++p->tos[0].link; ! 246: if (toindex >= p->tolimit) { ! 247: goto overflow; ! 248: } ! 249: top = &p->tos[toindex]; ! 250: top->selfpc = selfpc; ! 251: top->count = 1; ! 252: top->link = *frompcindex; ! 253: *frompcindex = toindex; ! 254: goto done; ! 255: } ! 256: /* ! 257: * otherwise, check the next arc on the chain. ! 258: */ ! 259: prevtop = top; ! 260: top = &p->tos[top->link]; ! 261: if (top->selfpc == selfpc) { ! 262: /* ! 263: * there it is. ! 264: * increment its count ! 265: * move it to the head of the chain. ! 266: */ ! 267: top->count++; ! 268: toindex = prevtop->link; ! 269: prevtop->link = top->link; ! 270: top->link = *frompcindex; ! 271: *frompcindex = toindex; ! 272: goto done; ! 273: } ! 274: ! 275: } ! 276: done: ! 277: MCOUNT_EXIT; ! 278: return; ! 279: ! 280: overflow: ! 281: p->state = GMON_PROF_ERROR; ! 282: MCOUNT_EXIT; ! 283: printf("mcount: tos overflow\n"); ! 284: return; ! 285: } ! 286: ! 287: #endif /* GPROF */ ! 288: ! 289: #if NCPUS > 1 ! 290: #define PROFILE_LOCK(x) simple_lock(x) ! 291: #define PROFILE_UNLOCK(x) simple_unlock(x) ! 292: #else ! 293: #define PROFILE_LOCK(x) ! 294: #define PROFILE_UNLOCK(x) ! 295: #endif ! 296: ! 297: struct profil_args { ! 298: short *bufbase; ! 299: u_int bufsize; ! 300: u_int pcoffset; ! 301: u_int pcscale; ! 302: }; ! 303: int ! 304: profil(p, uap, retval) ! 305: struct proc *p; ! 306: register struct profil_args *uap; ! 307: register_t *retval; ! 308: { ! 309: register struct uprof *upp = &p->p_stats->p_prof; ! 310: struct uprof *upc, *nupc; ! 311: int s; ! 312: ! 313: if (uap->pcscale > (1 << 16)) ! 314: return (EINVAL); ! 315: if (uap->pcscale == 0) { ! 316: stopprofclock(p); ! 317: return (0); ! 318: } ! 319: ! 320: /* Block profile interrupts while changing state. */ ! 321: s = splstatclock(); ! 322: PROFILE_LOCK(&upp->pr_lock); ! 323: upp->pr_base = (caddr_t)uap->bufbase; ! 324: upp->pr_size = uap->bufsize; ! 325: upp->pr_off = uap->pcoffset; ! 326: upp->pr_scale = uap->pcscale; ! 327: ! 328: /* remove buffers previously allocated with add_profil() */ ! 329: for (upc = upp->pr_next; upc; upc = nupc) { ! 330: nupc = upc->pr_next; ! 331: kfree(upc, sizeof (struct uprof)); ! 332: } ! 333: ! 334: upp->pr_next = 0; ! 335: PROFILE_UNLOCK(&upp->pr_lock); ! 336: startprofclock(p); ! 337: splx(s); ! 338: return(0); ! 339: } ! 340: ! 341: struct add_profile_args { ! 342: short *bufbase; ! 343: u_int bufsize; ! 344: u_int pcoffset; ! 345: u_int pcscale; ! 346: }; ! 347: int ! 348: add_profil(p, uap, retval) ! 349: struct proc *p; ! 350: register struct add_profile_args *uap; ! 351: register_t *retval; ! 352: { ! 353: struct uprof *upp = &p->p_stats->p_prof, *upc; ! 354: int s; ! 355: ! 356: if (upp->pr_scale == 0) ! 357: return (0); ! 358: s = splstatclock(); ! 359: upc = (struct uprof *) kalloc(sizeof (struct uprof)); ! 360: upc->pr_base = (caddr_t)uap->bufbase; ! 361: upc->pr_size = uap->bufsize; ! 362: upc->pr_off = uap->pcoffset; ! 363: upc->pr_scale = uap->pcscale; ! 364: PROFILE_LOCK(&upp->pr_lock); ! 365: upc->pr_next = upp->pr_next; ! 366: upp->pr_next = upc; ! 367: PROFILE_UNLOCK(&upp->pr_lock); ! 368: splx(s); ! 369: return(0); ! 370: } ! 371: ! 372: /* ! 373: * Scale is a fixed-point number with the binary point 16 bits ! 374: * into the value, and is <= 1.0. pc is at most 32 bits, so the ! 375: * intermediate result is at most 48 bits. ! 376: */ ! 377: #define PC_TO_INDEX(pc, prof) \ ! 378: ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \ ! 379: (u_quad_t)((prof)->pr_scale)) >> 16) & ~1) ! 380: ! 381: /* ! 382: * Collect user-level profiling statistics; called on a profiling tick, ! 383: * when a process is running in user-mode. We use ! 384: * an AST that will vector us to trap() with a context in which copyin ! 385: * and copyout will work. Trap will then call addupc_task(). ! 386: * ! 387: * Note that we may (rarely) not get around to the AST soon enough, and ! 388: * lose profile ticks when the next tick overwrites this one, but in this ! 389: * case the system is overloaded and the profile is probably already ! 390: * inaccurate. ! 391: * ! 392: * We can afford to take faults here. If the ! 393: * update fails, we simply turn off profiling. ! 394: */ ! 395: void ! 396: addupc_task(p, pc, ticks) ! 397: register struct proc *p; ! 398: register u_long pc; ! 399: u_int ticks; ! 400: { ! 401: register struct uprof *prof; ! 402: register short *cell; ! 403: register u_int off; ! 404: u_short count; ! 405: ! 406: /* Testing P_PROFIL may be unnecessary, but is certainly safe. */ ! 407: if ((p->p_flag & P_PROFIL) == 0 || ticks == 0) ! 408: return; ! 409: ! 410: for (prof = &p->p_stats->p_prof; prof; prof = prof->pr_next) { ! 411: off = PC_TO_INDEX(pc,prof); ! 412: cell = (short *)(prof->pr_base + off); ! 413: if (cell >= (short *)prof->pr_base && ! 414: cell < (short*)(prof->pr_size + (int) prof->pr_base)) { ! 415: if (copyin((caddr_t)cell, (caddr_t) &count, sizeof(count)) == 0) { ! 416: count += ticks; ! 417: if(copyout((caddr_t) &count, (caddr_t)cell, sizeof(count)) == 0) ! 418: return; ! 419: } ! 420: p->p_stats->p_prof.pr_scale = 0; ! 421: stopprofclock(p); ! 422: break; ! 423: } ! 424: } ! 425: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.