|
|
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.