Add mlockall and SCHED_FIFO support
The attached patch adds support for mlockall() as well as the SCHED_FIFO real-time scheduler. It should result in reduced (and more consistent) latency. Usage is documented in all the documents.
This commit is contained in:
parent
cdc22df903
commit
35e662d810
11 changed files with 258 additions and 2 deletions
56
chrony.texi
56
chrony.texi
|
@ -1088,13 +1088,19 @@ useful for dial-up systems that are shut down when not in use. For this
|
|||
to work well, it relies on @code{chronyd} having been able to determine
|
||||
accurate statistics for the difference between the real time clock and
|
||||
system clock last time the computer was on.
|
||||
|
||||
@item -u <user>
|
||||
When this option is used, chronyd will drop root privileges to the specified
|
||||
user. So far, it works only on Linux when compiled with capabilities support.
|
||||
@item -v
|
||||
This option displays @code{chronyd's} version number to the terminal and
|
||||
exits.
|
||||
@item -P <priority>
|
||||
This option will select the SCHED_FIFO real-time scheduler at the
|
||||
specified priority (which must be between 0 and 100). This mode is
|
||||
supported only on Linux.
|
||||
@item -m
|
||||
This option will lock chronyd into RAM so that it will never be paged
|
||||
out. This mode is only supported on Linux.
|
||||
@end table
|
||||
|
||||
On systems that support an @file{/etc/rc.local} file for starting
|
||||
|
@ -1187,6 +1193,9 @@ directives can occur in any order in the file.
|
|||
* rtcfile directive:: Specify the file where real-time clock data is stored
|
||||
* rtconutc directive:: Specify that the real time clock keeps UTC not local time
|
||||
* server directive:: Specify an NTP server
|
||||
* sched_priority directive:: Require real-time scheduling and specify a priority for it.
|
||||
* lock_all directive:: Require that chronyd be locked into RAM.
|
||||
|
||||
@end menu
|
||||
@c }}}
|
||||
@c {{{ comments in config file
|
||||
|
@ -2177,6 +2186,37 @@ If the @code{rtconutc} directive appears, it means the RTC is required
|
|||
to keep UTC. The directive takes no arguments. It is equivalent to
|
||||
specifying the @code{-u} switch to the Linux @file{/sbin/clock} program.
|
||||
@c }}}
|
||||
@c {{{ sched_priority
|
||||
@node sched_priority directive
|
||||
@subsection sched_priority
|
||||
|
||||
The @code{sched_priority} directive will select the SCHED_FIFO real-time
|
||||
scheduler at the specified priority (which must be between 0 and 100).
|
||||
This mode is supported only on Linux.
|
||||
|
||||
This directive uses the Linux sched_setscheduler() system call to
|
||||
instruct the kernel to use the SCHED_FIFO first-in, first-out
|
||||
real-time scheduling policy for Chronyd with the specified priority.
|
||||
This means that whenever Chronyd is ready to run it will run,
|
||||
interrupting whatever else is running unless it is a higher priority
|
||||
real-time process. This should not impact performance as Chronyd's
|
||||
resource requirements are modest, but it should result in lower and
|
||||
more consistent latency since Chronyd will not need to wait for the
|
||||
scheduler to get around to running it. You should not use this unless
|
||||
you really need it. The sched_setscheduler man page has more details.
|
||||
@c }}}
|
||||
@c {{{ lock_all
|
||||
@node lock_all directive
|
||||
@subsection lock_all
|
||||
|
||||
The @code{lock_all} directive will lock chronyd into RAM so that it
|
||||
will never be paged out. This mode is only supported on Linux. This
|
||||
directive uses the Linux mlockall() system call to prevent Chronyd
|
||||
from ever being swapped out. This should result in lower and more
|
||||
consistent latency. It should not have significant impact on
|
||||
performance as Chronyd's memory usage is modest. The mlockall man
|
||||
page has more details.
|
||||
@c }}}
|
||||
@c {{{ server
|
||||
@node server directive
|
||||
@subsection server
|
||||
|
@ -2287,6 +2327,20 @@ chrony when disconnecting the dial-up link. (It will still be necessary to use
|
|||
chronyc's @code{online} (@pxref{online command}) command when the link has been
|
||||
established, to enable measurements to start.)
|
||||
|
||||
@item sched_priority
|
||||
This directive tells chronyd to use the real-time FIFO scheduler with the
|
||||
specified priority (which must be between 0 and 100). This should result
|
||||
in reduced latency. You don't need it unless you really have a requirement
|
||||
for extreme clock stability. Works only on Linux. Note that the "-P"
|
||||
command-line switch will override this.
|
||||
|
||||
@item lock_all
|
||||
This directive tells chronyd to use the mlockall() syscall to lock itself
|
||||
into RAM so that it will never be paged out. This should result in reduced
|
||||
latency. You don't need it unless you really have a requirement
|
||||
for extreme clock stability. Works only on Linux. Note that the "-m"
|
||||
command-line switch will also enable this feature.
|
||||
|
||||
@end table
|
||||
@c }}}
|
||||
@c }}}
|
||||
|
|
|
@ -35,6 +35,15 @@ Information messages and warnings will be logged to syslog.
|
|||
.SH OPTIONS
|
||||
A summary of the options supported by \fBchronyd\fR is included below.
|
||||
|
||||
.TP
|
||||
\fB\-P\fR \fIpriority\fR
|
||||
This option will select the SCHED_FIFO real-time scheduler at the specified
|
||||
priority (which must be between 0 and 100). This mode is supported only on
|
||||
Linux.
|
||||
.TP
|
||||
.B \-m
|
||||
This option will lock chronyd into RAM so that it will never be paged out.
|
||||
This mode is only supported on Linux.
|
||||
.TP
|
||||
.B \-d
|
||||
When run in this mode, the program will not detach itself from the
|
||||
|
|
36
conf.c
36
conf.c
|
@ -93,6 +93,14 @@ static void parse_broadcast(const char *);
|
|||
static void parse_linux_hz(const char *);
|
||||
static void parse_linux_freq_scale(const char *);
|
||||
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
static void parse_sched_priority(const char *);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MLOCKALL)
|
||||
static void parse_lockall(const char *);
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
/* Configuration variables */
|
||||
|
||||
|
@ -209,6 +217,14 @@ static const Command commands[] = {
|
|||
{"broadcast", 9, parse_broadcast},
|
||||
{"linux_hz", 8, parse_linux_hz},
|
||||
{"linux_freq_scale", 16, parse_linux_freq_scale}
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
,{"sched_priority", 14, parse_sched_priority}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MLOCKALL)
|
||||
,{"lock_all", 8, parse_lockall}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
static int n_commands = (sizeof(commands) / sizeof(commands[0]));
|
||||
|
@ -365,6 +381,26 @@ parse_source(const char *line, NTP_Source_Type type)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
static void
|
||||
parse_sched_priority(const char *line)
|
||||
{
|
||||
if (SchedPriority == 0) { /* Command-line switch must have priority */
|
||||
sscanf(line, "%d", &SchedPriority);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MLOCKALL)
|
||||
static void
|
||||
parse_lockall(const char *line)
|
||||
{
|
||||
LockAll = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_server(const char *line)
|
||||
{
|
||||
|
|
8
conf.h
8
conf.h
|
@ -71,4 +71,12 @@ extern int CNF_AllowLocalReference(int *stratum);
|
|||
|
||||
extern void CNF_SetupAccessRestrictions(void);
|
||||
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
extern int SchedPriority;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MLOCKALL)
|
||||
extern int LockAll;
|
||||
#endif
|
||||
|
||||
#endif /* GOT_CONF_H */
|
||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -257,7 +257,7 @@ case $SYSTEM in
|
|||
EXTRA_DEFS+=" -DFEAT_LINUXCAPS=1"
|
||||
EXTRA_LIBS="-lcap"
|
||||
fi
|
||||
SYSDEFS="-DLINUX"
|
||||
SYSDEFS="-DLINUX -DHAVE_SCHED_SETSCHEDULER -DHAVE_MLOCKALL"
|
||||
echo "Configuring for " $SYSTEM
|
||||
if [ "${MACHINE}" = "alpha" ]; then
|
||||
echo "Enabling -mieee"
|
||||
|
|
|
@ -287,3 +287,21 @@ cmdallow 127.0.0.1
|
|||
! rtcdevice /dev/misc/rtc
|
||||
|
||||
#######################################################################
|
||||
### REAL TIME SCHEDULER
|
||||
# This directive tells chronyd to use the real-time FIFO scheduler with the
|
||||
# specified priority (which must be between 0 and 100). This should result
|
||||
# in reduced latency. You don't need it unless you really have a requirement
|
||||
# for extreme clock stability. Works only on Linux. Note that the "-P"
|
||||
# command-line switch will override this.
|
||||
|
||||
! sched_priority 1
|
||||
|
||||
#######################################################################
|
||||
### LOCKING CHRONYD INTO RAM
|
||||
# This directive tells chronyd to use the mlockall() syscall to lock itself
|
||||
# into RAM so that it will never be paged out. This should result in reduced
|
||||
# latency. You don't need it unless you really have a requirement
|
||||
# for extreme clock stability. Works only on Linux. Note that the "-m"
|
||||
# command-line switch will also enable this feature.
|
||||
|
||||
! lock_all
|
||||
|
|
44
main.c
44
main.c
|
@ -25,6 +25,16 @@
|
|||
|
||||
=======================================================================
|
||||
|
||||
2009-1-28 John G. Hasler <jhasler@debian.org>
|
||||
|
||||
Added real-time support (Linux only) using sched_setscheduler() and
|
||||
mlockall(). Files affected: main.c, conf.c, sys.c, sys_linux.c,
|
||||
conf.h, configure, chronyd.8, chrony.texi, and
|
||||
examples/chrony.conf.example. The changes are licensed under
|
||||
version 2 of the GPL as described above.
|
||||
|
||||
=======================================================================
|
||||
|
||||
The main program
|
||||
*/
|
||||
|
||||
|
@ -211,6 +221,10 @@ int main
|
|||
int do_init_rtc = 0;
|
||||
int other_pid;
|
||||
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
int return_value = 0;
|
||||
#endif
|
||||
|
||||
LOG_Initialise();
|
||||
|
||||
/* Parse command line options */
|
||||
|
@ -219,6 +233,24 @@ int main
|
|||
if (!strcmp("-f", *argv)) {
|
||||
++argv, --argc;
|
||||
conf_file = *argv;
|
||||
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
/* Get real-time scheduler priority */
|
||||
} else if (!strcmp("-P", *argv)) {
|
||||
++argv, --argc;
|
||||
return_value = sscanf(*argv, "%d", &SchedPriority);
|
||||
if (return_value != 1 || SchedPriority < 1 || SchedPriority > 99) {
|
||||
SchedPriority = 0;
|
||||
LOG(LOGS_WARN, LOGF_Main, "Bad scheduler priority: [%s]", *argv);
|
||||
}
|
||||
#endif /* HAVE_SCHED_SETCHEDULER */
|
||||
|
||||
#if defined(HAVE_MLOCKALL)
|
||||
/* Detect lockall switch */
|
||||
} else if (!strcmp("-m", *argv)) {
|
||||
LockAll = 1;
|
||||
#endif /* HAVE_MLOCKALL */
|
||||
|
||||
} else if (!strcmp("-r", *argv)) {
|
||||
reload = 1;
|
||||
} else if (!strcmp("-u", *argv)) {
|
||||
|
@ -307,6 +339,18 @@ int main
|
|||
signal(SIGHUP, signal_cleanup);
|
||||
#endif /* WINNT */
|
||||
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
if (SchedPriority > 0) {
|
||||
SYS_SetScheduler(SchedPriority);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MLOCKALL)
|
||||
if (LockAll == 1 ) {
|
||||
SYS_MemLockAll(LockAll);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The program normally runs under control of the main loop in
|
||||
the scheduler. */
|
||||
SCH_MainLoop();
|
||||
|
|
17
sys.c
17
sys.c
|
@ -106,6 +106,23 @@ void SYS_DropRoot(char *user)
|
|||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void SYS_SetScheduler(int SchedPriority)
|
||||
{
|
||||
#if defined(LINUX) && defined(HAVE_SCHED_SETSCHEDULER)
|
||||
SYS_Linux_SetScheduler(SchedPriority);
|
||||
#endif
|
||||
;;
|
||||
}
|
||||
|
||||
void SYS_MemLockAll(int LockAll)
|
||||
{
|
||||
#if defined(LINUX) && defined(HAVE_MLOCKALL)
|
||||
SYS_Linux_MemLockAll(LockAll);
|
||||
#endif
|
||||
;;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
||||
|
|
3
sys.h
3
sys.h
|
@ -42,4 +42,7 @@ extern void SYS_Finalise(void);
|
|||
/* Drop root privileges to the specified user */
|
||||
extern void SYS_DropRoot(char *user);
|
||||
|
||||
extern void SYS_SetScheduler(int SchedPriority);
|
||||
extern void SYS_MemLockAll(int LockAll);
|
||||
|
||||
#endif /* GOT_SYS_H */
|
||||
|
|
63
sys_linux.c
63
sys_linux.c
|
@ -39,6 +39,17 @@
|
|||
#include <assert.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
# include <sched.h>
|
||||
int SchedPriority = 0;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MLOCKALL)
|
||||
# include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
int LockAll = 0;
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_LINUXCAPS
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
@ -898,6 +909,58 @@ SYS_Linux_DropRoot(char *user)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(HAVE_SCHED_SETSCHEDULER)
|
||||
/* Install SCHED_FIFO real-time scheduler with specified priority */
|
||||
void SYS_Linux_SetScheduler(int SchedPriority)
|
||||
{
|
||||
int pmax, pmin;
|
||||
struct sched_param sched;
|
||||
|
||||
if (SchedPriority > 0) {
|
||||
sched.sched_priority = SchedPriority;
|
||||
pmax = sched_get_priority_max(SCHED_FIFO);
|
||||
pmin = sched_get_priority_min(SCHED_FIFO);
|
||||
if ( SchedPriority > pmax ) {
|
||||
sched.sched_priority = pmax;
|
||||
}
|
||||
else if ( SchedPriority < pmin ) {
|
||||
sched.sched_priority = pmin;
|
||||
}
|
||||
if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 ) {
|
||||
LOG(LOGS_ERR, LOGF_SysLinux, "sched_setscheduler() failed");
|
||||
}
|
||||
else {
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "Enabled SCHED_FIFO with priority %d", sched.sched_priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SCHED_SETSCHEDULER */
|
||||
|
||||
#if defined(HAVE_MLOCKALL)
|
||||
/* Lock the process into RAM so that it will never be swapped out */
|
||||
void SYS_Linux_MemLockAll(int LockAll)
|
||||
{
|
||||
struct rlimit rlim;
|
||||
if (LockAll == 1 ) {
|
||||
/* Make sure that we will be able to lock all the memory we need */
|
||||
/* even after dropping privileges. This does not actually reaerve any memory */
|
||||
rlim.rlim_max = RLIM_INFINITY;
|
||||
rlim.rlim_cur = RLIM_INFINITY;
|
||||
if (setrlimit(RLIMIT_MEMLOCK, &rlim) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysLinux, "setrlimit() failed: not locking into RAM");
|
||||
}
|
||||
else {
|
||||
if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysLinux, "mlockall() failed");
|
||||
}
|
||||
else {
|
||||
LOG(LOGS_INFO, LOGF_SysLinux, "Successfully locked into RAM");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_MLOCKALL */
|
||||
|
||||
#endif /* LINUX */
|
||||
|
||||
/* vim:ts=8
|
||||
|
|
|
@ -39,4 +39,8 @@ extern void SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel);
|
|||
|
||||
extern void SYS_Linux_DropRoot(char *user);
|
||||
|
||||
extern void SYS_Linux_MemLockAll(int LockAll);
|
||||
|
||||
extern void SYS_linux_SetScheduler(int SchedPriority);
|
||||
|
||||
#endif /* GOT_SYS_LINUX_H */
|
||||
|
|
Loading…
Reference in a new issue