kern_tc.c revision 34975
1static volatile int print_tci = 1; 2 3/*- 4 * Copyright (c) 1997, 1998 Poul-Henning Kamp <phk@FreeBSD.org> 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. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 42 * $Id: kern_clock.c,v 1.61 1998/03/31 10:44:56 phk Exp $ 43 */ 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/dkstat.h> 48#include <sys/callout.h> 49#include <sys/kernel.h> 50#include <sys/proc.h> 51#include <sys/resourcevar.h> 52#include <sys/signalvar.h> 53#include <sys/timex.h> 54#include <vm/vm.h> 55#include <sys/lock.h> 56#include <vm/pmap.h> 57#include <vm/vm_map.h> 58#include <sys/sysctl.h> 59 60#include <machine/cpu.h> 61#include <machine/limits.h> 62 63#ifdef GPROF 64#include <sys/gmon.h> 65#endif 66 67#if defined(SMP) && defined(BETTER_CLOCK) 68#include <machine/smp.h> 69#endif 70 71static void initclocks __P((void *dummy)); 72SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL) 73 74static void tco_forward __P((void)); 75static void tco_setscales __P((struct timecounter *tc)); 76 77/* Some of these don't belong here, but it's easiest to concentrate them. */ 78#if defined(SMP) && defined(BETTER_CLOCK) 79long cp_time[CPUSTATES]; 80#else 81static long cp_time[CPUSTATES]; 82#endif 83long dk_seek[DK_NDRIVE]; 84static long dk_time[DK_NDRIVE]; /* time busy (in statclock ticks) */ 85long dk_wds[DK_NDRIVE]; 86long dk_wpms[DK_NDRIVE]; 87long dk_xfer[DK_NDRIVE]; 88 89int dk_busy; 90int dk_ndrive = 0; 91char dk_names[DK_NDRIVE][DK_NAMELEN]; 92 93long tk_cancc; 94long tk_nin; 95long tk_nout; 96long tk_rawcc; 97 98struct timecounter *timecounter; 99 100time_t time_second; 101 102/* 103 * Clock handling routines. 104 * 105 * This code is written to operate with two timers that run independently of 106 * each other. 107 * 108 * The main timer, running hz times per second, is used to trigger interval 109 * timers, timeouts and rescheduling as needed. 110 * 111 * The second timer handles kernel and user profiling, 112 * and does resource use estimation. If the second timer is programmable, 113 * it is randomized to avoid aliasing between the two clocks. For example, 114 * the randomization prevents an adversary from always giving up the cpu 115 * just before its quantum expires. Otherwise, it would never accumulate 116 * cpu ticks. The mean frequency of the second timer is stathz. 117 * 118 * If no second timer exists, stathz will be zero; in this case we drive 119 * profiling and statistics off the main clock. This WILL NOT be accurate; 120 * do not do it unless absolutely necessary. 121 * 122 * The statistics clock may (or may not) be run at a higher rate while 123 * profiling. This profile clock runs at profhz. We require that profhz 124 * be an integral multiple of stathz. 125 * 126 * If the statistics clock is running fast, it must be divided by the ratio 127 * profhz/stathz for statistics. (For profiling, every tick counts.) 128 * 129 * Time-of-day is maintained using a "timecounter", which may or may 130 * not be related to the hardware generating the above mentioned 131 * interrupts. 132 */ 133 134int stathz; 135int profhz; 136static int profprocs; 137int ticks; 138static int psdiv, pscnt; /* prof => stat divider */ 139int psratio; /* ratio: prof / stat */ 140 141volatile struct timeval mono_time; 142 143/* 144 * Initialize clock frequencies and start both clocks running. 145 */ 146/* ARGSUSED*/ 147static void 148initclocks(dummy) 149 void *dummy; 150{ 151 register int i; 152 153 /* 154 * Set divisors to 1 (normal case) and let the machine-specific 155 * code do its bit. 156 */ 157 psdiv = pscnt = 1; 158 cpu_initclocks(); 159 160 /* 161 * Compute profhz/stathz, and fix profhz if needed. 162 */ 163 i = stathz ? stathz : hz; 164 if (profhz == 0) 165 profhz = i; 166 psratio = profhz / i; 167} 168 169/* 170 * The real-time timer, interrupting hz times per second. 171 */ 172void 173hardclock(frame) 174 register struct clockframe *frame; 175{ 176 register struct proc *p; 177 178 p = curproc; 179 if (p) { 180 register struct pstats *pstats; 181 182 /* 183 * Run current process's virtual and profile time, as needed. 184 */ 185 pstats = p->p_stats; 186 if (CLKF_USERMODE(frame) && 187 timerisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) && 188 itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0) 189 psignal(p, SIGVTALRM); 190 if (timerisset(&pstats->p_timer[ITIMER_PROF].it_value) && 191 itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0) 192 psignal(p, SIGPROF); 193 } 194 195#if defined(SMP) && defined(BETTER_CLOCK) 196 forward_hardclock(pscnt); 197#endif 198 199 /* 200 * If no separate statistics clock is available, run it from here. 201 */ 202 if (stathz == 0) 203 statclock(frame); 204 205 tco_forward(); 206 ticks++; 207 208 /* 209 * Process callouts at a very low cpu priority, so we don't keep the 210 * relatively high clock interrupt priority any longer than necessary. 211 */ 212 if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) { 213 if (CLKF_BASEPRI(frame)) { 214 /* 215 * Save the overhead of a software interrupt; 216 * it will happen as soon as we return, so do it now. 217 */ 218 (void)splsoftclock(); 219 softclock(); 220 } else 221 setsoftclock(); 222 } else if (softticks + 1 == ticks) 223 ++softticks; 224} 225 226/* 227 * Compute number of ticks in the specified amount of time. 228 */ 229int 230tvtohz(tv) 231 struct timeval *tv; 232{ 233 register unsigned long ticks; 234 register long sec, usec; 235 int s; 236 237 /* 238 * If the number of usecs in the whole seconds part of the time 239 * difference fits in a long, then the total number of usecs will 240 * fit in an unsigned long. Compute the total and convert it to 241 * ticks, rounding up and adding 1 to allow for the current tick 242 * to expire. Rounding also depends on unsigned long arithmetic 243 * to avoid overflow. 244 * 245 * Otherwise, if the number of ticks in the whole seconds part of 246 * the time difference fits in a long, then convert the parts to 247 * ticks separately and add, using similar rounding methods and 248 * overflow avoidance. This method would work in the previous 249 * case but it is slightly slower and assumes that hz is integral. 250 * 251 * Otherwise, round the time difference down to the maximum 252 * representable value. 253 * 254 * If ints have 32 bits, then the maximum value for any timeout in 255 * 10ms ticks is 248 days. 256 */ 257 sec = tv->tv_sec; 258 usec = tv->tv_usec; 259 if (usec < 0) { 260 sec--; 261 usec += 1000000; 262 } 263 if (sec < 0) { 264#ifdef DIAGNOSTIC 265 if (usec > 0) { 266 sec++; 267 usec -= 1000000; 268 } 269 printf("tvotohz: negative time difference %ld sec %ld usec\n", 270 sec, usec); 271#endif 272 ticks = 1; 273 } else if (sec <= LONG_MAX / 1000000) 274 ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1)) 275 / tick + 1; 276 else if (sec <= LONG_MAX / hz) 277 ticks = sec * hz 278 + ((unsigned long)usec + (tick - 1)) / tick + 1; 279 else 280 ticks = LONG_MAX; 281 if (ticks > INT_MAX) 282 ticks = INT_MAX; 283 return (ticks); 284} 285 286 287/* 288 * Compute number of hz until specified time. Used to 289 * compute third argument to timeout() from an absolute time. 290 */ 291int 292hzto(tv) 293 struct timeval *tv; 294{ 295 register long sec, usec; 296 struct timeval t2; 297 298 getmicrotime(&t2); 299 t2.tv_sec = tv->tv_sec - t2.tv_sec; 300 t2.tv_usec = tv->tv_usec - t2.tv_usec; 301 return (tvtohz(&t2)); 302} 303 304/* 305 * Start profiling on a process. 306 * 307 * Kernel profiling passes proc0 which never exits and hence 308 * keeps the profile clock running constantly. 309 */ 310void 311startprofclock(p) 312 register struct proc *p; 313{ 314 int s; 315 316 if ((p->p_flag & P_PROFIL) == 0) { 317 p->p_flag |= P_PROFIL; 318 if (++profprocs == 1 && stathz != 0) { 319 s = splstatclock(); 320 psdiv = pscnt = psratio; 321 setstatclockrate(profhz); 322 splx(s); 323 } 324 } 325} 326 327/* 328 * Stop profiling on a process. 329 */ 330void 331stopprofclock(p) 332 register struct proc *p; 333{ 334 int s; 335 336 if (p->p_flag & P_PROFIL) { 337 p->p_flag &= ~P_PROFIL; 338 if (--profprocs == 0 && stathz != 0) { 339 s = splstatclock(); 340 psdiv = pscnt = 1; 341 setstatclockrate(stathz); 342 splx(s); 343 } 344 } 345} 346 347/* 348 * Statistics clock. Grab profile sample, and if divider reaches 0, 349 * do process and kernel statistics. 350 */ 351void 352statclock(frame) 353 register struct clockframe *frame; 354{ 355#ifdef GPROF 356 register struct gmonparam *g; 357#endif 358 register struct proc *p; 359 register int i; 360 struct pstats *pstats; 361 long rss; 362 struct rusage *ru; 363 struct vmspace *vm; 364 365 if (CLKF_USERMODE(frame)) { 366 p = curproc; 367 if (p->p_flag & P_PROFIL) 368 addupc_intr(p, CLKF_PC(frame), 1); 369#if defined(SMP) && defined(BETTER_CLOCK) 370 if (stathz != 0) 371 forward_statclock(pscnt); 372#endif 373 if (--pscnt > 0) 374 return; 375 /* 376 * Came from user mode; CPU was in user state. 377 * If this process is being profiled record the tick. 378 */ 379 p->p_uticks++; 380 if (p->p_nice > NZERO) 381 cp_time[CP_NICE]++; 382 else 383 cp_time[CP_USER]++; 384 } else { 385#ifdef GPROF 386 /* 387 * Kernel statistics are just like addupc_intr, only easier. 388 */ 389 g = &_gmonparam; 390 if (g->state == GMON_PROF_ON) { 391 i = CLKF_PC(frame) - g->lowpc; 392 if (i < g->textsize) { 393 i /= HISTFRACTION * sizeof(*g->kcount); 394 g->kcount[i]++; 395 } 396 } 397#endif 398#if defined(SMP) && defined(BETTER_CLOCK) 399 if (stathz != 0) 400 forward_statclock(pscnt); 401#endif 402 if (--pscnt > 0) 403 return; 404 /* 405 * Came from kernel mode, so we were: 406 * - handling an interrupt, 407 * - doing syscall or trap work on behalf of the current 408 * user process, or 409 * - spinning in the idle loop. 410 * Whichever it is, charge the time as appropriate. 411 * Note that we charge interrupts to the current process, 412 * regardless of whether they are ``for'' that process, 413 * so that we know how much of its real time was spent 414 * in ``non-process'' (i.e., interrupt) work. 415 */ 416 p = curproc; 417 if (CLKF_INTR(frame)) { 418 if (p != NULL) 419 p->p_iticks++; 420 cp_time[CP_INTR]++; 421 } else if (p != NULL) { 422 p->p_sticks++; 423 cp_time[CP_SYS]++; 424 } else 425 cp_time[CP_IDLE]++; 426 } 427 pscnt = psdiv; 428 429 /* 430 * We maintain statistics shown by user-level statistics 431 * programs: the amount of time in each cpu state, and 432 * the amount of time each of DK_NDRIVE ``drives'' is busy. 433 * 434 * XXX should either run linked list of drives, or (better) 435 * grab timestamps in the start & done code. 436 */ 437 for (i = 0; i < DK_NDRIVE; i++) 438 if (dk_busy & (1 << i)) 439 dk_time[i]++; 440 441 /* 442 * We adjust the priority of the current process. The priority of 443 * a process gets worse as it accumulates CPU time. The cpu usage 444 * estimator (p_estcpu) is increased here. The formula for computing 445 * priorities (in kern_synch.c) will compute a different value each 446 * time p_estcpu increases by 4. The cpu usage estimator ramps up 447 * quite quickly when the process is running (linearly), and decays 448 * away exponentially, at a rate which is proportionally slower when 449 * the system is busy. The basic principal is that the system will 450 * 90% forget that the process used a lot of CPU time in 5 * loadav 451 * seconds. This causes the system to favor processes which haven't 452 * run much recently, and to round-robin among other processes. 453 */ 454 if (p != NULL) { 455 p->p_cpticks++; 456 if (++p->p_estcpu == 0) 457 p->p_estcpu--; 458 if ((p->p_estcpu & 3) == 0) { 459 resetpriority(p); 460 if (p->p_priority >= PUSER) 461 p->p_priority = p->p_usrpri; 462 } 463 464 /* Update resource usage integrals and maximums. */ 465 if ((pstats = p->p_stats) != NULL && 466 (ru = &pstats->p_ru) != NULL && 467 (vm = p->p_vmspace) != NULL) { 468 ru->ru_ixrss += vm->vm_tsize * PAGE_SIZE / 1024; 469 ru->ru_idrss += vm->vm_dsize * PAGE_SIZE / 1024; 470 ru->ru_isrss += vm->vm_ssize * PAGE_SIZE / 1024; 471 rss = vm->vm_pmap.pm_stats.resident_count * 472 PAGE_SIZE / 1024; 473 if (ru->ru_maxrss < rss) 474 ru->ru_maxrss = rss; 475 } 476 } 477} 478 479/* 480 * Return information about system clocks. 481 */ 482static int 483sysctl_kern_clockrate SYSCTL_HANDLER_ARGS 484{ 485 struct clockinfo clkinfo; 486 /* 487 * Construct clockinfo structure. 488 */ 489 clkinfo.hz = hz; 490 clkinfo.tick = tick; 491 clkinfo.tickadj = tickadj; 492 clkinfo.profhz = profhz; 493 clkinfo.stathz = stathz ? stathz : hz; 494 return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req)); 495} 496 497SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD, 498 0, 0, sysctl_kern_clockrate, "S,clockinfo",""); 499 500 501/* 502 * We have four functions for looking at the clock, two for microseconds 503 * and two for nanoseconds. For each there is fast but less precise 504 * version "get{nano|micro}time" which will return a time which is up 505 * to 1/HZ previous to the call, whereas the raw version "{nano|micro}time" 506 * will return a timestamp which is as precise as possible. 507 */ 508 509void 510getmicrotime(struct timeval *tvp) 511{ 512 struct timecounter *tc; 513 514 tc = timecounter; 515 tvp->tv_sec = tc->offset_sec; 516 tvp->tv_usec = tc->offset_micro; 517} 518 519void 520getnanotime(struct timespec *tsp) 521{ 522 struct timecounter *tc; 523 524 tc = timecounter; 525 tsp->tv_sec = tc->offset_sec; 526 tsp->tv_nsec = tc->offset_nano >> 32; 527} 528 529void 530microtime(struct timeval *tv) 531{ 532 struct timecounter *tc; 533 534 tc = (struct timecounter *)timecounter; 535 tv->tv_sec = tc->offset_sec; 536 tv->tv_usec = tc->offset_micro; 537 tv->tv_usec += 538 ((u_int64_t)tc->get_timedelta(tc) * tc->scale_micro) >> 32; 539 if (tv->tv_usec >= 1000000) { 540 tv->tv_usec -= 1000000; 541 tv->tv_sec++; 542 } 543} 544 545void 546nanotime(struct timespec *tv) 547{ 548 u_int count; 549 u_int64_t delta; 550 struct timecounter *tc; 551 552 tc = (struct timecounter *)timecounter; 553 tv->tv_sec = tc->offset_sec; 554 count = tc->get_timedelta(tc); 555 delta = tc->offset_nano; 556 delta += ((u_int64_t)count * tc->scale_nano_f); 557 delta >>= 32; 558 delta += ((u_int64_t)count * tc->scale_nano_i); 559 if (delta >= 1000000000) { 560 delta -= 1000000000; 561 tv->tv_sec++; 562 } 563 tv->tv_nsec = delta; 564} 565 566static void 567tco_setscales(struct timecounter *tc) 568{ 569 u_int64_t scale; 570 571 scale = 1000000000LL << 32; 572 if (tc->adjustment > 0) 573 scale += (tc->adjustment * 1000LL) << 10; 574 else 575 scale -= (-tc->adjustment * 1000LL) << 10; 576 scale /= tc->frequency; 577 tc->scale_micro = scale / 1000; 578 tc->scale_nano_f = scale & 0xffffffff; 579 tc->scale_nano_i = scale >> 32; 580} 581 582static u_int 583delta_timecounter(struct timecounter *tc) 584{ 585 586 return((tc->get_timecount() - tc->offset_count) & tc->counter_mask); 587} 588 589void 590init_timecounter(struct timecounter *tc) 591{ 592 struct timespec ts0, ts1; 593 int i; 594 595 if (!tc->get_timedelta) 596 tc->get_timedelta = delta_timecounter; 597 tc->adjustment = 0; 598 tco_setscales(tc); 599 tc->offset_count = tc->get_timecount(); 600 tc[0].tweak = &tc[0]; 601 tc[2] = tc[1] = tc[0]; 602 tc[1].other = &tc[2]; 603 tc[2].other = &tc[1]; 604 if (!timecounter) 605 timecounter = &tc[2]; 606 tc = &tc[1]; 607 608 /* 609 * Figure out the cost of calling this timecounter. 610 * XXX: The 1:15 ratio is a guess at reality. 611 */ 612 nanotime(&ts0); 613 for (i = 0; i < 16; i ++) 614 tc->get_timecount(); 615 for (i = 0; i < 240; i ++) 616 tc->get_timedelta(tc); 617 nanotime(&ts1); 618 ts1.tv_sec -= ts0.tv_sec; 619 tc->cost = ts1.tv_sec * 1000000000 + ts1.tv_nsec - ts0.tv_nsec; 620 tc->cost >>= 8; 621 if (print_tci && strcmp(tc->name, "dummy")) 622 printf("Timecounter \"%s\" frequency %lu Hz cost %u ns\n", 623 tc->name, tc->frequency, tc->cost); 624 625 /* XXX: For now always start using the counter. */ 626 tc->offset_count = tc->get_timecount(); 627 nanotime(&ts1); 628 tc->offset_nano = (u_int64_t)ts1.tv_nsec << 32; 629 tc->offset_micro = ts1.tv_nsec / 1000; 630 tc->offset_sec = ts1.tv_sec; 631 timecounter = tc; 632} 633 634void 635set_timecounter(struct timespec *ts) 636{ 637 struct timecounter *tc, *tco; 638 int s; 639 640 /* 641 * XXX we must be called at splclock() to preven *ts becoming 642 * invalid, so there is no point in spls here. 643 */ 644 s = splclock(); 645 tc = timecounter->other; 646 tco = tc->other; 647 *tc = *timecounter; 648 tc->other = tco; 649 tc->offset_sec = ts->tv_sec; 650 tc->offset_nano = (u_int64_t)ts->tv_nsec << 32; 651 tc->offset_micro = ts->tv_nsec / 1000; 652 tc->offset_count = tc->get_timecount(); 653 time_second = tc->offset_sec; 654 timecounter = tc; 655 splx(s); 656} 657 658void 659switch_timecounter(struct timecounter *newtc) 660{ 661 int s; 662 struct timecounter *tc; 663 struct timespec ts; 664 665 s = splclock(); 666 tc = timecounter; 667 if (newtc == tc || newtc == tc->other) { 668 splx(s); 669 return; 670 } 671 nanotime(&ts); 672 newtc->offset_sec = ts.tv_sec; 673 newtc->offset_nano = (u_int64_t)ts.tv_nsec << 32; 674 newtc->offset_micro = ts.tv_nsec / 1000; 675 newtc->offset_count = newtc->get_timecount(); 676 timecounter = newtc; 677 splx(s); 678} 679 680static struct timecounter * 681sync_other_counter(void) 682{ 683 struct timecounter *tc, *tco; 684 u_int delta; 685 686 tc = timecounter->other; 687 tco = tc->other; 688 *tc = *timecounter; 689 tc->other = tco; 690 delta = tc->get_timedelta(tc); 691 tc->offset_count += delta; 692 tc->offset_count &= tc->counter_mask; 693 tc->offset_nano += (u_int64_t)delta * tc->scale_nano_f; 694 tc->offset_nano += (u_int64_t)delta * tc->scale_nano_i << 32; 695 return (tc); 696} 697 698static void 699tco_forward(void) 700{ 701 struct timecounter *tc; 702 703 tc = sync_other_counter(); 704 if (timedelta != 0) { 705 tc->offset_nano += (u_int64_t)(tickdelta * 1000) << 32; 706 mono_time.tv_usec += tickdelta; 707 timedelta -= tickdelta; 708 } 709 mono_time.tv_usec += tick; 710 if (mono_time.tv_usec >= 1000000) { 711 mono_time.tv_usec -= 1000000; 712 mono_time.tv_sec++; 713 } 714 715 if (tc->offset_nano >= 1000000000ULL << 32) { 716 tc->offset_nano -= 1000000000ULL << 32; 717 tc->offset_sec++; 718 tc->frequency = tc->tweak->frequency; 719 tc->adjustment = tc->tweak->adjustment; 720 ntp_update_second(tc); /* XXX only needed if xntpd runs */ 721 tco_setscales(tc); 722 } 723 724 tc->offset_micro = (tc->offset_nano / 1000) >> 32; 725 726 time_second = tc->offset_sec; 727 timecounter = tc; 728} 729 730static int 731sysctl_kern_timecounter_frequency SYSCTL_HANDLER_ARGS 732{ 733 734 return (sysctl_handle_opaque(oidp, &timecounter->tweak->frequency, 735 sizeof(timecounter->tweak->frequency), req)); 736} 737 738static int 739sysctl_kern_timecounter_adjustment SYSCTL_HANDLER_ARGS 740{ 741 742 return (sysctl_handle_opaque(oidp, &timecounter->tweak->adjustment, 743 sizeof(timecounter->tweak->adjustment), req)); 744} 745 746SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); 747 748SYSCTL_PROC(_kern_timecounter, OID_AUTO, frequency, CTLTYPE_INT | CTLFLAG_RW, 749 0, sizeof(u_int), sysctl_kern_timecounter_frequency, "I", ""); 750 751SYSCTL_PROC(_kern_timecounter, OID_AUTO, adjustment, CTLTYPE_INT | CTLFLAG_RW, 752 0, sizeof(int), sysctl_kern_timecounter_adjustment, "I", ""); 753 754/* 755 * Implement a dummy timecounter which we can use until we get a real one 756 * in the air. This allows the console and other early stuff to use 757 * timeservices. 758 */ 759 760static u_int64_t 761dummy_get_timecount(void) 762{ 763 static u_int64_t now; 764 return (++now); 765} 766 767static struct timecounter dummy_timecounter[3] = { 768 { 769 0, 770 dummy_get_timecount, 771 ~0, 772 100000, 773 "dummy" 774 } 775}; 776 777static void 778initdummytimecounter(dummy) 779 void *dummy; 780{ 781 init_timecounter(dummy_timecounter); 782} 783 784SYSINIT(dummytc, SI_SUB_CONSOLE, SI_ORDER_FIRST, initdummytimecounter, NULL) 785