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