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:
John Hasler 2009-02-10 17:59:57 +01:00 committed by Miroslav Lichvar
parent cdc22df903
commit 35e662d810
11 changed files with 258 additions and 2 deletions

View file

@ -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 }}}

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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"

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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 */

View file

@ -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

View file

@ -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 */