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