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