subr_prof.c revision 50477
1295016Sjkim/*- 2280304Sjkim * Copyright (c) 1982, 1986, 1993 3280304Sjkim * The Regents of the University of California. All rights reserved. 4280304Sjkim * 568651Skris * Redistribution and use in source and binary forms, with or without 668651Skris * modification, are permitted provided that the following conditions 768651Skris * are met: 868651Skris * 1. Redistributions of source code must retain the above copyright 968651Skris * notice, this list of conditions and the following disclaimer. 1068651Skris * 2. Redistributions in binary form must reproduce the above copyright 1168651Skris * notice, this list of conditions and the following disclaimer in the 1268651Skris * documentation and/or other materials provided with the distribution. 1368651Skris * 3. All advertising materials mentioning features or use of this software 14280304Sjkim * must display the following acknowledgement: 1568651Skris * This product includes software developed by the University of 1668651Skris * California, Berkeley and its contributors. 1768651Skris * 4. Neither the name of the University nor the names of its contributors 1868651Skris * may be used to endorse or promote products derived from this software 1968651Skris * without specific prior written permission. 2068651Skris * 2168651Skris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2268651Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2368651Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2468651Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2568651Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2668651Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2768651Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2868651Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2968651Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3068651Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3168651Skris * SUCH DAMAGE. 3268651Skris * 3368651Skris * @(#)subr_prof.c 8.3 (Berkeley) 9/23/93 3468651Skris * $FreeBSD: head/sys/kern/subr_prof.c 50477 1999-08-28 01:08:13Z peter $ 3568651Skris */ 3668651Skris 3768651Skris#include <sys/param.h> 3868651Skris#include <sys/systm.h> 3968651Skris#include <sys/sysproto.h> 4068651Skris#include <sys/kernel.h> 4168651Skris#include <sys/proc.h> 4268651Skris#include <sys/resourcevar.h> 4368651Skris#include <sys/sysctl.h> 4468651Skris 4568651Skris#include <machine/cpu.h> 4668651Skris 4768651Skris#ifdef GPROF 4868651Skris#include <sys/malloc.h> 4968651Skris#include <sys/gmon.h> 5068651Skris#undef MCOUNT 5168651Skris 5268651Skrisstatic MALLOC_DEFINE(M_GPROF, "gprof", "kernel profiling buffer"); 5368651Skris 5468651Skrisstatic void kmstartup __P((void *)); 5568651SkrisSYSINIT(kmem, SI_SUB_KPROF, SI_ORDER_FIRST, kmstartup, NULL) 5668651Skris 5768651Skrisstruct gmonparam _gmonparam = { GMON_PROF_OFF }; 5868651Skris 5968651Skris#ifdef GUPROF 60280304Sjkim#include <machine/asmacros.h> 61280304Sjkim 62280304Sjkimvoid 63280304Sjkimnullfunc_loop_profiled() 64280304Sjkim{ 65276864Sjkim int i; 66280304Sjkim 67238405Sjkim for (i = 0; i < CALIB_SCALE; i++) 68238405Sjkim nullfunc_profiled(); 6968651Skris} 7068651Skris 7168651Skris#define nullfunc_loop_profiled_end nullfunc_profiled /* XXX */ 7268651Skris 7368651Skrisvoid 7468651Skrisnullfunc_profiled() 75280304Sjkim{ 76280304Sjkim} 77280304Sjkim#endif /* GUPROF */ 7868651Skris 7968651Skrisstatic void 80280304Sjkimkmstartup(dummy) 81280304Sjkim void *dummy; 82280304Sjkim{ 83280304Sjkim char *cp; 84280304Sjkim struct gmonparam *p = &_gmonparam; 85280304Sjkim#ifdef GUPROF 86280304Sjkim int cputime_overhead; 87238405Sjkim int empty_loop_time; 88238405Sjkim int i; 89238405Sjkim int mcount_overhead; 90280304Sjkim int mexitcount_overhead; 91280304Sjkim int nullfunc_loop_overhead; 92280304Sjkim int nullfunc_loop_profiled_time; 93238405Sjkim uintfptr_t tmp_addr; 9468651Skris#endif 9568651Skris 96280304Sjkim /* 9768651Skris * Round lowpc and highpc to multiples of the density we're using 98109998Smarkm * so the rest of the scaling (here and in gprof) stays in ints. 9968651Skris */ 10068651Skris p->lowpc = ROUNDDOWN((u_long)btext, HISTFRACTION * sizeof(HISTCOUNTER)); 10168651Skris p->highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER)); 102280304Sjkim p->textsize = p->highpc - p->lowpc; 10368651Skris printf("Profiling kernel, textsize=%lu [%x..%x]\n", 10468651Skris p->textsize, p->lowpc, p->highpc); 10568651Skris p->kcountsize = p->textsize / HISTFRACTION; 106109998Smarkm p->hashfraction = HASHFRACTION; 107280304Sjkim p->fromssize = p->textsize / HASHFRACTION; 108109998Smarkm p->tolimit = p->textsize * ARCDENSITY / 100; 109160814Ssimon if (p->tolimit < MINARCS) 110280304Sjkim p->tolimit = MINARCS; 111280304Sjkim else if (p->tolimit > MAXARCS) 112238405Sjkim p->tolimit = MAXARCS; 11368651Skris p->tossize = p->tolimit * sizeof(struct tostruct); 11468651Skris cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize, 115280304Sjkim M_GPROF, M_NOWAIT); 116280304Sjkim if (cp == 0) { 117280304Sjkim printf("No memory for profiling.\n"); 118280304Sjkim return; 119280304Sjkim } 12068651Skris bzero(cp, p->kcountsize + p->tossize + p->fromssize); 121280304Sjkim p->tos = (struct tostruct *)cp; 122280304Sjkim cp += p->tossize; 123280304Sjkim p->kcount = (HISTCOUNTER *)cp; 124280304Sjkim cp += p->kcountsize; 125280304Sjkim p->froms = (u_short *)cp; 126280304Sjkim 127280304Sjkim#ifdef GUPROF 128280304Sjkim /* Initialize pointers to overhead counters. */ 129280304Sjkim p->cputime_count = &KCOUNT(p, PC_TO_I(p, cputime)); 130280304Sjkim p->mcount_count = &KCOUNT(p, PC_TO_I(p, mcount)); 131280304Sjkim p->mexitcount_count = &KCOUNT(p, PC_TO_I(p, mexitcount)); 132280304Sjkim 13368651Skris /* 13468651Skris * Disable interrupts to avoid interference while we calibrate 135280304Sjkim * things. 136280304Sjkim */ 137280304Sjkim disable_intr(); 13868651Skris 139280304Sjkim /* 140280304Sjkim * Determine overheads. 141280304Sjkim * XXX this needs to be repeated for each useful timer/counter. 142280304Sjkim */ 143280304Sjkim cputime_overhead = 0; 144280304Sjkim startguprof(p); 145280304Sjkim for (i = 0; i < CALIB_SCALE; i++) 146280304Sjkim cputime_overhead += cputime(); 147280304Sjkim 148280304Sjkim empty_loop(); 149280304Sjkim startguprof(p); 150280304Sjkim empty_loop(); 151280304Sjkim empty_loop_time = cputime(); 152280304Sjkim 153280304Sjkim nullfunc_loop_profiled(); 154280304Sjkim 155280304Sjkim /* 156280304Sjkim * Start profiling. There won't be any normal function calls since 157280304Sjkim * interrupts are disabled, but we will call the profiling routines 158280304Sjkim * directly to determine their overheads. 159280304Sjkim */ 160280304Sjkim p->state = GMON_PROF_HIRES; 161280304Sjkim 162280304Sjkim startguprof(p); 163280304Sjkim nullfunc_loop_profiled(); 16468651Skris 165280304Sjkim startguprof(p); 166280304Sjkim for (i = 0; i < CALIB_SCALE; i++) 167280304Sjkim#if defined(__i386__) && __GNUC__ >= 2 16868651Skris __asm("pushl %0; call __mcount; popl %%ecx" 16968651Skris : 170109998Smarkm : "i" (profil) 171280304Sjkim : "ax", "bx", "cx", "dx", "memory"); 172280304Sjkim#else 173280304Sjkim#error 174280304Sjkim#endif 175280304Sjkim mcount_overhead = KCOUNT(p, PC_TO_I(p, profil)); 17668651Skris 177280304Sjkim startguprof(p); 178280304Sjkim for (i = 0; i < CALIB_SCALE; i++) 179280304Sjkim#if defined(__i386__) && __GNUC__ >= 2 180280304Sjkim __asm("call " __XSTRING(HIDENAME(mexitcount)) "; 1:" 181280304Sjkim : : : "ax", "bx", "cx", "dx", "memory"); 182280304Sjkim __asm("movl $1b,%0" : "=rm" (tmp_addr)); 183280304Sjkim#else 184280304Sjkim#error 185280304Sjkim#endif 186280304Sjkim mexitcount_overhead = KCOUNT(p, PC_TO_I(p, tmp_addr)); 187280304Sjkim 188280304Sjkim p->state = GMON_PROF_OFF; 189280304Sjkim stopguprof(p); 190280304Sjkim 191280304Sjkim enable_intr(); 192280304Sjkim 193280304Sjkim nullfunc_loop_profiled_time = 0; 194280304Sjkim for (tmp_addr = (uintfptr_t)nullfunc_loop_profiled; 195280304Sjkim tmp_addr < (uintfptr_t)nullfunc_loop_profiled_end; 196280304Sjkim tmp_addr += HISTFRACTION * sizeof(HISTCOUNTER)) 197280304Sjkim nullfunc_loop_profiled_time += KCOUNT(p, PC_TO_I(p, tmp_addr)); 198280304Sjkim#define CALIB_DOSCALE(count) (((count) + CALIB_SCALE / 3) / CALIB_SCALE) 199280304Sjkim#define c2n(count, freq) ((int)((count) * 1000000000LL / freq)) 200280304Sjkim printf("cputime %d, empty_loop %d, nullfunc_loop_profiled %d, mcount %d, mexitcount %d\n", 201280304Sjkim CALIB_DOSCALE(c2n(cputime_overhead, p->profrate)), 202280304Sjkim CALIB_DOSCALE(c2n(empty_loop_time, p->profrate)), 203280304Sjkim CALIB_DOSCALE(c2n(nullfunc_loop_profiled_time, p->profrate)), 204280304Sjkim CALIB_DOSCALE(c2n(mcount_overhead, p->profrate)), 205109998Smarkm CALIB_DOSCALE(c2n(mexitcount_overhead, p->profrate))); 20668651Skris cputime_overhead -= empty_loop_time; 20768651Skris mcount_overhead -= empty_loop_time; 208280304Sjkim mexitcount_overhead -= empty_loop_time; 209280304Sjkim 210280304Sjkim /*- 211280304Sjkim * Profiling overheads are determined by the times between the 212280304Sjkim * following events: 213280304Sjkim * MC1: mcount() is called 214280304Sjkim * MC2: cputime() (called from mcount()) latches the timer 215280304Sjkim * MC3: mcount() completes 216280304Sjkim * ME1: mexitcount() is called 217280304Sjkim * ME2: cputime() (called from mexitcount()) latches the timer 218280304Sjkim * ME3: mexitcount() completes. 219280304Sjkim * The times between the events vary slightly depending on instruction 220280304Sjkim * combination and cache misses, etc. Attempt to determine the 221280304Sjkim * minimum times. These can be subtracted from the profiling times 222280304Sjkim * without much risk of reducing the profiling times below what they 223280304Sjkim * would be when profiling is not configured. Abbreviate: 224280304Sjkim * ab = minimum time between MC1 and MC3 225280304Sjkim * a = minumum time between MC1 and MC2 226280304Sjkim * b = minimum time between MC2 and MC3 227280304Sjkim * cd = minimum time between ME1 and ME3 228280304Sjkim * c = minimum time between ME1 and ME2 22968651Skris * d = minimum time between ME2 and ME3. 23068651Skris * These satisfy the relations: 231280304Sjkim * ab <= mcount_overhead (just measured) 232280304Sjkim * a + b <= ab 23368651Skris * cd <= mexitcount_overhead (just measured) 234280304Sjkim * c + d <= cd 235280304Sjkim * a + d <= nullfunc_loop_profiled_time (just measured) 236280304Sjkim * a >= 0, b >= 0, c >= 0, d >= 0. 237280304Sjkim * Assume that ab and cd are equal to the minimums. 238280304Sjkim */ 239280304Sjkim p->cputime_overhead = CALIB_DOSCALE(cputime_overhead); 240280304Sjkim p->mcount_overhead = CALIB_DOSCALE(mcount_overhead - cputime_overhead); 241280304Sjkim p->mexitcount_overhead = CALIB_DOSCALE(mexitcount_overhead 242280304Sjkim - cputime_overhead); 243280304Sjkim nullfunc_loop_overhead = nullfunc_loop_profiled_time - empty_loop_time; 244280304Sjkim p->mexitcount_post_overhead = CALIB_DOSCALE((mcount_overhead 245280304Sjkim - nullfunc_loop_overhead) 246280304Sjkim / 4); 247280304Sjkim p->mexitcount_pre_overhead = p->mexitcount_overhead 248280304Sjkim + p->cputime_overhead 249280304Sjkim - p->mexitcount_post_overhead; 250280304Sjkim p->mcount_pre_overhead = CALIB_DOSCALE(nullfunc_loop_overhead) 251280304Sjkim - p->mexitcount_post_overhead; 252280304Sjkim p->mcount_post_overhead = p->mcount_overhead 253280304Sjkim + p->cputime_overhead 254280304Sjkim - p->mcount_pre_overhead; 25568651Skris printf( 25668651Skris"Profiling overheads: mcount: %d+%d, %d+%d; mexitcount: %d+%d, %d+%d nsec\n", 257280304Sjkim c2n(p->cputime_overhead, p->profrate), 258280304Sjkim c2n(p->mcount_overhead, p->profrate), 259280304Sjkim c2n(p->mcount_pre_overhead, p->profrate), 260280304Sjkim c2n(p->mcount_post_overhead, p->profrate), 261280304Sjkim c2n(p->cputime_overhead, p->profrate), 262280304Sjkim c2n(p->mexitcount_overhead, p->profrate), 26368651Skris c2n(p->mexitcount_pre_overhead, p->profrate), 264280304Sjkim c2n(p->mexitcount_post_overhead, p->profrate)); 265280304Sjkim printf( 266280304Sjkim"Profiling overheads: mcount: %d+%d, %d+%d; mexitcount: %d+%d, %d+%d cycles\n", 267280304Sjkim p->cputime_overhead, p->mcount_overhead, 268280304Sjkim p->mcount_pre_overhead, p->mcount_post_overhead, 269280304Sjkim p->cputime_overhead, p->mexitcount_overhead, 270280304Sjkim p->mexitcount_pre_overhead, p->mexitcount_post_overhead); 271280304Sjkim#endif /* GUPROF */ 272280304Sjkim} 273280304Sjkim 274280304Sjkim/* 275280304Sjkim * Return kernel profiling information. 276280304Sjkim */ 277280304Sjkimstatic int 278280304Sjkimsysctl_kern_prof SYSCTL_HANDLER_ARGS 279280304Sjkim{ 280280304Sjkim int *name = (int *) arg1; 281280304Sjkim u_int namelen = arg2; 282280304Sjkim struct gmonparam *gp = &_gmonparam; 283280304Sjkim int error; 284280304Sjkim int state; 28568651Skris 286160814Ssimon /* all sysctl names at this level are terminal */ 287280304Sjkim if (namelen != 1) 288280304Sjkim return (ENOTDIR); /* overloaded */ 289280304Sjkim 290160814Ssimon switch (name[0]) { 291280304Sjkim case GPROF_STATE: 292280304Sjkim state = gp->state; 293280304Sjkim error = sysctl_handle_int(oidp, &state, 0, req); 294280304Sjkim if (error) 295280304Sjkim return (error); 296280304Sjkim if (!req->newptr) 297280304Sjkim return (0); 298280304Sjkim if (state == GMON_PROF_OFF) { 299280304Sjkim gp->state = state; 300280304Sjkim stopprofclock(&proc0); 301280304Sjkim stopguprof(gp); 302280304Sjkim } else if (state == GMON_PROF_ON) { 303280304Sjkim gp->state = GMON_PROF_OFF; 304280304Sjkim stopguprof(gp); 305280304Sjkim gp->profrate = profhz; 306280304Sjkim startprofclock(&proc0); 307280304Sjkim gp->state = state; 308280304Sjkim#ifdef GUPROF 309280304Sjkim } else if (state == GMON_PROF_HIRES) { 310280304Sjkim gp->state = GMON_PROF_OFF; 311280304Sjkim stopprofclock(&proc0); 312280304Sjkim startguprof(gp); 313280304Sjkim gp->state = state; 314280304Sjkim#endif 315280304Sjkim } else if (state != gp->state) 316280304Sjkim return (EINVAL); 317280304Sjkim return (0); 318280304Sjkim case GPROF_COUNT: 319280304Sjkim return (sysctl_handle_opaque(oidp, 320280304Sjkim gp->kcount, gp->kcountsize, req)); 321280304Sjkim case GPROF_FROMS: 322280304Sjkim return (sysctl_handle_opaque(oidp, 323280304Sjkim gp->froms, gp->fromssize, req)); 324280304Sjkim case GPROF_TOS: 325280304Sjkim return (sysctl_handle_opaque(oidp, 326160814Ssimon gp->tos, gp->tossize, req)); 327280304Sjkim case GPROF_GMONPARAM: 328280304Sjkim return (sysctl_handle_opaque(oidp, gp, sizeof *gp, req)); 329160814Ssimon default: 330280304Sjkim return (EOPNOTSUPP); 331280304Sjkim } 332280304Sjkim /* NOTREACHED */ 333280304Sjkim} 334280304Sjkim 335280304SjkimSYSCTL_NODE(_kern, KERN_PROF, prof, CTLFLAG_RW, sysctl_kern_prof, ""); 336280304Sjkim#endif /* GPROF */ 337280304Sjkim 338280304Sjkim/* 339280304Sjkim * Profiling system call. 340280304Sjkim * 341280304Sjkim * The scale factor is a fixed point number with 16 bits of fraction, so that 342280304Sjkim * 1.0 is represented as 0x10000. A scale factor of 0 turns off profiling. 343280304Sjkim */ 344280304Sjkim#ifndef _SYS_SYSPROTO_H_ 345160814Ssimonstruct profil_args { 346280304Sjkim caddr_t samples; 347280304Sjkim size_t size; 348280304Sjkim size_t offset; 349280304Sjkim u_int scale; 350280304Sjkim}; 351280304Sjkim#endif 352280304Sjkim/* ARGSUSED */ 353205128Ssimonint 354109998Smarkmprofil(p, uap) 355280304Sjkim struct proc *p; 356280304Sjkim register struct profil_args *uap; 357280304Sjkim{ 358109998Smarkm register struct uprof *upp; 359280304Sjkim int s; 360280304Sjkim 361280304Sjkim if (uap->scale > (1 << 16)) 362280304Sjkim return (EINVAL); 363280304Sjkim if (uap->scale == 0) { 364280304Sjkim stopprofclock(p); 365280304Sjkim return (0); 366280304Sjkim } 367280304Sjkim upp = &p->p_stats->p_prof; 368280304Sjkim 369280304Sjkim /* Block profile interrupts while changing state. */ 370280304Sjkim s = splstatclock(); 371280304Sjkim upp->pr_off = uap->offset; 372280304Sjkim upp->pr_scale = uap->scale; 373280304Sjkim upp->pr_base = uap->samples; 374280304Sjkim upp->pr_size = uap->size; 375280304Sjkim startprofclock(p); 376280304Sjkim splx(s); 377280304Sjkim 378280304Sjkim return (0); 379280304Sjkim} 380280304Sjkim 381280304Sjkim/* 38268651Skris * Scale is a fixed-point number with the binary point 16 bits 383280304Sjkim * into the value, and is <= 1.0. pc is at most 32 bits, so the 384280304Sjkim * intermediate result is at most 48 bits. 385238405Sjkim */ 386238405Sjkim#define PC_TO_INDEX(pc, prof) \ 387238405Sjkim ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \ 388238405Sjkim (u_quad_t)((prof)->pr_scale)) >> 16) & ~1) 389238405Sjkim 390238405Sjkim/* 391238405Sjkim * Collect user-level profiling statistics; called on a profiling tick, 392238405Sjkim * when a process is running in user-mode. This routine may be called 393238405Sjkim * from an interrupt context. We try to update the user profiling buffers 394238405Sjkim * cheaply with fuswintr() and suswintr(). If that fails, we revert to 395238405Sjkim * an AST that will vector us to trap() with a context in which copyin 396238405Sjkim * and copyout will work. Trap will then call addupc_task(). 397280304Sjkim * 398280304Sjkim * Note that we may (rarely) not get around to the AST soon enough, and 399280304Sjkim * lose profile ticks when the next tick overwrites this one, but in this 400238405Sjkim * case the system is overloaded and the profile is probably already 401280304Sjkim * inaccurate. 402280304Sjkim */ 403280304Sjkimvoid 404280304Sjkimaddupc_intr(p, pc, ticks) 405280304Sjkim register struct proc *p; 406280304Sjkim register u_long pc; 407280304Sjkim u_int ticks; 408238405Sjkim{ 409280304Sjkim register struct uprof *prof; 410238405Sjkim register caddr_t addr; 411280304Sjkim register u_int i; 412280304Sjkim register int v; 413238405Sjkim 414238405Sjkim if (ticks == 0) 415238405Sjkim return; 416280304Sjkim prof = &p->p_stats->p_prof; 417280304Sjkim if (pc < prof->pr_off || 418280304Sjkim (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) 419238405Sjkim return; /* out of range; ignore */ 420280304Sjkim 421238405Sjkim addr = prof->pr_base + i; 422280304Sjkim if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + ticks) == -1) { 423280304Sjkim prof->pr_addr = pc; 424280304Sjkim prof->pr_ticks = ticks; 425280304Sjkim need_proftick(p); 426280304Sjkim } 427238405Sjkim} 428280304Sjkim 429280304Sjkim/* 430280304Sjkim * Much like before, but we can afford to take faults here. If the 431280304Sjkim * update fails, we simply turn off profiling. 432280304Sjkim */ 433280304Sjkimvoid 434280304Sjkimaddupc_task(p, pc, ticks) 435280304Sjkim register struct proc *p; 436280304Sjkim register u_long pc; 437238405Sjkim u_int ticks; 438280304Sjkim{ 439280304Sjkim register struct uprof *prof; 440280304Sjkim register caddr_t addr; 441280304Sjkim register u_int i; 442280304Sjkim u_short v; 443280304Sjkim 444280304Sjkim /* Testing P_PROFIL may be unnecessary, but is certainly safe. */ 445280304Sjkim if ((p->p_flag & P_PROFIL) == 0 || ticks == 0) 446280304Sjkim return; 447280304Sjkim 448238405Sjkim prof = &p->p_stats->p_prof; 449280304Sjkim if (pc < prof->pr_off || 450280304Sjkim (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) 451280304Sjkim return; 452280304Sjkim 453238405Sjkim addr = prof->pr_base + i; 454238405Sjkim if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) { 455280304Sjkim v += ticks; 456280304Sjkim if (copyout((caddr_t)&v, addr, sizeof(v)) == 0) 457238405Sjkim return; 458280304Sjkim } 459280304Sjkim stopprofclock(p); 460280304Sjkim} 461280304Sjkim