subr_prof.c revision 1.50 1 1.50 ryo /* $NetBSD: subr_prof.c,v 1.50 2021/08/14 17:51:20 ryo Exp $ */
2 1.3 cgd
3 1.1 cgd /*-
4 1.1 cgd * Copyright (c) 1982, 1986, 1993
5 1.1 cgd * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * Redistribution and use in source and binary forms, with or without
8 1.1 cgd * modification, are permitted provided that the following conditions
9 1.1 cgd * are met:
10 1.1 cgd * 1. Redistributions of source code must retain the above copyright
11 1.1 cgd * notice, this list of conditions and the following disclaimer.
12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 cgd * notice, this list of conditions and the following disclaimer in the
14 1.1 cgd * documentation and/or other materials provided with the distribution.
15 1.28 agc * 3. Neither the name of the University nor the names of its contributors
16 1.1 cgd * may be used to endorse or promote products derived from this software
17 1.1 cgd * without specific prior written permission.
18 1.1 cgd *
19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 cgd * SUCH DAMAGE.
30 1.1 cgd *
31 1.17 fvdl * @(#)subr_prof.c 8.4 (Berkeley) 2/14/95
32 1.1 cgd */
33 1.25 lukem
34 1.25 lukem #include <sys/cdefs.h>
35 1.50 ryo __KERNEL_RCSID(0, "$NetBSD: subr_prof.c,v 1.50 2021/08/14 17:51:20 ryo Exp $");
36 1.48 maxv
37 1.48 maxv #ifdef _KERNEL_OPT
38 1.48 maxv #include "opt_gprof.h"
39 1.50 ryo #include "opt_multiprocessor.h"
40 1.48 maxv #endif
41 1.1 cgd
42 1.1 cgd #include <sys/param.h>
43 1.1 cgd #include <sys/systm.h>
44 1.1 cgd #include <sys/kernel.h>
45 1.1 cgd #include <sys/proc.h>
46 1.4 cgd #include <sys/mount.h>
47 1.4 cgd #include <sys/syscallargs.h>
48 1.16 jonathan #include <sys/sysctl.h>
49 1.4 cgd
50 1.42 ad #include <sys/cpu.h>
51 1.9 christos
52 1.1 cgd #ifdef GPROF
53 1.1 cgd #include <sys/malloc.h>
54 1.1 cgd #include <sys/gmon.h>
55 1.50 ryo #include <sys/xcall.h>
56 1.27 thorpej
57 1.27 thorpej MALLOC_DEFINE(M_GPROF, "gprof", "kernel profiling buffer");
58 1.1 cgd
59 1.50 ryo static int sysctl_kern_profiling(SYSCTLFN_ARGS);
60 1.50 ryo #ifdef MULTIPROCESSOR
61 1.50 ryo void _gmonparam_merge(struct gmonparam *, struct gmonparam *);
62 1.50 ryo #endif
63 1.50 ryo
64 1.1 cgd /*
65 1.1 cgd * Froms is actually a bunch of unsigned shorts indexing tos
66 1.1 cgd */
67 1.37 christos struct gmonparam _gmonparam = { .state = GMON_PROF_OFF };
68 1.1 cgd
69 1.15 gwr /* Actual start of the kernel text segment. */
70 1.15 gwr extern char kernel_text[];
71 1.15 gwr
72 1.1 cgd extern char etext[];
73 1.1 cgd
74 1.9 christos
75 1.9 christos void
76 1.32 thorpej kmstartup(void)
77 1.1 cgd {
78 1.1 cgd char *cp;
79 1.1 cgd struct gmonparam *p = &_gmonparam;
80 1.50 ryo unsigned long size;
81 1.1 cgd /*
82 1.1 cgd * Round lowpc and highpc to multiples of the density we're using
83 1.1 cgd * so the rest of the scaling (here and in gprof) stays in ints.
84 1.1 cgd */
85 1.34 christos p->lowpc = rounddown(((u_long)kernel_text),
86 1.15 gwr HISTFRACTION * sizeof(HISTCOUNTER));
87 1.34 christos p->highpc = roundup((u_long)etext,
88 1.15 gwr HISTFRACTION * sizeof(HISTCOUNTER));
89 1.1 cgd p->textsize = p->highpc - p->lowpc;
90 1.14 christos printf("Profiling kernel, textsize=%ld [%lx..%lx]\n",
91 1.1 cgd p->textsize, p->lowpc, p->highpc);
92 1.1 cgd p->kcountsize = p->textsize / HISTFRACTION;
93 1.1 cgd p->hashfraction = HASHFRACTION;
94 1.1 cgd p->fromssize = p->textsize / HASHFRACTION;
95 1.1 cgd p->tolimit = p->textsize * ARCDENSITY / 100;
96 1.1 cgd if (p->tolimit < MINARCS)
97 1.1 cgd p->tolimit = MINARCS;
98 1.1 cgd else if (p->tolimit > MAXARCS)
99 1.1 cgd p->tolimit = MAXARCS;
100 1.1 cgd p->tossize = p->tolimit * sizeof(struct tostruct);
101 1.50 ryo
102 1.50 ryo size = p->kcountsize + p->fromssize + p->tossize;
103 1.50 ryo #ifdef MULTIPROCESSOR
104 1.50 ryo CPU_INFO_ITERATOR cii;
105 1.50 ryo struct cpu_info *ci;
106 1.50 ryo for (CPU_INFO_FOREACH(cii, ci)) {
107 1.50 ryo p = malloc(sizeof(struct gmonparam) + size, M_GPROF,
108 1.50 ryo M_NOWAIT | M_ZERO);
109 1.50 ryo if (p == NULL) {
110 1.50 ryo printf("No memory for profiling on %s\n",
111 1.50 ryo cpu_name(ci));
112 1.50 ryo /* cannot profile on this cpu */
113 1.50 ryo continue;
114 1.50 ryo }
115 1.50 ryo memcpy(p, &_gmonparam, sizeof(_gmonparam));
116 1.50 ryo ci->ci_gmon = p;
117 1.50 ryo
118 1.50 ryo /*
119 1.50 ryo * To allow profiling to be controlled only by the global
120 1.50 ryo * _gmonparam.state, set the default value for each CPU to
121 1.50 ryo * GMON_PROF_ON. If _gmonparam.state is not ON, mcount will
122 1.50 ryo * not be executed.
123 1.50 ryo * This is For compatibility of the kgmon(8) kmem interface.
124 1.50 ryo */
125 1.50 ryo p->state = GMON_PROF_ON;
126 1.50 ryo
127 1.50 ryo cp = (char *)(p + 1);
128 1.50 ryo p->tos = (struct tostruct *)cp;
129 1.50 ryo p->kcount = (u_short *)(cp + p->tossize);
130 1.50 ryo p->froms = (u_short *)(cp + p->tossize + p->kcountsize);
131 1.50 ryo }
132 1.50 ryo
133 1.50 ryo sysctl_createv(NULL, 0, NULL, NULL,
134 1.50 ryo 0, CTLTYPE_NODE, "percpu",
135 1.50 ryo SYSCTL_DESCR("per cpu profiling information"),
136 1.50 ryo NULL, 0, NULL, 0,
137 1.50 ryo CTL_KERN, KERN_PROF, GPROF_PERCPU, CTL_EOL);
138 1.50 ryo
139 1.50 ryo for (CPU_INFO_FOREACH(cii, ci)) {
140 1.50 ryo if (ci->ci_gmon == NULL)
141 1.50 ryo continue;
142 1.50 ryo
143 1.50 ryo sysctl_createv(NULL, 0, NULL, NULL,
144 1.50 ryo 0, CTLTYPE_NODE, cpu_name(ci),
145 1.50 ryo NULL,
146 1.50 ryo NULL, 0, NULL, 0,
147 1.50 ryo CTL_KERN, KERN_PROF, GPROF_PERCPU, cpu_index(ci), CTL_EOL);
148 1.50 ryo
149 1.50 ryo sysctl_createv(NULL, 0, NULL, NULL,
150 1.50 ryo CTLFLAG_READWRITE, CTLTYPE_INT, "state",
151 1.50 ryo SYSCTL_DESCR("Profiling state"),
152 1.50 ryo sysctl_kern_profiling, 0, (void *)ci, 0,
153 1.50 ryo CTL_KERN, KERN_PROF, GPROF_PERCPU, cpu_index(ci),
154 1.50 ryo GPROF_STATE, CTL_EOL);
155 1.50 ryo sysctl_createv(NULL, 0, NULL, NULL,
156 1.50 ryo CTLFLAG_READWRITE, CTLTYPE_STRUCT, "count",
157 1.50 ryo SYSCTL_DESCR("Array of statistical program counters"),
158 1.50 ryo sysctl_kern_profiling, 0, (void *)ci, 0,
159 1.50 ryo CTL_KERN, KERN_PROF, GPROF_PERCPU, cpu_index(ci),
160 1.50 ryo GPROF_COUNT, CTL_EOL);
161 1.50 ryo sysctl_createv(NULL, 0, NULL, NULL,
162 1.50 ryo CTLFLAG_READWRITE, CTLTYPE_STRUCT, "froms",
163 1.50 ryo SYSCTL_DESCR("Array indexed by program counter of "
164 1.50 ryo "call-from points"),
165 1.50 ryo sysctl_kern_profiling, 0, (void *)ci, 0,
166 1.50 ryo CTL_KERN, KERN_PROF, GPROF_PERCPU, cpu_index(ci),
167 1.50 ryo GPROF_FROMS, CTL_EOL);
168 1.50 ryo sysctl_createv(NULL, 0, NULL, NULL,
169 1.50 ryo CTLFLAG_READWRITE, CTLTYPE_STRUCT, "tos",
170 1.50 ryo SYSCTL_DESCR("Array of structures describing "
171 1.50 ryo "destination of calls and their counts"),
172 1.50 ryo sysctl_kern_profiling, 0, (void *)ci, 0,
173 1.50 ryo CTL_KERN, KERN_PROF, GPROF_PERCPU, cpu_index(ci),
174 1.50 ryo GPROF_TOS, CTL_EOL);
175 1.50 ryo sysctl_createv(NULL, 0, NULL, NULL,
176 1.50 ryo CTLFLAG_READWRITE, CTLTYPE_STRUCT, "gmonparam",
177 1.50 ryo SYSCTL_DESCR("Structure giving the sizes of the above "
178 1.50 ryo "arrays"),
179 1.50 ryo sysctl_kern_profiling, 0, (void *)ci, 0,
180 1.50 ryo CTL_KERN, KERN_PROF, GPROF_PERCPU, cpu_index(ci),
181 1.50 ryo GPROF_GMONPARAM, CTL_EOL);
182 1.50 ryo }
183 1.50 ryo
184 1.50 ryo /*
185 1.50 ryo * For minimal compatibility of the kgmon(8) kmem interface,
186 1.50 ryo * the _gmonparam and cpu0:ci_gmon share buffers.
187 1.50 ryo */
188 1.50 ryo p = curcpu()->ci_gmon;
189 1.50 ryo if (p != NULL) {
190 1.50 ryo _gmonparam.tos = p->tos;
191 1.50 ryo _gmonparam.kcount = p->kcount;
192 1.50 ryo _gmonparam.froms = p->froms;
193 1.50 ryo }
194 1.50 ryo #else /* MULTIPROCESSOR */
195 1.50 ryo cp = malloc(size, M_GPROF, M_NOWAIT | M_ZERO);
196 1.1 cgd if (cp == 0) {
197 1.14 christos printf("No memory for profiling.\n");
198 1.1 cgd return;
199 1.1 cgd }
200 1.1 cgd p->tos = (struct tostruct *)cp;
201 1.1 cgd cp += p->tossize;
202 1.1 cgd p->kcount = (u_short *)cp;
203 1.1 cgd cp += p->kcountsize;
204 1.1 cgd p->froms = (u_short *)cp;
205 1.50 ryo #endif /* MULTIPROCESSOR */
206 1.50 ryo }
207 1.50 ryo
208 1.50 ryo #ifdef MULTIPROCESSOR
209 1.50 ryo static void
210 1.50 ryo prof_set_state_xc(void *arg1, void *arg2 __unused)
211 1.50 ryo {
212 1.50 ryo int state = PTRTOUINT64(arg1);
213 1.50 ryo struct gmonparam *gp = curcpu()->ci_gmon;
214 1.50 ryo
215 1.50 ryo if (gp != NULL)
216 1.50 ryo gp->state = state;
217 1.1 cgd }
218 1.50 ryo #endif /* MULTIPROCESSOR */
219 1.1 cgd
220 1.1 cgd /*
221 1.1 cgd * Return kernel profiling information.
222 1.1 cgd */
223 1.29 atatat /*
224 1.29 atatat * sysctl helper routine for kern.profiling subtree. enables/disables
225 1.29 atatat * kernel profiling and gives out copies of the profiling data.
226 1.29 atatat */
227 1.29 atatat static int
228 1.29 atatat sysctl_kern_profiling(SYSCTLFN_ARGS)
229 1.1 cgd {
230 1.50 ryo struct sysctlnode node = *rnode;
231 1.50 ryo struct gmonparam *gp;
232 1.1 cgd int error;
233 1.50 ryo #ifdef MULTIPROCESSOR
234 1.50 ryo CPU_INFO_ITERATOR cii;
235 1.50 ryo struct cpu_info *ci, *target_ci;
236 1.50 ryo uint64_t where;
237 1.50 ryo int state;
238 1.50 ryo bool prof_on, do_merge;
239 1.50 ryo
240 1.50 ryo target_ci = (struct cpu_info *)rnode->sysctl_data;
241 1.50 ryo do_merge = (oldp != NULL) && (target_ci == NULL) &&
242 1.50 ryo ((node.sysctl_num == GPROF_COUNT) ||
243 1.50 ryo (node.sysctl_num == GPROF_FROMS) ||
244 1.50 ryo (node.sysctl_num == GPROF_TOS));
245 1.50 ryo
246 1.50 ryo if (do_merge) {
247 1.50 ryo /* kern.profiling.{count,froms,tos} */
248 1.50 ryo unsigned long size;
249 1.50 ryo char *cp;
250 1.50 ryo
251 1.50 ryo /* allocate temporary gmonparam, and merge results of all CPU */
252 1.50 ryo size = _gmonparam.kcountsize + _gmonparam.fromssize +
253 1.50 ryo _gmonparam.tossize;
254 1.50 ryo gp = malloc(sizeof(struct gmonparam) + size, M_GPROF,
255 1.50 ryo M_NOWAIT | M_ZERO);
256 1.50 ryo if (gp == NULL)
257 1.50 ryo return ENOMEM;
258 1.50 ryo memcpy(gp, &_gmonparam, sizeof(_gmonparam));
259 1.50 ryo cp = (char *)(gp + 1);
260 1.50 ryo gp->tos = (struct tostruct *)cp;
261 1.50 ryo gp->kcount = (u_short *)(cp + gp->tossize);
262 1.50 ryo gp->froms = (u_short *)(cp + gp->tossize + gp->kcountsize);
263 1.50 ryo
264 1.50 ryo for (CPU_INFO_FOREACH(cii, ci)) {
265 1.50 ryo if (ci->ci_gmon == NULL)
266 1.50 ryo continue;
267 1.50 ryo _gmonparam_merge(gp, ci->ci_gmon);
268 1.50 ryo }
269 1.50 ryo } else if (target_ci != NULL) {
270 1.50 ryo /* kern.profiling.percpu.* */
271 1.50 ryo gp = target_ci->ci_gmon;
272 1.50 ryo } else {
273 1.50 ryo /* kern.profiling.{state,gmonparam} */
274 1.50 ryo gp = &_gmonparam;
275 1.50 ryo }
276 1.50 ryo #else /* MULTIPROCESSOR */
277 1.50 ryo gp = &_gmonparam;
278 1.50 ryo #endif
279 1.23 bjh21
280 1.29 atatat switch (node.sysctl_num) {
281 1.1 cgd case GPROF_STATE:
282 1.50 ryo #ifdef MULTIPROCESSOR
283 1.50 ryo /*
284 1.50 ryo * if _gmonparam.state is OFF, the state of each CPU is
285 1.50 ryo * considered to be OFF, even if it is actually ON.
286 1.50 ryo */
287 1.50 ryo if (_gmonparam.state == GMON_PROF_OFF ||
288 1.50 ryo gp->state == GMON_PROF_OFF)
289 1.50 ryo state = GMON_PROF_OFF;
290 1.50 ryo else
291 1.50 ryo state = GMON_PROF_ON;
292 1.50 ryo node.sysctl_data = &state;
293 1.50 ryo #else
294 1.29 atatat node.sysctl_data = &gp->state;
295 1.50 ryo #endif
296 1.29 atatat break;
297 1.1 cgd case GPROF_COUNT:
298 1.29 atatat node.sysctl_data = gp->kcount;
299 1.29 atatat node.sysctl_size = gp->kcountsize;
300 1.29 atatat break;
301 1.1 cgd case GPROF_FROMS:
302 1.29 atatat node.sysctl_data = gp->froms;
303 1.29 atatat node.sysctl_size = gp->fromssize;
304 1.29 atatat break;
305 1.1 cgd case GPROF_TOS:
306 1.29 atatat node.sysctl_data = gp->tos;
307 1.29 atatat node.sysctl_size = gp->tossize;
308 1.29 atatat break;
309 1.1 cgd case GPROF_GMONPARAM:
310 1.29 atatat node.sysctl_data = gp;
311 1.29 atatat node.sysctl_size = sizeof(*gp);
312 1.29 atatat break;
313 1.1 cgd default:
314 1.1 cgd return (EOPNOTSUPP);
315 1.1 cgd }
316 1.29 atatat
317 1.29 atatat error = sysctl_lookup(SYSCTLFN_CALL(&node));
318 1.29 atatat if (error || newp == NULL)
319 1.50 ryo goto done;
320 1.29 atatat
321 1.50 ryo #ifdef MULTIPROCESSOR
322 1.50 ryo switch (node.sysctl_num) {
323 1.50 ryo case GPROF_STATE:
324 1.50 ryo if (target_ci != NULL) {
325 1.50 ryo where = xc_unicast(0, prof_set_state_xc,
326 1.50 ryo UINT64TOPTR(state), NULL, target_ci);
327 1.50 ryo xc_wait(where);
328 1.50 ryo
329 1.50 ryo /* if even one CPU being profiled, enable perfclock. */
330 1.50 ryo prof_on = false;
331 1.50 ryo for (CPU_INFO_FOREACH(cii, ci)) {
332 1.50 ryo if (ci->ci_gmon == NULL)
333 1.50 ryo continue;
334 1.50 ryo if (ci->ci_gmon->state != GMON_PROF_OFF) {
335 1.50 ryo prof_on = true;
336 1.50 ryo break;
337 1.50 ryo }
338 1.50 ryo }
339 1.50 ryo mutex_spin_enter(&proc0.p_stmutex);
340 1.50 ryo if (prof_on)
341 1.50 ryo startprofclock(&proc0);
342 1.50 ryo else
343 1.50 ryo stopprofclock(&proc0);
344 1.50 ryo mutex_spin_exit(&proc0.p_stmutex);
345 1.50 ryo
346 1.50 ryo if (prof_on) {
347 1.50 ryo _gmonparam.state = GMON_PROF_ON;
348 1.50 ryo } else {
349 1.50 ryo _gmonparam.state = GMON_PROF_OFF;
350 1.50 ryo /*
351 1.50 ryo * when _gmonparam.state and all CPU gmon state
352 1.50 ryo * are OFF, all CPU states should be ON so that
353 1.50 ryo * the entire CPUs profiling can be controlled
354 1.50 ryo * by _gmonparam.state only.
355 1.50 ryo */
356 1.50 ryo for (CPU_INFO_FOREACH(cii, ci)) {
357 1.50 ryo if (ci->ci_gmon == NULL)
358 1.50 ryo continue;
359 1.50 ryo ci->ci_gmon->state = GMON_PROF_ON;
360 1.50 ryo }
361 1.50 ryo }
362 1.50 ryo } else {
363 1.50 ryo _gmonparam.state = state;
364 1.50 ryo where = xc_broadcast(0, prof_set_state_xc,
365 1.50 ryo UINT64TOPTR(state), NULL);
366 1.50 ryo xc_wait(where);
367 1.50 ryo
368 1.50 ryo mutex_spin_enter(&proc0.p_stmutex);
369 1.50 ryo if (state == GMON_PROF_OFF)
370 1.50 ryo stopprofclock(&proc0);
371 1.50 ryo else
372 1.50 ryo startprofclock(&proc0);
373 1.50 ryo mutex_spin_exit(&proc0.p_stmutex);
374 1.50 ryo }
375 1.50 ryo break;
376 1.50 ryo case GPROF_COUNT:
377 1.50 ryo /*
378 1.50 ryo * if 'kern.profiling.{count,froms,tos}' is written, the same
379 1.50 ryo * data will be written to 'kern.profiling.percpu.cpuN.xxx'
380 1.50 ryo */
381 1.50 ryo if (target_ci == NULL) {
382 1.50 ryo for (CPU_INFO_FOREACH(cii, ci)) {
383 1.50 ryo if (ci->ci_gmon == NULL)
384 1.50 ryo continue;
385 1.50 ryo memmove(ci->ci_gmon->kcount, gp->kcount,
386 1.50 ryo newlen);
387 1.50 ryo }
388 1.50 ryo }
389 1.50 ryo break;
390 1.50 ryo case GPROF_FROMS:
391 1.50 ryo if (target_ci == NULL) {
392 1.50 ryo for (CPU_INFO_FOREACH(cii, ci)) {
393 1.50 ryo if (ci->ci_gmon == NULL)
394 1.50 ryo continue;
395 1.50 ryo memmove(ci->ci_gmon->froms, gp->froms, newlen);
396 1.50 ryo }
397 1.50 ryo }
398 1.50 ryo break;
399 1.50 ryo case GPROF_TOS:
400 1.50 ryo if (target_ci == NULL) {
401 1.50 ryo for (CPU_INFO_FOREACH(cii, ci)) {
402 1.50 ryo if (ci->ci_gmon == NULL)
403 1.50 ryo continue;
404 1.50 ryo memmove(ci->ci_gmon->tos, gp->tos, newlen);
405 1.50 ryo }
406 1.50 ryo }
407 1.50 ryo break;
408 1.50 ryo }
409 1.50 ryo #else
410 1.29 atatat if (node.sysctl_num == GPROF_STATE) {
411 1.38 ad mutex_spin_enter(&proc0.p_stmutex);
412 1.29 atatat if (gp->state == GMON_PROF_OFF)
413 1.29 atatat stopprofclock(&proc0);
414 1.29 atatat else
415 1.29 atatat startprofclock(&proc0);
416 1.38 ad mutex_spin_exit(&proc0.p_stmutex);
417 1.29 atatat }
418 1.50 ryo #endif
419 1.29 atatat
420 1.50 ryo done:
421 1.50 ryo #ifdef MULTIPROCESSOR
422 1.50 ryo if (do_merge)
423 1.50 ryo free(gp, M_GPROF);
424 1.50 ryo #endif
425 1.50 ryo return error;
426 1.29 atatat }
427 1.29 atatat
428 1.29 atatat SYSCTL_SETUP(sysctl_kern_gprof_setup, "sysctl kern.profiling subtree setup")
429 1.29 atatat {
430 1.29 atatat
431 1.30 atatat sysctl_createv(clog, 0, NULL, NULL,
432 1.30 atatat CTLFLAG_PERMANENT,
433 1.31 atatat CTLTYPE_NODE, "profiling",
434 1.31 atatat SYSCTL_DESCR("Profiling information (available)"),
435 1.29 atatat NULL, 0, NULL, 0,
436 1.29 atatat CTL_KERN, KERN_PROF, CTL_EOL);
437 1.29 atatat
438 1.30 atatat sysctl_createv(clog, 0, NULL, NULL,
439 1.30 atatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
440 1.31 atatat CTLTYPE_INT, "state",
441 1.31 atatat SYSCTL_DESCR("Profiling state"),
442 1.29 atatat sysctl_kern_profiling, 0, NULL, 0,
443 1.29 atatat CTL_KERN, KERN_PROF, GPROF_STATE, CTL_EOL);
444 1.30 atatat sysctl_createv(clog, 0, NULL, NULL,
445 1.30 atatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
446 1.31 atatat CTLTYPE_STRUCT, "count",
447 1.31 atatat SYSCTL_DESCR("Array of statistical program counters"),
448 1.29 atatat sysctl_kern_profiling, 0, NULL, 0,
449 1.29 atatat CTL_KERN, KERN_PROF, GPROF_COUNT, CTL_EOL);
450 1.30 atatat sysctl_createv(clog, 0, NULL, NULL,
451 1.30 atatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
452 1.31 atatat CTLTYPE_STRUCT, "froms",
453 1.31 atatat SYSCTL_DESCR("Array indexed by program counter of "
454 1.31 atatat "call-from points"),
455 1.29 atatat sysctl_kern_profiling, 0, NULL, 0,
456 1.29 atatat CTL_KERN, KERN_PROF, GPROF_FROMS, CTL_EOL);
457 1.30 atatat sysctl_createv(clog, 0, NULL, NULL,
458 1.30 atatat CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
459 1.31 atatat CTLTYPE_STRUCT, "tos",
460 1.31 atatat SYSCTL_DESCR("Array of structures describing "
461 1.31 atatat "destination of calls and their counts"),
462 1.29 atatat sysctl_kern_profiling, 0, NULL, 0,
463 1.29 atatat CTL_KERN, KERN_PROF, GPROF_TOS, CTL_EOL);
464 1.30 atatat sysctl_createv(clog, 0, NULL, NULL,
465 1.30 atatat CTLFLAG_PERMANENT,
466 1.31 atatat CTLTYPE_STRUCT, "gmonparam",
467 1.31 atatat SYSCTL_DESCR("Structure giving the sizes of the above "
468 1.31 atatat "arrays"),
469 1.29 atatat sysctl_kern_profiling, 0, NULL, 0,
470 1.29 atatat CTL_KERN, KERN_PROF, GPROF_GMONPARAM, CTL_EOL);
471 1.1 cgd }
472 1.1 cgd #endif /* GPROF */
473 1.1 cgd
474 1.1 cgd /*
475 1.1 cgd * Profiling system call.
476 1.1 cgd *
477 1.1 cgd * The scale factor is a fixed point number with 16 bits of fraction, so that
478 1.1 cgd * 1.0 is represented as 0x10000. A scale factor of 0 turns off profiling.
479 1.1 cgd */
480 1.1 cgd /* ARGSUSED */
481 1.9 christos int
482 1.43 dsl sys_profil(struct lwp *l, const struct sys_profil_args *uap, register_t *retval)
483 1.6 thorpej {
484 1.43 dsl /* {
485 1.40 drochner syscallarg(char *) samples;
486 1.44 dsl syscallarg(size_t) size;
487 1.44 dsl syscallarg(u_long) offset;
488 1.4 cgd syscallarg(u_int) scale;
489 1.43 dsl } */
490 1.26 thorpej struct proc *p = l->l_proc;
491 1.20 augustss struct uprof *upp;
492 1.1 cgd
493 1.4 cgd if (SCARG(uap, scale) > (1 << 16))
494 1.1 cgd return (EINVAL);
495 1.4 cgd if (SCARG(uap, scale) == 0) {
496 1.38 ad mutex_spin_enter(&p->p_stmutex);
497 1.1 cgd stopprofclock(p);
498 1.38 ad mutex_spin_exit(&p->p_stmutex);
499 1.1 cgd return (0);
500 1.1 cgd }
501 1.1 cgd upp = &p->p_stats->p_prof;
502 1.1 cgd
503 1.1 cgd /* Block profile interrupts while changing state. */
504 1.38 ad mutex_spin_enter(&p->p_stmutex);
505 1.4 cgd upp->pr_off = SCARG(uap, offset);
506 1.4 cgd upp->pr_scale = SCARG(uap, scale);
507 1.4 cgd upp->pr_base = SCARG(uap, samples);
508 1.4 cgd upp->pr_size = SCARG(uap, size);
509 1.1 cgd startprofclock(p);
510 1.38 ad mutex_spin_exit(&p->p_stmutex);
511 1.1 cgd
512 1.1 cgd return (0);
513 1.1 cgd }
514 1.1 cgd
515 1.1 cgd /*
516 1.1 cgd * Scale is a fixed-point number with the binary point 16 bits
517 1.1 cgd * into the value, and is <= 1.0. pc is at most 32 bits, so the
518 1.1 cgd * intermediate result is at most 48 bits.
519 1.1 cgd */
520 1.1 cgd #define PC_TO_INDEX(pc, prof) \
521 1.1 cgd ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
522 1.1 cgd (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
523 1.1 cgd
524 1.1 cgd /*
525 1.1 cgd * Collect user-level profiling statistics; called on a profiling tick,
526 1.1 cgd * when a process is running in user-mode. This routine may be called
527 1.49 thorpej * from an interrupt context. We schedule an AST that will vector us
528 1.49 thorpej * to trap() with a context in which copyin and copyout will work.
529 1.49 thorpej * Trap will then call addupc_task().
530 1.49 thorpej *
531 1.49 thorpej * XXX We could use ufetch/ustore here if the profile buffers were
532 1.49 thorpej * wired.
533 1.1 cgd *
534 1.1 cgd * Note that we may (rarely) not get around to the AST soon enough, and
535 1.1 cgd * lose profile ticks when the next tick overwrites this one, but in this
536 1.1 cgd * case the system is overloaded and the profile is probably already
537 1.1 cgd * inaccurate.
538 1.1 cgd */
539 1.1 cgd void
540 1.38 ad addupc_intr(struct lwp *l, u_long pc)
541 1.1 cgd {
542 1.20 augustss struct uprof *prof;
543 1.38 ad struct proc *p;
544 1.20 augustss u_int i;
545 1.1 cgd
546 1.38 ad p = l->l_proc;
547 1.38 ad
548 1.41 ad KASSERT(mutex_owned(&p->p_stmutex));
549 1.38 ad
550 1.1 cgd prof = &p->p_stats->p_prof;
551 1.1 cgd if (pc < prof->pr_off ||
552 1.1 cgd (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
553 1.1 cgd return; /* out of range; ignore */
554 1.1 cgd
555 1.38 ad mutex_spin_exit(&p->p_stmutex);
556 1.49 thorpej
557 1.49 thorpej /* XXXSMP */
558 1.49 thorpej prof->pr_addr = pc;
559 1.49 thorpej prof->pr_ticks++;
560 1.49 thorpej cpu_need_proftick(l);
561 1.49 thorpej
562 1.38 ad mutex_spin_enter(&p->p_stmutex);
563 1.1 cgd }
564 1.1 cgd
565 1.1 cgd /*
566 1.1 cgd * Much like before, but we can afford to take faults here. If the
567 1.1 cgd * update fails, we simply turn off profiling.
568 1.1 cgd */
569 1.1 cgd void
570 1.38 ad addupc_task(struct lwp *l, u_long pc, u_int ticks)
571 1.1 cgd {
572 1.20 augustss struct uprof *prof;
573 1.38 ad struct proc *p;
574 1.39 christos void *addr;
575 1.38 ad int error;
576 1.20 augustss u_int i;
577 1.1 cgd u_short v;
578 1.1 cgd
579 1.38 ad p = l->l_proc;
580 1.38 ad
581 1.38 ad if (ticks == 0)
582 1.1 cgd return;
583 1.1 cgd
584 1.38 ad mutex_spin_enter(&p->p_stmutex);
585 1.1 cgd prof = &p->p_stats->p_prof;
586 1.38 ad
587 1.38 ad /* Testing P_PROFIL may be unnecessary, but is certainly safe. */
588 1.38 ad if ((p->p_stflag & PST_PROFIL) == 0 || pc < prof->pr_off ||
589 1.38 ad (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) {
590 1.38 ad mutex_spin_exit(&p->p_stmutex);
591 1.1 cgd return;
592 1.38 ad }
593 1.1 cgd
594 1.40 drochner addr = prof->pr_base + i;
595 1.38 ad mutex_spin_exit(&p->p_stmutex);
596 1.39 christos if ((error = copyin(addr, (void *)&v, sizeof(v))) == 0) {
597 1.1 cgd v += ticks;
598 1.39 christos error = copyout((void *)&v, addr, sizeof(v));
599 1.38 ad }
600 1.38 ad if (error != 0) {
601 1.38 ad mutex_spin_enter(&p->p_stmutex);
602 1.38 ad stopprofclock(p);
603 1.38 ad mutex_spin_exit(&p->p_stmutex);
604 1.1 cgd }
605 1.1 cgd }
606