Commit 09fcca03 authored by Eric S. Raymond's avatar Eric S. Raymond

Introduction of ntpfrob. Collects what used to be in the following files:

util/jitter.c
util/pps-api.c
util/precision.c
util/testrs6000.c
util/ntptickadj.c
parent 84fadffb
......@@ -19,20 +19,20 @@ ntp=ntp
ntpd=ntpd
ntpdig=ntpdig
ntpdconf=ntpd.conf
ntpfrob=ntpfrob
ntpkeygen=ntpkeygen
ntpkeys=ntp.keys
ntpq=ntpq
ntptickadj=ntptickadj
ntptime=ntptime
ntpwait=ntpwait
# Annoyingly, these have to be *manually* synchronized with the headers
# on their manual pages - asciidoc doesn't expand attributes in header lines.
ntpdconfman=ntp.conf(5)
ntpfrobman=ntpfrob(8)
ntpkeygenman=ntpkeygen(8)
ntpkeysman=ntp.keys(5)
ntpdman=ntpd(8)
ntpqman=ntpq(1)
ntptickadjman=ntptickadj(8)
ntptimeman=ntptime(8)
ntpwaitman=ntpwait(8)
ntpdigman=ntpdig(1)
// This is the body of the manual page for ntpfrob.
// It's included in two places: once for the docs/ HTML
// tree, and once to make an individual man page.
== Synopsis ==
`{ntpfrob} [ -A ] [ -a tick ] [ -p ppsdev ] [-c] [-e] [-s]`
== Description ==
The {ntpfrob} program frobs the local clock hardware. It collects
several small diagnostic functions into a set that will differ
depending on your platform and underlying system calls.
Portions of it formerly traveled as `tickadj` and `ntptime`.
== Command Line Options ==
`-a` 'tick'::
Set the kernel variable `tick` to the value _tick_ specifies.
`-A`::
Display the kernel variable `tick`.
`-p` 'ppsdev'::
Look for PPS pulses on a specified device
`-c`::
Compute and display clock jitter.
`-e`::
Measure clock precision.
`-s`::
Check for stepback bug.
== Modes of operation ==
Documentation for some of these functions is scanty. If you suspect
you may need to use them, reading the source code may be wise.
=== Clock tick adjustment ===
The -A function reads your clock's tick rate in microseconds. The -a
function sets it. Both rely on the adjtimex(2) system call.
Tweaking your tick rate is almost never necessary on hardware new
enough to have a fully POSIX.1-2001-conformant Unix.
=== Clock jitter measurement ===
The -c option can be used to determine the timing jitter due to the
operating system in a gettimeofday() call. For most systems the
dominant contribution to the jitter budget is the period of the
hardware interrupt, usually in the range 10 us-1 ms. For those systems
with microsecond counters the jitter is dominated only by the
operating system.
=== Pulse-per-second check ==
The -p option shows whether the PPS-API (RFC 2783 kernel
PPS interface) finds PPS on a specified device.
=== Measure clock precision ===
The -e option measure the resolution of the system clock, watching how
the current time changes as we read it repeatedly.
=== Stepback bug check ===
The -s option checks for a bug originally seen on IBM RS/6000 AIX
machines. If a negative offset is given, the system gets messed up and
never completes the adjustment. If the problem is fixed, this program
will print the time, sit there for 10 seconds, and exit. If the
problem isn't fixed, the program will print an occasional
"result=nnnnnn" (the residual slew from adjtime()).
// end
// This is the body of the manual page for ntptickadj.
// It's included in two places: once for the docs/ HTML
// tree, and once to make an individual man page.
== Synopsis ==
`{ntptickadj} [ -Aqs ] [ -a tickadj ] [ -t tick ]`
== Description ==
The `{ntptickadj}` program (formerly named just `tickadj`) reads, and
optionally modifies, several timekeeping-related variables. It relies
on the adjtimex(2) system call.
These tweaks are almost never necessary on hardware new enough to have
a fully POSIX.1-2001-conformant Unix. This utility is deprecated and
exists mainly for backward compatibility to old scripts. In the future
it may be removed or merged into a more general tuning tool.
The particular variables that can be changed with `{ntptickadj}` include
`tick`, which is the number of microseconds added to the system time
for a clock interrupt, and possibly `tickadj`, which sets the slew
rate and resolution used by the `adjtime` system call. These should
be members of the `struct timex` that adjtimex(2) operates on.
By default, with no arguments, `{ntptickadj}` reads the `struct timex`
variable(s) of interest and displays them. At the same time, it
determines an "optimal" value for the value of the `tickadj` variable
if the intent is to run the Network Time Protocol (NTP) daemon,
and prints this as well. Since the operation of `{ntptickadj}` when reading
the kernel mimics the operation of similar parts of the `{ntpd}` program
fairly closely, this can be useful when debugging problems with
`{ntpd}`.
Note: The support this program formerly had for directly reading and
writing '/dev/kmem' dated from the last century; it has been removed
as unsafe and probably bitrotted.
== Theory of Operation ==
(This section was adapted from some configuration notes for very old Solaris
systems. Some portions, notably the claim about `tickadj` being too
large for NTP use, are probably no longer true.)
The NTP Version 4 specification calls for a maximum oscillator
frequency tolerance of +-500 parts-per-million (PPM).
In the rare case that this tolerance is violated, the performance may
be improved by adjusting the values of certain kernel variables; in
particular, `tick` and `tickadj`.
The variable `tick` is the increment in microseconds added to the system
time on each interval-timer interrupt, while the variable `tickadj` is
used by the time adjustment code as a slew rate, in microseconds per
tick. When the time is being adjusted via a call to the system routine
`adjtime()`, the kernel increases or reduces tick by `tickadj`
microseconds per tick until the specified adjustment has been completed.
Unfortunately, in most Unix implementations the tick increment must be
either zero or plus/minus exactly `tickadj` microseconds, meaning that
adjustments are truncated to be an integral multiple of `tickadj` (this
latter behaviour is a misfeature, and is the only reason the `{ntptickadj}`
code needs to concern itself with the internal implementation of
`tickadj` at all). In addition, the stock Unix implementation considers
it an error to request another adjustment before a prior one has
completed.
Thus, to make very sure it avoids problems related to the roundoff, the
`{ntptickadj}` program can be used to adjust the values of `tick` and
`tickadj`. This ensures that all adjustments given to `adjtime()` are an
even multiple of `tickadj` microseconds and computes the largest
adjustment that can be completed in the adjustment interval (using both
the value of `tick` and the value of `tickadj`) so it can avoid
exceeding this limit. It is important to note that not all systems will
allow inspection or modification of kernel variables other than at
system build time. It is also important to know that, with the current
NTP tolerances, it is rarely necessary to make these changes, but in
many cases they will substantially improve the general accuracy of the
time service.
Unfortunately, the value of `tickadj` set by default is almost always
too large for `{ntpd}`. NTP operates by continuously making small
adjustments to the clock, usually at one-second intervals. If `tickadj`
is set too large, the adjustments will disappear in the roundoff; while,
if `tickadj` is too small, NTP will have difficulty if it needs to make
an occasional large adjustment. While the daemon itself will read the
kernel's values of these variables, it will not change the values, even
if they are unsuitable. You must do this yourself before the daemon is
started using the `{ntptickadj}` program. Note that the latter program
will also compute an optimal value of `tickadj` for NTP use based on
the kernel's value of `tick`.
In order to maintain reasonable correctness bounds, as well as
reasonably good accuracy with acceptable polling intervals, `{ntpd}` will
complain if the frequency error is greater than 500 PPM. For machines
with a value of `tick` in the 10-ms range, a change of one in the value
of `tick` will change the frequency by about 100 PPM.
== Command Line Options ==
`-a` 'tickadj'::
Set the kernel variable `tickadj` to the value _tickadj_ specifies.
`-A`::
Set the kernel variable `tickadj` to an internally computed "optimal"
value.
`-t` 'tick'::
Set the kernel variable `tick` to the value _`tick`_ specified.
`-q`::
Normally, `{ntptickadj}` is quite verbose about what it is doing. The `-q`
flag tells it to shut up about everything except errors.
// end
= `ntptickadj` - set time-related kernel variables =
= `ntpfrob` - frob the local clock hardware =
include::includes/ntptickadj-body.txt
include::includes/ntpfrob-body.txt
'''''
......
......@@ -5,6 +5,9 @@
* reads the system clock and, finally, writes out the time values for
* later analysis. From this you can determine the jitter and if the
* clock ever runs backwards.
*
* Copyright 2015 by the NTPsec project contributors
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <config.h>
......@@ -55,11 +58,7 @@ get_clocktime(
now->l_uf = (uint32_t)dtemp;
}
int
main(
int argc,
char *argv[]
)
void jitter(void)
{
l_fp tr;
int i, j;
......@@ -109,7 +108,6 @@ main(
fprintf(stderr, "Last rank\n");
for (i = NBUF - 12; i < NBUF - 2; i++)
fprintf(stderr, "%2d %13.9f\n", i, gtod[i]);
exit(0);
}
/* end */
/* Copyright 2015 by the NTPsec project contributors
SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include "config.h"
/*
* Our methods, one per linked module
*/
extern void ppscheck(char *device);
extern void tickadj(const int tick);
extern void jitter(void);
extern void stepback(void);
extern void precision(void);
int
main(int argc, char **argv)
{
int ch;
while ((ch = getopt(argc, argv, "aA:cp:")) != EOF) {
switch (ch) {
case 'A':
#ifdef HAVE_ADJTIMEX
tickadj(0);
#else
fputs("ntpfrob: no adjtimex(2) call.\n", stderr);
exit(0);
#endif
break;
case 'a':
#ifdef HAVE_ADJTIMEX
tickadj(atoi(optarg));
#else
fputs("ntpfrob: no adjtimex(2) call.\n", stderr);
exit(0);
#endif
break;
case 'c':
jitter();
exit(0);
break;
case 'p':
#ifdef HAVE_SYS_TIMEPPS_H
ppscheck(optarg);
#else
fputs("ntpfrob: no PPS kernel interface.\n", stderr);
exit(0);
#endif
break;
}
}
exit(0);
}
= ntptickadj(8) =
= ntprob(8) =
:doctype: manpage
== NAME ==
{ntptickadj} - read and set kernel ticlk and tickadj variables
{ntpfrob} - frob the clock hardware
@../docs/includes/ntptickadj-body.txt@
@../docs/includes/ntpfrob-body.txt@
== EXIT STATUS ==
......
/*
Try to run this program to see what the PPS-API finds. You give it the
device as argument and you may have to modify the pp.mode = BLA assignment.
Poul-Henning
*/
*
* Try to run this code to see what the PPS-API finds. You give it the
* device as argument and you may have to modify the pp.mode = BLA assignment.
*
* Code originally by Poul-Henning Kemp.
*
* Copyright 2015 by the NTPsec project contributors
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdlib.h>
#include <stdio.h>
......@@ -45,12 +47,11 @@ Chew(struct timespec *tsa, struct timespec *tsc, unsigned sa, unsigned sc)
static int err(int out, const char *legend)
{
fprintf(stderr, "pps-api: %s\n", legend);
fprintf(stderr, "ntpfrob: %s\n", legend);
exit(out);
}
int
main(int argc, char **argv)
void ppscheck(char *device)
{
int fd;
pps_info_t pi;
......@@ -60,12 +61,12 @@ main(int argc, char **argv)
u_int olda, oldc;
struct timespec to;
if (argc < 2)
argv[1] = "/dev/cuaa1";
if (device == NULL)
device = "/dev/cuaa1";
setbuf(stdout, 0);
fd = open(argv[1], O_RDONLY);
fd = open(device, O_RDONLY);
if (fd < 0)
err(1, argv[1]);
err(1, device);
i = time_pps_create(fd, &ph);
if (i < 0)
err(1, "time_pps_create");
......@@ -99,6 +100,6 @@ main(int argc, char **argv)
olda = pi.assert_sequence;
oldc = pi.clear_sequence;
}
return(0);
}
/* end */
/*
* Copyright 2015 by the NTPsec project contributors
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "ntp_unixtime.h"
#include <stdio.h>
......@@ -7,16 +12,11 @@
int default_get_resolution();
int default_get_precision();
int
main(
int argc,
char *argv[]
)
void precision(void)
{
printf("log2(resolution) = %d, log2(precision) = %d\n",
default_get_resolution(),
default_get_precision());
return 0;
}
/* Find the resolution of the system clock by watching how the current time
......@@ -169,3 +169,5 @@ default_get_precision(void)
diff >>= 1;
return (i);
}
/* end */
......@@ -9,6 +9,9 @@
* the RS6000's day.
*
* Run this as root!
*
* Copyright 2015 by the NTPsec project contributors
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdlib.h>
#include <unistd.h>
......@@ -31,11 +34,7 @@ timeout(int sig)
}
}
int
main (
int argc,
char *argv[]
)
void stepback(void)
{
struct itimerval value, oldvalue;
int i;
......@@ -57,7 +56,5 @@ main (
for (i=0; i<10; i++) {
pause();
}
exit(0);
}
/*
* ntptickadj - read, and possibly modify, the kernel `tick' and
* tickadj - read, and possibly modify, the kernel `tick' and
* `tickadj' variables', using adjtimex(2). This is
* included only for compatibility with old scripts.
* and its former support for unsafe /dev/kmem operations
* has been removed.
*
* Copyright 2015 by the NTPsec project contributors
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <config.h>
......@@ -22,26 +25,18 @@
static struct timex txc;
int main(
int argc,
char *argv[]
)
void tickadj(const int newtick)
{
if (argc > 2)
{
fprintf(stderr, "Usage: %s [tick_value]\n", argv[0]);
exit(-1);
}
else if (argc == 2)
if (newtick != 0)
{
#ifdef STRUCT_TIMEX_HAS_TIME_TICK
if ( (txc.time_tick = atoi(argv[1])) < 1 )
if ( (txc.time_tick = newtick) < 1 )
#else
if ( (txc.tick = atoi(argv[1])) < 1 )
if ( (txc.tick = newtick) < 1 )
#endif
{
fprintf(stderr, "Silly value for tick: %s\n", argv[1]);
exit(-1);
fprintf(stderr, "ntpfrob: silly value for tick: %d\n", newtick);
exit(1);
}
#ifdef ADJ_TIMETICK
txc.modes = ADJ_TIMETICK;
......@@ -79,6 +74,5 @@ int main(
#endif
}
exit(0);
}
#endif
from waflib import Utils
def build(ctx):
srcnode = ctx.srcnode.abspath()
bldnode = ctx.bldnode.abspath()
frob_sources = ['main.c', 'jitter.c', 'precision.c', 'stepback.c']
# FIXME: These guards do not currebtly work
if ctx.get_define("HAVE_SYS_TIMEPPS_H"):
frob_sources += ["pps-api.c"]
if ctx.get_define("HAVE_ADJTIMEX"):
frob_sources += ["tickadj.c"]
ctx(
target = "ntpfrob",
features = "c cprogram bld_include src_include libisc_include",
source = frob_sources,
includes = [
"%s/ntpfrob/" % bldnode
],
use = "ntp opts isc M RT PTHREAD",
install_path = "${PREFIX}/bin/"
)
......@@ -16,14 +16,6 @@ hist.c::
analysis. From this you can determine the jitter and if the clock ever
runs backwards.
jitter.c::
Can be used to determine the timing jitter due to
the operating system in a gettimeofday() call. For most systems the
dominant contribution to the jitter budget is the period of the hardware
interrupt, usually in the range 10 us-1 ms. For those systems with
microsecond counters, such as recent Sun and certain HP and DEC systems,
the jitter is dominated only by the operating system.
kern.c::
Header comment from deep in the mists of past time says: "This
program simulates a first-order, type-II phase-lock loop using
......@@ -33,12 +25,12 @@ kern.c::
supposed to be used for should explain it to us, please.
ntptime.c::
Checks the kernel configuration for the NTP user
interface syscalls ntp_gettime() and ntp_adjtime(). If present, the
current timekeeping data are displayed. If not, a dissapointment is
Checks the kernel configuration for the NTP user interface
syscalls ntp_gettime() and ntp_adjtime(). If present, the current
timekeeping data are displayed. If not, a disappointment is
displayed. See the kernel page file in the HTML documentation in
distribution for further details. ntptime will be built be if configure
believes your system can use it.
distribution for further details. ntptime will be built if the
configuration system believes your platform can use it.
propdelay.c::
Computes high frequency propagation delays, given the
......@@ -46,30 +38,9 @@ propdelay.c::
this for WWV/H and CHU. Don't use it for WWVB (the computation
is easier for that).
pps-api.c::
Try to run this program to see what the PPS-API (RFC 2783 kernel
PPS interface) finds. You give it the device as argument and you
may have to modify the pp.mode = BLA assignment.
precision.c::
Measure the resolution of the system clock watching how the current time
changes as we read it repeatedly.
sht.c::
Test program for shared memory refclock.
testrs6000.c::
The testrs6000.c program is used for testing purposes with the IBM
RS/6000 AIX machines. Bill Jones <jones@chpc.utexas.edu> reports:
"I could not get a tickadj of less than 40 us to work on a RS6000.
If you set it less than 40 us do so at your own risk!" The RS6000
is dead, but this is kept around as a way to bogon-test other kernels.
ntptickadj.c::
Can be used to read and set various kernel parameters affecting NTP
operations. See the tickadj page in the HTML documentation for further
details.
tg.c and tg2.c::
These are tone generators. They make audio signals that emulate WWV
or IRIG (-B and -E). tg runs on Solaris. tg2 is a clone that runs on
......
......@@ -4,14 +4,10 @@ def build(ctx):
srcnode = ctx.srcnode.abspath()
bldnode = ctx.bldnode.abspath()
util = ['hist', 'jitter', 'precision', 'propdelay',
'sht', 'testrs6000', 'tg2']
util = ['hist', 'propdelay', 'sht', 'tg2']
if ctx.env.PLATFORM_TARGET != "freebsd": # XXX: fix this using a test in configure().
util += ["pps-api", "ntptime"]
if ctx.env.HAVE_ADJTIMEX:
util += ["ntptickadj"]
util += ["ntptime"]
for name in util:
ctx(
......
......@@ -100,6 +100,7 @@ def build(ctx):
ctx.recurse("libntp")
ctx.recurse("ntpdig")
ctx.recurse("ntpd")
ctx.recurse("ntpfrob")
ctx.recurse("ntpq")
# ctx.recurse("clockstuff") -
# ctx.recurse("kernel")
......@@ -131,7 +132,7 @@ def build(ctx):
"scripts/ntpwait/ntpwait-man.txt.in",
"scripts/ntptrace/ntptrace-man.txt.in",
"ntpdig/ntpdig-man.txt.in",
"util/ntptickadj-man.txt.in",
"ntpfrob/ntpfrob-man.txt.in",
"util/ntptime-man.txt.in",
]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment