sysconf(_SC_CLK_TCK) returns a contstant value defined in src/sys/i386/include/ansi.h this is not correct as the actual value of the statistics clock is not a constnat. In particular it is 100Hz on my system, but the constant returned is 128. The stat clock may be 100Hz is apm is enabled with flags 0x20 in the kernel file Fix: The call to sysconf(_SC_CLK_TCK) should actuallyy query the kernel to get the correct value. Note that this is how /usr/bin/time gets the frequency of the clock. I have included below an analysis of the problem done by someone else on the FreeBSD stable mailing lists, which follwos the code through in more depth. I do not know if this problem still exists in 5 or CURRENT. Response from Jon Noack <noackjr@alumni.rice.edu> to my query on -stable ------------------------------------------------------------------- I infer from your kern.clockrate output that you are running 4.x. Why does sysconf(_SC_CLK_TCK) always returns 128? Check out sysconf() in src/lib/libc/gen/sysconf.c (lines 83-84 of rev. 1.10): ********************************************************************** case _SC_CLK_TCK: return (CLK_TCK); ********************************************************************** CLK_TCK is defined in src/include/time.h (line 52 of rev. 1.15): ********************************************************************** #define CLK_TCK _BSD_CLK_TCK_ ********************************************************************** _BSD_CLK_TCK_ is defined in src/sys/i386/include/ansi.h (line 101 of rev. 1.18.2.4): ********************************************************************** #define _BSD_CLK_TCK_ 128 ********************************************************************** So on i386 (and FreeBSD 4.x), sysconf(_SC_CLK_TCK) will always return 128. If you look in src/sys/alpha/include/ansi.h, you'll see that on alpha it will always return 100. To determine how stathz can vary, we'll have to dig deeper. Check out initclocks() in src/sys/kern/kern_clock.c (lines 196-213 of rev. 1.105.2.11): ********************************************************************** /* * Set divisors to 1 (normal case) and let the machine-specific * code do its bit. */ psdiv = pscnt = 1; cpu_initclocks(); #ifdef DEVICE_POLLING init_device_poll(); #endif /* * Compute profhz/stathz, and fix profhz if needed. */ i = stathz ? stathz : hz; if (profhz == 0) profhz = i; psratio = profhz / i; ********************************************************************** stathz and profhz are originally set by cpu_initclocks() (which is MD). If they are not set at this point, hz is used. This must be the case for some of your machines as both stathz and profhz equal hz. So why aren't stathz and profhz being set earlier? Check out cpu_initclocks() in src/sys/i386/isa/clock.c (lines 995-1008 of rev. 1.149.2.6): ********************************************************************** if (statclock_disable) { /* * The stat interrupt mask is different without the * statistics clock. Also, don't set the interrupt * flag which would normally cause the RTC to generate * interrupts. */ stat_imask = HWI_MASK | SWI_MASK; rtc_statusb = RTCSB_24HR; } else { /* Setting stathz to nonzero early helps avoid races. */ stathz = RTC_NOPROFRATE; profhz = RTC_PROFRATE; } ********************************************************************** If you look in src/sys/isa/rtc.h, you'll see that RTC_NOPROFRATE=128 and RTC_PROFRATE=1024. The only way stathz and profhz will not be set here is if statclock_disable is true. Where is statclock_disable set? Check out apm_attach() in src/sys/i386/apm/apm.c (lines 1032-1033 of rev. 1.114.2.6): ********************************************************************** if (flags & 0x20) statclock_disable = 1; ********************************************************************** Thus, you must have "device apm0 flags 0x20" or something similar in your kernel config file for you to get stathz and profhz as 100. apm is disabled in GENERIC, so by default this is not a problem; apm_attach won't be called if apm is disabled, so the fact that GENERIC includes "flags 0x20" is irrelevant. Jon How-To-Repeat: Build a kernel which has a statistics clock other tahn 128 and observe that sysconf(_SC_CLK_TCK) returns the wrong value!
The patch below borrows code from NetBSD and partially solves the issue. It does not address all bde's concerns though http://docs.freebsd.org/cgi/mid.cgi?20020701142849.U6692-100000 Also, on my amd64 box stathz != 128 kern.clockrate: { hz = 1000, tick = 1000, profhz = 8126, stathz = 127 } --- a.diff begins here --- Index: include/time.h =================================================================== --- include/time.h (revision 216514) +++ include/time.h (working copy) @@ -50,8 +50,12 @@ * Frequency of the clock ticks reported by times(). Deprecated - use * sysconf(_SC_CLK_TCK) instead. (Removed in 1003.1-2001.) */ -#define CLK_TCK 128 +#ifndef __lint +__weak_reference(sysconf, __sysconf); +long __sysconf(int); #endif +#define CLK_TCK (__sysconf(3)) +#endif /* Frequency of the clock ticks reported by clock(). */ #define CLOCKS_PER_SEC 128 Index: lib/libc/gen/sysconf.c =================================================================== --- lib/libc/gen/sysconf.c (revision 216473) +++ lib/libc/gen/sysconf.c (working copy) @@ -75,6 +75,8 @@ sysconf(name) int mib[2], sverrno, value; long lvalue, defaultresult; const char *path; + struct clockinfo tmpclock; + static int clk_tck; defaultresult = -1; @@ -94,7 +96,21 @@ sysconf(name) } return ((long)rl.rlim_cur); case _SC_CLK_TCK: - return (CLK_TCK); + /* + * Has to be handled specially because it returns a + * struct clockinfo instead of an integer. Also, since + * this might be called often by some things that + * don't grok CLK_TCK can be a macro expanding to a + * function, cache the value. + */ + if (clk_tck == 0) { + mib[0] = CTL_KERN; + mib[1] = KERN_CLOCKRATE; + len = sizeof(struct clockinfo); + clk_tck = sysctl(mib, 2, &tmpclock, &len, NULL, 0) + == -1 ? -1 : tmpclock.stathz; + } + return(clk_tck); case _SC_NGROUPS_MAX: mib[0] = CTL_KERN; mib[1] = KERN_NGROUPS; Index: usr.sbin/timed/timed/timed.c =================================================================== --- usr.sbin/timed/timed/timed.c (revision 216514) +++ usr.sbin/timed/timed/timed.c (working copy) @@ -759,7 +759,8 @@ int force; { # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */ - static unsigned long last_update = -NG_DELAY; + static unsigned long last_update; + static int firsttime; unsigned long new_update; struct goodhost *ghp, **ghpp; #ifdef HAVENIS @@ -768,6 +769,10 @@ #endif /* HAVENIS */ struct tms tm; + if (firsttime == 0) { + last_update = -NG_DELAY; + firsttime++; + } /* if no netgroup, then we are finished */ if (goodgroup == 0 || !Mflag) --- a.diff ends here ---
For bugs matching the following criteria: Status: In Progress Changed: (is less than) 2014-06-01 Reset to default assignee and clear in-progress tags. Mail being skipped
Keyword: patch or patch-ready – in lieu of summary line prefix: [patch] * bulk change for the keyword * summary lines may be edited manually (not in bulk). Keyword descriptions and search interface: <https://bugs.freebsd.org/bugzilla/describekeywords.cgi>