sys_macosx: add option to run chronyd as real-time process

Adds option -P to chronyd on MacOS X which can be used to enable the
thread time constraint scheduling policy. This near real-time scheduling
policy removes a 1usec bias from the 'System time' offset.
This commit is contained in:
Bryan Christianson 2015-08-25 08:32:14 +12:00 committed by Miroslav Lichvar
parent 5039f959e0
commit b9cfdaf666
5 changed files with 78 additions and 13 deletions

View file

@ -1039,9 +1039,11 @@ not correct the clock.
This option displays @code{chronyd's} version number to the terminal and This option displays @code{chronyd's} version number to the terminal and
exits. exits.
@item -P <priority> @item -P <priority>
This option will select the SCHED_FIFO real-time scheduler at the On Linux, this option will select the SCHED_FIFO real-time scheduler at the
specified priority (which must be between 0 and 100). This mode is specified priority (which must be between 0 and 100). On Mac OS X, this option
supported only on Linux. must have either a value of 0 (the default) to disable the thread time
constraint policy or 1 for the policy to be enabled. Other systems do not
support this option.
@item -m @item -m
This option will lock chronyd into RAM so that it will never be paged This option will lock chronyd into RAM so that it will never be paged
out. This mode is only supported on Linux. out. This mode is only supported on Linux.
@ -2910,13 +2912,15 @@ is used.
@node sched_priority directive @node sched_priority directive
@subsection sched_priority @subsection sched_priority
The @code{sched_priority} directive will select the SCHED_FIFO real-time On Linux, the @code{sched_priority} directive will select the SCHED_FIFO
scheduler at the specified priority (which must be between 0 and 100). real-time scheduler at the specified priority (which must be between 0 and
This mode is supported only on Linux. 100). On Mac OS X, this option must have either a value of 0 (the default) to
disable the thread time constraint policy or 1 for the policy to be enabled.
Other systems do not support this option.
This directive uses the Linux sched_setscheduler() system call to On Linux, this directive uses the sched_setscheduler() system call to instruct
instruct the kernel to use the SCHED_FIFO first-in, first-out the kernel to use the SCHED_FIFO first-in, first-out real-time scheduling
real-time scheduling policy for @code{chronyd} with the specified priority. policy for @code{chronyd} with the specified priority.
This means that whenever @code{chronyd} is ready to run it will run, This means that whenever @code{chronyd} is ready to run it will run,
interrupting whatever else is running unless it is a higher priority interrupting whatever else is running unless it is a higher priority
real-time process. This should not impact performance as @code{chronyd's} real-time process. This should not impact performance as @code{chronyd's}
@ -2924,6 +2928,10 @@ resource requirements are modest, but it should result in lower and
more consistent latency since @code{chronyd} will not need to wait for the more consistent latency since @code{chronyd} will not need to wait for the
scheduler to get around to running it. You should not use this unless 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. you really need it. The sched_setscheduler man page has more details.
On Mac OS X, this directive uses the thread_policy_set() kernel call to specify
real-time scheduling. As noted for Linux, you should not use this directive
unless you really need it.
@c }}} @c }}}
@c {{{ server @c {{{ server
@node server directive @node server directive

View file

@ -40,9 +40,11 @@ A summary of the options supported by \fBchronyd\fR is included below.
.TP .TP
\fB\-P\fR \fIpriority\fR \fB\-P\fR \fIpriority\fR
This option will select the SCHED_FIFO real-time scheduler at the specified On Linux, this option will select the SCHED_FIFO real-time scheduler at the
priority (which must be between 0 and 100). This mode is supported only on specified priority (which must be between 0 and 100). On Mac OS X, this
Linux. option must have either a value of 0 (the default) to disable the thread
time constraint policy or 1 for the policy to be enabled. Other systems do not
support this option.
.TP .TP
.B \-m .B \-m
This option will lock chronyd into RAM so that it will never be paged out. This option will lock chronyd into RAM so that it will never be paged out.

2
sys.c
View file

@ -126,6 +126,8 @@ void SYS_SetScheduler(int SchedPriority)
{ {
#if defined(LINUX) && defined(HAVE_SCHED_SETSCHEDULER) #if defined(LINUX) && defined(HAVE_SCHED_SETSCHEDULER)
SYS_Linux_SetScheduler(SchedPriority); SYS_Linux_SetScheduler(SchedPriority);
#elif defined(MACOSX)
SYS_MacOSX_SetScheduler(SchedPriority);
#else #else
LOG_FATAL(LOGF_Sys, "scheduler priority setting not supported"); LOG_FATAL(LOGF_Sys, "scheduler priority setting not supported");
#endif #endif

View file

@ -42,6 +42,10 @@
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <pthread.h>
#include "sys_macosx.h" #include "sys_macosx.h"
#include "localp.h" #include "localp.h"
#include "sched.h" #include "sched.h"
@ -85,6 +89,8 @@ static struct timeval Tdrift;
/* minimum resolution of current_frequency */ /* minimum resolution of current_frequency */
#define FREQUENCY_RES (1.0e-9) #define FREQUENCY_RES (1.0e-9)
#define NANOS_PER_MSEC (1000000ULL)
/* ================================================== */ /* ================================================== */
static void static void
@ -334,6 +340,53 @@ drift_removal_timeout(SCH_ArbitraryArgument not_used)
drift_removal_id = SCH_AddTimeoutByDelay(drift_removal_interval, drift_removal_timeout, NULL); drift_removal_id = SCH_AddTimeoutByDelay(drift_removal_interval, drift_removal_timeout, NULL);
} }
/* ================================================== */
/*
Give chronyd real time priority so that time critical calculations
are not pre-empted by the kernel.
*/
static int
set_realtime(void)
{
/* https://developer.apple.com/library/ios/technotes/tn2169/_index.html */
mach_timebase_info_data_t timebase_info;
double clock2abs;
thread_time_constraint_policy_data_t policy;
int kr;
mach_timebase_info(&timebase_info);
clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
policy.period = 0;
policy.computation = (uint32_t)(5 * clock2abs); /* 5 ms of work */
policy.constraint = (uint32_t)(10 * clock2abs);
policy.preemptible = 0;
kr = thread_policy_set(
pthread_mach_thread_np(pthread_self()),
THREAD_TIME_CONSTRAINT_POLICY,
(thread_policy_t)&policy,
THREAD_TIME_CONSTRAINT_POLICY_COUNT);
if (kr != KERN_SUCCESS) {
LOG(LOGS_WARN, LOGF_SysMacOSX, "Cannot set real-time priority: %d", kr);
return -1;
}
return 0;
}
/* ================================================== */
void
SYS_MacOSX_SetScheduler(int SchedPriority)
{
if (SchedPriority) {
set_realtime();
}
}
/* ================================================== */ /* ================================================== */
void void

View file

@ -30,8 +30,8 @@
#ifndef GOT_SYS_MACOSX_H #ifndef GOT_SYS_MACOSX_H
#define GOT_SYS_MACOSX_H #define GOT_SYS_MACOSX_H
void SYS_MacOSX_SetScheduler(int SchedPriority);
void SYS_MacOSX_Initialise(void); void SYS_MacOSX_Initialise(void);
void SYS_MacOSX_Finalise(void); void SYS_MacOSX_Finalise(void);
#endif #endif