Annotation of sys/kern/subr_prof.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: subr_prof.c,v 1.17 2007/03/15 10:22:30 art Exp $ */
2: /* $NetBSD: subr_prof.c,v 1.12 1996/04/22 01:38:50 christos Exp $ */
3:
4: /*-
5: * Copyright (c) 1982, 1986, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the University nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: *
32: * @(#)subr_prof.c 8.3 (Berkeley) 9/23/93
33: */
34:
35: #include <sys/param.h>
36: #include <sys/systm.h>
37: #include <sys/kernel.h>
38: #include <sys/proc.h>
39: #include <sys/user.h>
40: #include <sys/mount.h>
41: #include <sys/syscallargs.h>
42:
43: #include <machine/cpu.h>
44:
45: #ifdef GPROF
46: #include <sys/malloc.h>
47: #include <sys/gmon.h>
48: #include <uvm/uvm_extern.h>
49:
50: /*
51: * Froms is actually a bunch of unsigned shorts indexing tos
52: */
53: struct gmonparam _gmonparam = { GMON_PROF_OFF };
54:
55: extern char etext[];
56:
57:
58: void
59: kmstartup(void)
60: {
61: char *cp;
62: struct gmonparam *p = &_gmonparam;
63: int size;
64:
65: /*
66: * Round lowpc and highpc to multiples of the density we're using
67: * so the rest of the scaling (here and in gprof) stays in ints.
68: */
69: p->lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
70: p->highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
71: p->textsize = p->highpc - p->lowpc;
72: printf("Profiling kernel, textsize=%ld [%lx..%lx]\n",
73: p->textsize, p->lowpc, p->highpc);
74: p->kcountsize = p->textsize / HISTFRACTION;
75: p->hashfraction = HASHFRACTION;
76: p->fromssize = p->textsize / HASHFRACTION;
77: p->tolimit = p->textsize * ARCDENSITY / 100;
78: if (p->tolimit < MINARCS)
79: p->tolimit = MINARCS;
80: else if (p->tolimit > MAXARCS)
81: p->tolimit = MAXARCS;
82: p->tossize = p->tolimit * sizeof(struct tostruct);
83: size = p->kcountsize + p->fromssize + p->tossize;
84: cp = (char *)uvm_km_zalloc(kernel_map, round_page(size));
85: if (cp == 0) {
86: printf("No memory for profiling.\n");
87: return;
88: }
89: p->tos = (struct tostruct *)cp;
90: cp += p->tossize;
91: p->kcount = (u_short *)cp;
92: cp += p->kcountsize;
93: p->froms = (u_short *)cp;
94: }
95:
96: /*
97: * Return kernel profiling information.
98: */
99: int
100: sysctl_doprof(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
101: size_t newlen)
102: {
103: struct gmonparam *gp = &_gmonparam;
104: int error;
105:
106: /* all sysctl names at this level are terminal */
107: if (namelen != 1)
108: return (ENOTDIR); /* overloaded */
109:
110: switch (name[0]) {
111: case GPROF_STATE:
112: error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
113: if (error)
114: return (error);
115: if (gp->state == GMON_PROF_OFF)
116: stopprofclock(&proc0);
117: else
118: startprofclock(&proc0);
119: return (0);
120: case GPROF_COUNT:
121: return (sysctl_struct(oldp, oldlenp, newp, newlen,
122: gp->kcount, gp->kcountsize));
123: case GPROF_FROMS:
124: return (sysctl_struct(oldp, oldlenp, newp, newlen,
125: gp->froms, gp->fromssize));
126: case GPROF_TOS:
127: return (sysctl_struct(oldp, oldlenp, newp, newlen,
128: gp->tos, gp->tossize));
129: case GPROF_GMONPARAM:
130: return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
131: default:
132: return (EOPNOTSUPP);
133: }
134: /* NOTREACHED */
135: }
136: #endif /* GPROF */
137:
138: /*
139: * Profiling system call.
140: *
141: * The scale factor is a fixed point number with 16 bits of fraction, so that
142: * 1.0 is represented as 0x10000. A scale factor of 0 turns off profiling.
143: */
144: /* ARGSUSED */
145: int
146: sys_profil(struct proc *p, void *v, register_t *retval)
147: {
148: struct sys_profil_args /* {
149: syscallarg(caddr_t) samples;
150: syscallarg(size_t) size;
151: syscallarg(u_long) offset;
152: syscallarg(u_int) scale;
153: } */ *uap = v;
154: struct uprof *upp;
155: int s;
156:
157: if (SCARG(uap, scale) > (1 << 16))
158: return (EINVAL);
159: if (SCARG(uap, scale) == 0) {
160: stopprofclock(p);
161: return (0);
162: }
163: upp = &p->p_stats->p_prof;
164:
165: /* Block profile interrupts while changing state. */
166: s = splstatclock();
167: upp->pr_off = SCARG(uap, offset);
168: upp->pr_scale = SCARG(uap, scale);
169: upp->pr_base = (caddr_t)SCARG(uap, samples);
170: upp->pr_size = SCARG(uap, size);
171: startprofclock(p);
172: splx(s);
173:
174: return (0);
175: }
176:
177: /*
178: * Scale is a fixed-point number with the binary point 16 bits
179: * into the value, and is <= 1.0. pc is at most 32 bits, so the
180: * intermediate result is at most 48 bits.
181: */
182: #define PC_TO_INDEX(pc, prof) \
183: ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
184: (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
185:
186: /*
187: * Collect user-level profiling statistics; called on a profiling tick,
188: * when a process is running in user-mode. This routine may be called
189: * from an interrupt context. Schedule an AST that will vector us to
190: * trap() with a context in which copyin and copyout will work.
191: * Trap will then call addupc_task().
192: */
193: void
194: addupc_intr(struct proc *p, u_long pc)
195: {
196: struct uprof *prof;
197:
198: prof = &p->p_stats->p_prof;
199: if (pc < prof->pr_off || PC_TO_INDEX(pc, prof) >= prof->pr_size)
200: return; /* out of range; ignore */
201:
202: prof->pr_addr = pc;
203: prof->pr_ticks++;
204: atomic_setbits_int(&p->p_flag, P_OWEUPC);
205: need_proftick(p);
206: }
207:
208:
209: /*
210: * Much like before, but we can afford to take faults here. If the
211: * update fails, we simply turn off profiling.
212: */
213: void
214: addupc_task(struct proc *p, u_long pc, u_int nticks)
215: {
216: struct uprof *prof;
217: caddr_t addr;
218: u_int i;
219: u_short v;
220:
221: /* Testing P_PROFIL may be unnecessary, but is certainly safe. */
222: if ((p->p_flag & P_PROFIL) == 0 || nticks == 0)
223: return;
224:
225: prof = &p->p_stats->p_prof;
226: if (pc < prof->pr_off ||
227: (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
228: return;
229:
230: addr = prof->pr_base + i;
231: if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
232: v += nticks;
233: if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
234: return;
235: }
236: stopprofclock(p);
237: }
CVSweb