1 /* $OpenBSD: kern_clock.c,v 1.101 2020/01/21 16:16:23 mpi Exp $ */ 2 /* $NetBSD: kern_clock.c,v 1.34 1996/06/09 04:51:03 briggs Exp $ */ 3 4 /*- 5 * Copyright (c) 1982, 1986, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/timeout.h> 43 #include <sys/kernel.h> 44 #include <sys/limits.h> 45 #include <sys/proc.h> 46 #include <sys/user.h> 47 #include <sys/resourcevar.h> 48 #include <sys/signalvar.h> 49 #include <sys/sysctl.h> 50 #include <sys/sched.h> 51 #include <sys/timetc.h> 52 53 54 #if defined(GPROF) || defined(DDBPROF) 55 #include <sys/gmon.h> 56 #endif 57 58 #include "dt.h" 59 #if NDT > 0 60 #include <dev/dt/dtvar.h> 61 #endif 62 63 /* 64 * Clock handling routines. 65 * 66 * This code is written to operate with two timers that run independently of 67 * each other. The main clock, running hz times per second, is used to keep 68 * track of real time. The second timer handles kernel and user profiling, 69 * and does resource use estimation. If the second timer is programmable, 70 * it is randomized to avoid aliasing between the two clocks. For example, 71 * the randomization prevents an adversary from always giving up the cpu 72 * just before its quantum expires. Otherwise, it would never accumulate 73 * cpu ticks. The mean frequency of the second timer is stathz. 74 * 75 * If no second timer exists, stathz will be zero; in this case we drive 76 * profiling and statistics off the main clock. This WILL NOT be accurate; 77 * do not do it unless absolutely necessary. 78 * 79 * The statistics clock may (or may not) be run at a higher rate while 80 * profiling. This profile clock runs at profhz. We require that profhz 81 * be an integral multiple of stathz. 82 * 83 * If the statistics clock is running fast, it must be divided by the ratio 84 * profhz/stathz for statistics. (For profiling, every tick counts.) 85 */ 86 87 int stathz; 88 int schedhz; 89 int profhz; 90 int profprocs; 91 int ticks; 92 static int psdiv, pscnt; /* prof => stat divider */ 93 int psratio; /* ratio: prof / stat */ 94 95 volatile unsigned long jiffies; /* XXX Linux API for drm(4) */ 96 97 /* 98 * Initialize clock frequencies and start both clocks running. 99 */ 100 void 101 initclocks(void) 102 { 103 int i; 104 105 ticks = INT_MAX - (15 * 60 * hz); 106 jiffies = ULONG_MAX - (10 * 60 * hz); 107 108 /* 109 * Set divisors to 1 (normal case) and let the machine-specific 110 * code do its bit. 111 */ 112 psdiv = pscnt = 1; 113 cpu_initclocks(); 114 115 /* 116 * Compute profhz/stathz, and fix profhz if needed. 117 */ 118 i = stathz ? stathz : hz; 119 if (profhz == 0) 120 profhz = i; 121 psratio = profhz / i; 122 123 /* For very large HZ, ensure that division by 0 does not occur later */ 124 if (tickadj == 0) 125 tickadj = 1; 126 127 inittimecounter(); 128 } 129 130 /* 131 * hardclock does the accounting needed for ITIMER_PROF and ITIMER_VIRTUAL. 132 * We don't want to send signals with psignal from hardclock because it makes 133 * MULTIPROCESSOR locking very complicated. Instead, to use an idea from 134 * FreeBSD, we set a flag on the thread and when it goes to return to 135 * userspace it signals itself. 136 */ 137 138 /* 139 * The real-time timer, interrupting hz times per second. 140 */ 141 void 142 hardclock(struct clockframe *frame) 143 { 144 struct proc *p; 145 struct cpu_info *ci = curcpu(); 146 147 p = curproc; 148 if (p && ((p->p_flag & (P_SYSTEM | P_WEXIT)) == 0)) { 149 struct process *pr = p->p_p; 150 151 /* 152 * Run current process's virtual and profile time, as needed. 153 */ 154 if (CLKF_USERMODE(frame) && 155 timespecisset(&pr->ps_timer[ITIMER_VIRTUAL].it_value) && 156 itimerdecr(&pr->ps_timer[ITIMER_VIRTUAL], tick_nsec) == 0) { 157 atomic_setbits_int(&p->p_flag, P_ALRMPEND); 158 need_proftick(p); 159 } 160 if (timespecisset(&pr->ps_timer[ITIMER_PROF].it_value) && 161 itimerdecr(&pr->ps_timer[ITIMER_PROF], tick_nsec) == 0) { 162 atomic_setbits_int(&p->p_flag, P_PROFPEND); 163 need_proftick(p); 164 } 165 } 166 167 /* 168 * If no separate statistics clock is available, run it from here. 169 */ 170 if (stathz == 0) 171 statclock(frame); 172 173 if (--ci->ci_schedstate.spc_rrticks <= 0) 174 roundrobin(ci); 175 176 #if NDT > 0 177 DT_ENTER(profile, NULL); 178 if (CPU_IS_PRIMARY(ci)) 179 DT_ENTER(interval, NULL); 180 #endif 181 182 /* 183 * If we are not the primary CPU, we're not allowed to do 184 * any more work. 185 */ 186 if (CPU_IS_PRIMARY(ci) == 0) 187 return; 188 189 tc_ticktock(); 190 ticks++; 191 jiffies++; 192 193 /* 194 * Update the timeout wheel. 195 */ 196 timeout_hardclock_update(); 197 } 198 199 /* 200 * Compute number of hz in the specified amount of time. 201 */ 202 int 203 tvtohz(const struct timeval *tv) 204 { 205 unsigned long nticks; 206 time_t sec; 207 long usec; 208 209 /* 210 * If the number of usecs in the whole seconds part of the time 211 * fits in a long, then the total number of usecs will 212 * fit in an unsigned long. Compute the total and convert it to 213 * ticks, rounding up and adding 1 to allow for the current tick 214 * to expire. Rounding also depends on unsigned long arithmetic 215 * to avoid overflow. 216 * 217 * Otherwise, if the number of ticks in the whole seconds part of 218 * the time fits in a long, then convert the parts to 219 * ticks separately and add, using similar rounding methods and 220 * overflow avoidance. This method would work in the previous 221 * case but it is slightly slower and assumes that hz is integral. 222 * 223 * Otherwise, round the time down to the maximum 224 * representable value. 225 * 226 * If ints have 32 bits, then the maximum value for any timeout in 227 * 10ms ticks is 248 days. 228 */ 229 sec = tv->tv_sec; 230 usec = tv->tv_usec; 231 if (sec < 0 || (sec == 0 && usec <= 0)) 232 nticks = 0; 233 else if (sec <= LONG_MAX / 1000000) 234 nticks = (sec * 1000000 + (unsigned long)usec + (tick - 1)) 235 / tick + 1; 236 else if (sec <= LONG_MAX / hz) 237 nticks = sec * hz 238 + ((unsigned long)usec + (tick - 1)) / tick + 1; 239 else 240 nticks = LONG_MAX; 241 if (nticks > INT_MAX) 242 nticks = INT_MAX; 243 return ((int)nticks); 244 } 245 246 int 247 tstohz(const struct timespec *ts) 248 { 249 struct timeval tv; 250 TIMESPEC_TO_TIMEVAL(&tv, ts); 251 252 /* Round up. */ 253 if ((ts->tv_nsec % 1000) != 0) { 254 tv.tv_usec += 1; 255 if (tv.tv_usec >= 1000000) { 256 tv.tv_usec -= 1000000; 257 tv.tv_sec += 1; 258 } 259 } 260 261 return (tvtohz(&tv)); 262 } 263 264 /* 265 * Start profiling on a process. 266 * 267 * Kernel profiling passes proc0 which never exits and hence 268 * keeps the profile clock running constantly. 269 */ 270 void 271 startprofclock(struct process *pr) 272 { 273 int s; 274 275 if ((pr->ps_flags & PS_PROFIL) == 0) { 276 atomic_setbits_int(&pr->ps_flags, PS_PROFIL); 277 if (++profprocs == 1 && stathz != 0) { 278 s = splstatclock(); 279 psdiv = pscnt = psratio; 280 setstatclockrate(profhz); 281 splx(s); 282 } 283 } 284 } 285 286 /* 287 * Stop profiling on a process. 288 */ 289 void 290 stopprofclock(struct process *pr) 291 { 292 int s; 293 294 if (pr->ps_flags & PS_PROFIL) { 295 atomic_clearbits_int(&pr->ps_flags, PS_PROFIL); 296 if (--profprocs == 0 && stathz != 0) { 297 s = splstatclock(); 298 psdiv = pscnt = 1; 299 setstatclockrate(stathz); 300 splx(s); 301 } 302 } 303 } 304 305 /* 306 * Statistics clock. Grab profile sample, and if divider reaches 0, 307 * do process and kernel statistics. 308 */ 309 void 310 statclock(struct clockframe *frame) 311 { 312 #if defined(GPROF) || defined(DDBPROF) 313 struct gmonparam *g; 314 u_long i; 315 #endif 316 struct cpu_info *ci = curcpu(); 317 struct schedstate_percpu *spc = &ci->ci_schedstate; 318 struct proc *p = curproc; 319 struct process *pr; 320 321 /* 322 * Notice changes in divisor frequency, and adjust clock 323 * frequency accordingly. 324 */ 325 if (spc->spc_psdiv != psdiv) { 326 spc->spc_psdiv = psdiv; 327 spc->spc_pscnt = psdiv; 328 if (psdiv == 1) { 329 setstatclockrate(stathz); 330 } else { 331 setstatclockrate(profhz); 332 } 333 } 334 335 if (CLKF_USERMODE(frame)) { 336 pr = p->p_p; 337 if (pr->ps_flags & PS_PROFIL) 338 addupc_intr(p, CLKF_PC(frame)); 339 if (--spc->spc_pscnt > 0) 340 return; 341 /* 342 * Came from user mode; CPU was in user state. 343 * If this process is being profiled record the tick. 344 */ 345 p->p_uticks++; 346 if (pr->ps_nice > NZERO) 347 spc->spc_cp_time[CP_NICE]++; 348 else 349 spc->spc_cp_time[CP_USER]++; 350 } else { 351 #if defined(GPROF) || defined(DDBPROF) 352 /* 353 * Kernel statistics are just like addupc_intr, only easier. 354 */ 355 g = ci->ci_gmon; 356 if (g != NULL && g->state == GMON_PROF_ON) { 357 i = CLKF_PC(frame) - g->lowpc; 358 if (i < g->textsize) { 359 i /= HISTFRACTION * sizeof(*g->kcount); 360 g->kcount[i]++; 361 } 362 } 363 #endif 364 #if defined(PROC_PC) 365 if (p != NULL && p->p_p->ps_flags & PS_PROFIL) 366 addupc_intr(p, PROC_PC(p)); 367 #endif 368 if (--spc->spc_pscnt > 0) 369 return; 370 /* 371 * Came from kernel mode, so we were: 372 * - spinning on a lock 373 * - handling an interrupt, 374 * - doing syscall or trap work on behalf of the current 375 * user process, or 376 * - spinning in the idle loop. 377 * Whichever it is, charge the time as appropriate. 378 * Note that we charge interrupts to the current process, 379 * regardless of whether they are ``for'' that process, 380 * so that we know how much of its real time was spent 381 * in ``non-process'' (i.e., interrupt) work. 382 */ 383 if (CLKF_INTR(frame)) { 384 if (p != NULL) 385 p->p_iticks++; 386 spc->spc_cp_time[spc->spc_spinning ? 387 CP_SPIN : CP_INTR]++; 388 } else if (p != NULL && p != spc->spc_idleproc) { 389 p->p_sticks++; 390 spc->spc_cp_time[spc->spc_spinning ? 391 CP_SPIN : CP_SYS]++; 392 } else 393 spc->spc_cp_time[spc->spc_spinning ? 394 CP_SPIN : CP_IDLE]++; 395 } 396 spc->spc_pscnt = psdiv; 397 398 if (p != NULL) { 399 p->p_cpticks++; 400 /* 401 * If no schedclock is provided, call it here at ~~12-25 Hz; 402 * ~~16 Hz is best 403 */ 404 if (schedhz == 0) { 405 if ((++spc->spc_schedticks & 3) == 0) 406 schedclock(p); 407 } 408 } 409 } 410 411 /* 412 * Return information about system clocks. 413 */ 414 int 415 sysctl_clockrate(char *where, size_t *sizep, void *newp) 416 { 417 struct clockinfo clkinfo; 418 419 /* 420 * Construct clockinfo structure. 421 */ 422 memset(&clkinfo, 0, sizeof clkinfo); 423 clkinfo.tick = tick; 424 clkinfo.tickadj = tickadj; 425 clkinfo.hz = hz; 426 clkinfo.profhz = profhz; 427 clkinfo.stathz = stathz ? stathz : hz; 428 return (sysctl_rdstruct(where, sizep, newp, &clkinfo, sizeof(clkinfo))); 429 } 430