static double tempcomp_interval;
static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2;
-/* Boolean for whether the Linux HZ value has been overridden, and the
- * new value. */
-static int set_linux_hz = 0;
-static int linux_hz;
-
-/* Boolean for whether the Linux frequency scaling value (i.e. the one that's
- * approx (1<<SHIFT_HZ)/HZ) has been overridden, and the new value. */
-static int set_linux_freq_scale = 0;
-static double linux_freq_scale;
-
static int sched_priority = 0;
static int lock_memory = 0;
} else if (!strcasecmp(command, "leapsectz")) {
parse_string(p, &leapsec_tz);
} else if (!strcasecmp(command, "linux_freq_scale")) {
- set_linux_freq_scale = parse_double(p, &linux_freq_scale);
+ LOG(LOGS_WARN, LOGF_Configure, "%s directive is no longer supported", command);
} else if (!strcasecmp(command, "linux_hz")) {
- set_linux_hz = parse_int(p, &linux_hz);
+ LOG(LOGS_WARN, LOGF_Configure, "%s directive is no longer supported", command);
} else if (!strcasecmp(command, "local")) {
parse_local(p);
} else if (!strcasecmp(command, "lock_all")) {
/* ================================================== */
-void
-CNF_GetLinuxHz(int *set, int *hz)
-{
- *set = set_linux_hz;
- *hz = linux_hz;
-}
-
-/* ================================================== */
-
-void
-CNF_GetLinuxFreqScale(int *set, double *freq_scale)
-{
- *set = set_linux_freq_scale;
- *freq_scale = linux_freq_scale ;
-}
-
-/* ================================================== */
-
int
CNF_GetSchedPriority(void)
{
/* This is the uncompensated system tick value */
static int nominal_tick;
+/* Current tick value */
+static int current_delta_tick;
+
/* The maximum amount by which 'tick' can be biased away from 'nominal_tick'
(sys_adjtimex() in the kernel bounds this to 10%) */
static int max_tick_bias;
-/* This is the scaling required to go between absolute ppm and the
- scaled ppm used as an argument to adjtimex. Because chronyd is to an extent
- 'closed loop' maybe it doesn't matter if this is wrongly determined, UNLESS
- the system's ppm error is close to a multiple of HZ, in which case the
- relationship between changing the frequency and changing the value of 'tick'
- will be wrong. This would (I imagine) cause the system to thrash between
- two states.
-
- However..., if this effect was not corrected, and the system is left offline
- for a long period, a substantial error would build up. e.g. with HZ==100,
- the correction required is 128/128.125, giving a drift of about 84 seconds
- per day). */
-static double freq_scale;
-
-/* The kernel HZ constant (USER_HZ in recent kernels). */
+/* The kernel USER_HZ constant */
static int hz;
static double dhz; /* And dbl prec version of same for arithmetic */
/* ================================================== */
/* This call sets the Linux kernel frequency to a given value in parts
per million relative to the nominal running frequency. Nominal is taken to
- be tick=10000, freq=0 (for a HZ==100 system, other values otherwise). The
- convention is that this is called with a positive argument if the local
+ be tick=10000, freq=0 (for a USER_HZ==100 system, other values otherwise).
+ The convention is that this is called with a positive argument if the local
clock runs fast when uncompensated. */
static double
set_frequency(double freq_ppm)
{
long required_tick;
- double required_freq; /* what we use */
- double scaled_freq; /* what adjtimex & the kernel use */
+ double required_freq;
int required_delta_tick;
required_delta_tick = our_round(freq_ppm / dhz);
+
+ /* Older kernels (pre-2.6.18) don't apply the frequency offset exactly as
+ set by adjtimex() and a scaling constant (that depends on the internal
+ kernel HZ constant) would be needed to compensate for the error. Because
+ chronyd is closed loop it doesn't matter much if we don't scale the
+ required frequency, but we want to prevent thrashing between two states
+ when the system's frequency error is close to a multiple of USER_HZ. With
+ USER_HZ <= 250, the maximum frequency adjustment of 500 ppm overlaps at
+ least two ticks and we can stick to the current tick if it's next to the
+ required tick. */
+ if (hz <= 250 && (required_delta_tick + 1 == current_delta_tick ||
+ required_delta_tick - 1 == current_delta_tick)) {
+ required_delta_tick = current_delta_tick;
+ }
+
required_freq = -(freq_ppm - dhz * required_delta_tick);
required_tick = nominal_tick - required_delta_tick;
- scaled_freq = freq_scale * required_freq;
- if (TMX_SetFrequency(&scaled_freq, required_tick) < 0) {
- LOG_FATAL(LOGF_SysLinux, "adjtimex failed for set_frequency, freq_ppm=%10.4e scaled_freq=%10.4e required_tick=%ld",
- freq_ppm, scaled_freq, required_tick);
+ if (TMX_SetFrequency(&required_freq, required_tick) < 0) {
+ LOG_FATAL(LOGF_SysLinux, "adjtimex failed for set_frequency, freq_ppm=%10.4e required_freq=%10.4e required_tick=%ld",
+ freq_ppm, required_freq, required_tick);
}
- return dhz * (nominal_tick - required_tick) - scaled_freq / freq_scale;
+ current_delta_tick = required_delta_tick;
+
+ return dhz * current_delta_tick - required_freq;
}
/* ================================================== */
static double
read_frequency(void)
{
- double tick_term;
- double unscaled_freq;
- double freq_term;
long tick;
+ double freq;
- if (TMX_GetFrequency(&unscaled_freq, &tick) < 0) {
+ if (TMX_GetFrequency(&freq, &tick) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
- tick_term = dhz * (double)(nominal_tick - tick);
- freq_term = unscaled_freq / freq_scale;
+ current_delta_tick = nominal_tick - tick;
-#if 0
- LOG(LOGS_INFO, LOGF_SysLinux, "txc.tick=%ld txc.freq=%ld tick_term=%f freq_term=%f",
- txc.tick, txc.freq, tick_term, freq_term);
-#endif
-
- return tick_term - freq_term;
+ return dhz * current_delta_tick - freq;
}
/* ================================================== */
/* ================================================== */
-/* Estimate the value of HZ given the value of txc.tick that chronyd finds when
+/* Estimate the value of USER_HZ given the value of txc.tick that chronyd finds when
* it starts. The only credible values are 100 (Linux/x86) or powers of 2.
* Also, the bounds checking inside the kernel's adjtimex system call enforces
- * a +/- 10% movement of tick away from the nominal value 1e6/HZ. */
+ * a +/- 10% movement of tick away from the nominal value 1e6/USER_HZ. */
static void
guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
{
int major, minor, patch;
int shift_hz;
- double dshift_hz;
- double basic_freq_scale; /* what to use if HZ!=100 */
- int config_hz, set_config_hz; /* values of HZ from conf file */
- int set_config_freq_scale;
- double config_freq_scale;
struct tmx_params tmx_params;
struct utsname uts;
}
}
- CNF_GetLinuxHz(&set_config_hz, &config_hz);
- if (set_config_hz) hz = config_hz;
- /* (If true, presumably freq_scale will be overridden anyway, making shift_hz
- redundant too.) */
-
dhz = (double) hz;
- dshift_hz = (double)(1UL << shift_hz);
- basic_freq_scale = dshift_hz / dhz;
nominal_tick = (1000000L + (hz/2))/hz; /* Mirror declaration in kernel */
max_tick_bias = nominal_tick / 10;
(CONFIG_NO_HZ aka tickless), assume the lowest commonly used fixed rate */
tick_update_hz = 100;
- /* The basic_freq_scale comes from:
- * the kernel increments the usec counter HZ times per second (if the timer
- interrupt period were perfect)
- * the following code in the kernel
-
- time_adj (+/-)= ltemp >>
- (SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE);
-
- causes the adjtimex 'freq' value to be divided down by 1<<SHIFT_HZ.
-
- The net effect is that we have to scale up the value we want by the
- reciprocal of all this, i.e. multiply by (1<<SHIFT_HZ)/HZ.
-
- If HZ==100, this code in the kernel comes into play too:
-#if HZ == 100
- * Compensate for (HZ==100) != (1 << SHIFT_HZ).
- * Add 25% and 3.125% to get 128.125; => only 0.125% error (p. 14)
- *
- if (time_adj < 0)
- time_adj -= (-time_adj >> 2) + (-time_adj >> 5);
- else
- time_adj += (time_adj >> 2) + (time_adj >> 5);
-#endif
-
- Special case that later.
- */
-
if (uname(&uts) < 0) {
LOG_FATAL(LOGF_SysLinux, "Cannot uname(2) to get kernel version, sorry.");
}
LOG_FATAL(LOGF_SysLinux, "Kernel version not supported, sorry.");
}
- if (kernelvercmp(major, minor, patch, 2, 6, 27) < 0) {
- freq_scale = (hz == 100) ? (128.0 / 128.125) : basic_freq_scale;
- } else {
- /* These don't seem to need scaling */
- freq_scale = 1.0;
-
- if (kernelvercmp(major, minor, patch, 2, 6, 33) < 0) {
- /* Tickless kernels before 2.6.33 accumulated ticks only in
- half-second intervals */
- tick_update_hz = 2;
- }
+ if (kernelvercmp(major, minor, patch, 2, 6, 27) >= 0 &&
+ kernelvercmp(major, minor, patch, 2, 6, 33) < 0) {
+ /* Tickless kernels before 2.6.33 accumulated ticks only in
+ half-second intervals */
+ tick_update_hz = 2;
}
/* ADJ_SETOFFSET support */
have_setoffset = 1;
}
- /* Override freq_scale if it appears in conf file */
- CNF_GetLinuxFreqScale(&set_config_freq_scale, &config_freq_scale);
- if (set_config_freq_scale) {
- freq_scale = config_freq_scale;
- }
-
- DEBUG_LOG(LOGF_SysLinux, "hz=%d shift_hz=%d freq_scale=%.8f nominal_tick=%d max_tick_bias=%d",
- hz, shift_hz, freq_scale, nominal_tick, max_tick_bias);
+ DEBUG_LOG(LOGF_SysLinux, "hz=%d nominal_tick=%d max_tick_bias=%d",
+ hz, nominal_tick, max_tick_bias);
}
/* ================================================== */