[pkg-ntp-maintainers] ntp: don't wake up every second

Serge E. Hallyn serge.hallyn at canonical.com
Tue Jan 18 17:41:20 UTC 2011


Hi,

A patch (based on a Fedora patch which was rejected by the ntp upstream)
was submitted against the Ubuntu ntp package, to reduce the number of
wakeups for the sake of power savings.  I was wondering whether you
deemed this suitable for the Debian package.  I'm afraid I'm not
qualified to comment on the patch's correctness myself, though at least
it does build and run.  The debdiff against the Debian sid ntp package
is appended below, and the original patch submission for Ubuntu was at:
https://bugs.launchpad.net/ubuntu/+source/ntp/+bug/697676

The description from the submitter was:

> The current design of ntp makes it generate at least 1 wakeup/second,
> thus disallowing the CPU to enter deeper states of sleep [1].
> 
> I propose applying a patch from Fedora which solves this issue. Previous
> attempts at integrating it upstream failed [2], despite the fact that
> the patch is used in Fedora for a long time. Hopefully, with the
> increasing need for energy efficient computing and Ubuntu validating the
> approach, upstream will be more willing to integrate the fix.

thanks,
-serge

diff -Nru ntp-4.2.6.p2+dfsg/debian/changelog ntp-4.2.6.p2+dfsg/debian/changelog
--- ntp-4.2.6.p2+dfsg/debian/changelog	2010-07-13 13:33:53.000000000 -0500
+++ ntp-4.2.6.p2+dfsg/debian/changelog	2011-01-18 09:46:29.000000000 -0600
@@ -1,3 +1,10 @@
+ntp (1:4.2.6.p2+dfsg-1polar1) natty; urgency=low
+
+  * Incorporate patch (by cristiklein at gmail.com and based on a patch in Fedora)
+    to not necessarily wake up every second.  (LP: #697676)
+
+ -- Serge Hallyn <serge.hallyn at ubuntu.com>  Tue, 18 Jan 2011 09:42:37 -0600
+
 ntp (1:4.2.6.p2+dfsg-1) unstable; urgency=low
 
   [ Peter Eisentraut ]
diff -Nru ntp-4.2.6.p2+dfsg/debian/patches/ntpd-sleep.patch ntp-4.2.6.p2+dfsg/debian/patches/ntpd-sleep.patch
--- ntp-4.2.6.p2+dfsg/debian/patches/ntpd-sleep.patch	1969-12-31 19:00:00.000000000 -0500
+++ ntp-4.2.6.p2+dfsg/debian/patches/ntpd-sleep.patch	2011-01-18 09:42:09.000000000 -0600
@@ -0,0 +1,507 @@
+From: cristiklein at gmail.com 
+Description: Promote power savings by not waking up every second.
+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ntp/+bug/697676
+
+Index: ntp-4.2.6.p2+dfsg/include/ntp_refclock.h
+===================================================================
+--- ntp-4.2.6.p2+dfsg.orig/include/ntp_refclock.h	2009-12-09 01:36:35.000000000 -0600
++++ ntp-4.2.6.p2+dfsg/include/ntp_refclock.h	2011-01-18 09:35:20.658203002 -0600
+@@ -260,6 +260,7 @@
+ 				    struct refclockstat *);
+ extern	int	refclock_open	(char *, u_int, u_int);
+ extern	int	refclock_setup	(int, u_int, u_int);
++extern	int	refclock_timer_needed	(struct peer *);
+ extern	void	refclock_timer	(struct peer *);
+ extern	void	refclock_transmit (struct peer *);
+ extern	int	refclock_ioctl	(int, u_int);
+Index: ntp-4.2.6.p2+dfsg/include/ntp_stdlib.h
+===================================================================
+--- ntp-4.2.6.p2+dfsg.orig/include/ntp_stdlib.h	2010-06-03 01:05:26.000000000 -0500
++++ ntp-4.2.6.p2+dfsg/include/ntp_stdlib.h	2011-01-18 09:35:20.662203002 -0600
+@@ -117,6 +117,7 @@
+ extern	void	signal_no_reset (int, RETSIGTYPE (*func)(int));
+ 
+ extern	void	getauthkeys 	(const char *);
++extern	int	auth_agekeys_needed (void);
+ extern	void	auth_agekeys	(void);
+ extern	void	rereadkeys	(void);
+ 
+Index: ntp-4.2.6.p2+dfsg/include/ntpd.h
+===================================================================
+--- ntp-4.2.6.p2+dfsg.orig/include/ntpd.h	2011-01-18 09:33:45.000000000 -0600
++++ ntp-4.2.6.p2+dfsg/include/ntpd.h	2011-01-18 09:35:20.662203002 -0600
+@@ -113,8 +113,10 @@
+ /* ntp_loopfilter.c */
+ extern	void	init_loopfilter(void);
+ extern	int 	local_clock(struct peer *, double);
+-extern	void	adj_host_clock(void);
++extern	int	adj_host_clock_needed(void);
++extern	void	adj_host_clock(int);
+ extern	void	loop_config(int, double);
++extern	int	huffpuff_enabled(void);
+ extern	void	huffpuff(void);
+ extern	u_long	sys_clocktime;
+ extern	u_int	sys_tai;
+@@ -220,6 +222,8 @@
+ /* ntp_timer.c */
+ extern	void	init_timer	(void);
+ extern	void	reinit_timer	(void);
++extern	double	get_timeout	(l_fp *);
++extern	int	timer_elapsed	(l_fp, int);
+ extern	void	timer		(void);
+ extern	void	timer_clr_stats (void);
+ extern  void    timer_interfacetimeout (u_long);
+Index: ntp-4.2.6.p2+dfsg/libntp/authkeys.c
+===================================================================
+--- ntp-4.2.6.p2+dfsg.orig/libntp/authkeys.c	2009-12-09 01:36:35.000000000 -0600
++++ ntp-4.2.6.p2+dfsg/libntp/authkeys.c	2011-01-18 09:35:20.662203002 -0600
+@@ -445,6 +445,25 @@
+ 	}
+ }
+ 
++int
++auth_agekeys_needed(void) {
++	struct savekey *sk;
++	int i;
++
++	if (authnumkeys > 20)
++		return 1;
++
++	for (i = 0; i < HASHSIZE; i++) {
++		sk = key_hash[i];
++		while (sk != 0) {
++			if (sk->lifetime > 0)
++				return 1;
++			sk = sk->next;
++		}
++	}
++	return 0;
++}
++
+ /*
+  * auth_agekeys - delete keys whose lifetimes have expired
+  */
+Index: ntp-4.2.6.p2+dfsg/ntpd/ntp_loopfilter.c
+===================================================================
+--- ntp-4.2.6.p2+dfsg.orig/ntpd/ntp_loopfilter.c	2011-01-18 09:33:45.000000000 -0600
++++ ntp-4.2.6.p2+dfsg/ntpd/ntp_loopfilter.c	2011-01-18 09:35:20.662203002 -0600
+@@ -675,6 +675,13 @@
+ #endif /* LOCKCLOCK */
+ }
+ 
++int
++adj_host_clock_needed(void)
++{
++	return !(!ntp_enable || mode_ntpdate || (pll_control &&
++	    kern_enable));
++}
++ 
+ 
+ /*
+  * adj_host_clock - Called once every second to update the local clock.
+@@ -684,7 +691,7 @@
+  */
+ void
+ adj_host_clock(
+-	void
++	int time_elapsed
+ 	)
+ {
+ 	double	adjustment;
+@@ -696,7 +703,7 @@
+ 	 * since the poll interval can exceed one day, the old test
+ 	 * would be counterproductive.
+ 	 */
+-	sys_rootdisp += clock_phi;
++	sys_rootdisp += clock_phi * time_elapsed;
+ 
+ #ifndef LOCKCLOCK
+ 	/*
+@@ -816,6 +823,12 @@
+ #endif /* KERNEL_PLL */
+ }
+ 
++int
++huffpuff_enabled(void)
++{
++	return sys_huffpuff != NULL;
++}
++
+ /*
+  * huff-n'-puff filter
+  */
+Index: ntp-4.2.6.p2+dfsg/ntpd/ntp_refclock.c
+===================================================================
+--- ntp-4.2.6.p2+dfsg.orig/ntpd/ntp_refclock.c	2010-06-19 01:40:31.000000000 -0500
++++ ntp-4.2.6.p2+dfsg/ntpd/ntp_refclock.c	2011-01-18 09:35:20.666203002 -0600
+@@ -269,6 +269,21 @@
+ }
+ 
+ 
++int
++refclock_timer_needed(
++	struct peer *peer	/* peer structure pointer */
++	)
++{
++	u_char clktype;
++	int unit;
++
++	clktype = peer->refclktype;
++	unit = peer->refclkunit;
++	if (refclock_conf[clktype]->clock_timer != noentry)
++		return 1;
++	return 0;
++}
++
+ /*
+  * refclock_timer - called once per second for housekeeping.
+  */
+Index: ntp-4.2.6.p2+dfsg/ntpd/ntp_timer.c
+===================================================================
+--- ntp-4.2.6.p2+dfsg.orig/ntpd/ntp_timer.c	2009-12-09 01:36:35.000000000 -0600
++++ ntp-4.2.6.p2+dfsg/ntpd/ntp_timer.c	2011-01-18 09:35:20.666203002 -0600
+@@ -56,7 +56,6 @@
+ static	u_long stats_timer;	/* stats timer */
+ static	u_long huffpuff_timer;	/* huff-n'-puff timer */
+ u_long	leapsec;		/* leapseconds countdown */
+-l_fp	sys_time;		/* current system time */
+ #ifdef OPENSSL
+ static	u_long revoke_timer;	/* keys revoke timer */
+ static	u_long keys_timer;	/* session key timer */
+@@ -74,6 +73,12 @@
+ #define	DAY	(24 * HOUR)
+ 
+ u_long current_time;		/* seconds since startup */
++l_fp timer_base;
++int time_elapsed;
++
++#define TIMEOUT_TS_SIZE 2
++l_fp timeout_ts[TIMEOUT_TS_SIZE];
++unsigned int timeout_ts_index;
+ 
+ /*
+  * Stats.  Number of overflows and number of calls to transmit().
+@@ -110,6 +115,8 @@
+ void 
+ reinit_timer(void)
+ {
++	get_systime(&timer_base);
++#if 0
+ #if !defined(SYS_WINNT) && !defined(VMS)
+ #  if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
+ 	timer_gettime(ntpd_timerid, &itimer);
+@@ -143,6 +150,7 @@
+ 	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+ #  endif
+ # endif /* VMS */
++#endif
+ }
+ 
+ /*
+@@ -165,6 +173,12 @@
+ 	timer_xmtcalls = 0;
+ 	timer_timereset = 0;
+ 
++	get_systime(&timer_base);
++
++	for (timeout_ts_index = 0; timeout_ts_index < TIMEOUT_TS_SIZE; timeout_ts_index++)
++		L_CLR(&timeout_ts[timeout_ts_index]);
++	timeout_ts_index = 0;
++#if 0
+ #if !defined(SYS_WINNT)
+ 	/*
+ 	 * Set up the alarm interrupt.	The first comes 2**EVENT_TIMEOUT
+@@ -226,6 +240,7 @@
+ 	}
+ 
+ #endif /* SYS_WINNT */
++#endif
+ }
+ 
+ #if defined(SYS_WINNT)
+@@ -236,6 +251,104 @@
+ }
+ #endif
+ 
++double
++get_timeout(l_fp *now)
++{
++	register struct peer *peer, *next_peer;
++	u_int	n;
++	double r;
++	int next;
++	l_fp ts;
++
++	ts = *now;
++	L_SUB(&ts, &timeout_ts[timeout_ts_index]);
++	timeout_ts[timeout_ts_index] = *now;
++	timeout_ts_index = (timeout_ts_index + 1) % TIMEOUT_TS_SIZE;
++
++	/* don't waste CPU time if called too frequently */
++	if (ts.l_ui == 0) {
++		next = 1;
++		goto finish;
++	}
++
++	next = current_time + HOUR;
++
++	if (adj_host_clock_needed()) {
++		next = 1;
++		goto finish;
++	}
++	for (n = 0; n < NTP_HASH_SIZE; n++) {
++		for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
++			next_peer = peer->next;
++#ifdef REFCLOCK
++			if (peer->flags & FLAG_REFCLOCK && refclock_timer_needed(peer)) {
++				next = 1;
++				goto finish;
++			}
++#endif /* REFCLOCK */
++			if (peer->action)
++			       next = min(next, peer->nextaction);
++			next = min(next, peer->nextdate);
++		}
++	}
++
++	if (leapsec > 0)
++		next = min(next, leapsec);
++
++	if (huffpuff_enabled())
++		next = min(next, huffpuff_timer);
++
++#ifdef OPENSSL
++	if (auth_agekeys_needed())
++		next = min(next, keys_timer);
++	if (sys_leap != LEAP_NOTINSYNC)
++		next = min(next, revoke_timer);
++#endif /* OPENSSL */
++
++	if (interface_interval)
++		next = min(next, interface_timer);
++
++	next = min(next, stats_timer);
++
++	next -= current_time;
++	if (next <= 0)
++		next = 1;
++finish:
++	ts = timer_base;
++	ts.l_ui += next;
++	L_SUB(&ts, now);
++	LFPTOD(&ts, r);
++#ifdef DEBUG 
++	DPRINTF(2, ("timer: timeout %f\n", r));
++#endif
++
++	return r;
++}
++
++int
++timer_elapsed(l_fp now, int timeout)
++{
++	int elapsed;
++
++	L_SUB(&now, &timer_base);
++	elapsed = now.l_i;
++	if (elapsed < 0 || elapsed > timeout + 10) {
++#ifdef DEBUG 
++		DPRINTF(2, ("timer: unexpected time jump\n"));
++#endif
++		elapsed = 0;
++		reinit_timer();
++
++	}
++	timer_base.l_ui += elapsed;
++	time_elapsed += elapsed;
++	current_time += elapsed;
++#ifdef DEBUG 
++	DPRINTF(2, ("timer: time elapsed %d\n", time_elapsed));
++#endif
++	return time_elapsed;
++}
++
+ /*
+  * timer - event timer
+  */
+@@ -251,11 +364,9 @@
+ 	 * kiss-o'-deatch function and implement the association
+ 	 * polling function..
+ 	 */
+-	current_time++;
+-	get_systime(&sys_time);
+ 	if (adjust_timer <= current_time) {
+-		adjust_timer += 1;
+-		adj_host_clock();
++		adjust_timer += time_elapsed;
++		adj_host_clock(time_elapsed);
+ #ifdef REFCLOCK
+ 		for (n = 0; n < NTP_HASH_SIZE; n++) {
+ 			for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
+@@ -286,7 +397,7 @@
+ 			 * 128 s or less.
+ 			 */
+ 			if (peer->throttle > 0)
+-				peer->throttle--;
++				peer->throttle -= min(peer->throttle, time_elapsed);
+ 			if (peer->nextdate <= current_time) {
+ #ifdef REFCLOCK
+ 				if (peer->flags & FLAG_REFCLOCK)
+@@ -333,7 +444,7 @@
+ 	 * set.
+ 	 */
+ 	if (leapsec > 0) {
+-		leapsec--;
++		leapsec -= min(leapsec, time_elapsed);
+ 		if (leapsec == 0) {
+ 			sys_leap = LEAP_NOWARNING;
+ 			sys_tai = leap_tai;
+@@ -398,11 +509,15 @@
+ 	 * Finally, write hourly stats.
+ 	 */
+ 	if (stats_timer <= current_time) {
++		l_fp sys_time;
++		get_systime(&sys_time);
+ 		stats_timer += HOUR;
+ 		write_stats();
+ 		if (sys_tai != 0 && sys_time.l_ui > leap_expire)
+ 			report_event(EVNT_LEAPVAL, NULL, NULL);
+ 	}
++
++	time_elapsed = 0;
+ }
+ 
+ 
+Index: ntp-4.2.6.p2+dfsg/ntpd/ntpd.c
+===================================================================
+--- ntp-4.2.6.p2+dfsg.orig/ntpd/ntpd.c	2011-01-18 09:33:45.000000000 -0600
++++ ntp-4.2.6.p2+dfsg/ntpd/ntpd.c	2011-01-18 09:35:20.670203002 -0600
+@@ -197,8 +197,6 @@
+ 
+ char const *progname;
+ 
+-int was_alarmed;
+-
+ #ifdef DECL_SYSCALL
+ /*
+  * We put this here, since the argument profile is syscall-specific
+@@ -1054,7 +1052,7 @@
+ #else /* normal I/O */
+ 
+ 	BLOCK_IO_AND_ALARM();
+-	was_alarmed = 0;
++
+ 	for (;;)
+ 	{
+ # if !defined(HAVE_SIGNALED_IO)
+@@ -1062,42 +1060,39 @@
+ 		extern int maxactivefd;
+ 
+ 		fd_set rdfdes;
+-		int nfound;
+-# endif
++		int nfound, time_elapsed;
+ 
+-		if (alarm_flag)		/* alarmed? */
+-		{
+-			was_alarmed = 1;
+-			alarm_flag = 0;
+-		}
++		time_elapsed = 0;
++# endif
+ 
+-		if (!was_alarmed && has_full_recv_buffer() == ISC_FALSE)
++		if (has_full_recv_buffer() == ISC_FALSE)
+ 		{
+ 			/*
+ 			 * Nothing to do.  Wait for something.
+ 			 */
+ # ifndef HAVE_SIGNALED_IO
++			double timeout;
++
+ 			rdfdes = activefds;
+-#  if defined(VMS) || defined(SYS_VXWORKS)
+-			/* make select() wake up after one second */
+-			{
+-				struct timeval t1;
++			get_systime(&now);
++			timeout = get_timeout(&now);
+ 
+-				t1.tv_sec = 1; t1.tv_usec = 0;
++			if (timeout > 0.0) {
++ 				struct timeval t1;
++
++				t1.tv_sec = timeout;
++				t1.tv_usec = (timeout - t1.tv_sec) * 1000000;
+ 				nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
+ 						(fd_set *)0, &t1);
+-			}
+-#  else
+-			nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
+-					(fd_set *)0, (struct timeval *)0);
+-#  endif /* VMS */
+-			if (nfound > 0)
+-			{
+-				l_fp ts;
++				get_systime(&now);
++			} else
++				nfound = 0;
+ 
+-				get_systime(&ts);
++			time_elapsed = timer_elapsed(now, timeout);
+ 
+-				(void)input_handler(&ts);
++			if (nfound > 0)
++			{
++				(void)input_handler(&now);
+ 			}
+ 			else if (nfound == -1 && errno != EINTR)
+ 				msyslog(LOG_ERR, "select() error: %m");
+@@ -1106,17 +1101,13 @@
+ 				msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
+ #  endif /* DEBUG */
+ # else /* HAVE_SIGNALED_IO */
++#  error not supported by sleep patch
+ 
+ 			wait_for_signal();
+ # endif /* HAVE_SIGNALED_IO */
+-			if (alarm_flag)		/* alarmed? */
+-			{
+-				was_alarmed = 1;
+-				alarm_flag = 0;
+-			}
+ 		}
+ 
+-		if (was_alarmed)
++		if (time_elapsed > 0)
+ 		{
+ 			UNBLOCK_IO_AND_ALARM();
+ 			/*
+@@ -1124,7 +1115,6 @@
+ 			 * to process expiry.
+ 			 */
+ 			timer();
+-			was_alarmed = 0;
+ 			BLOCK_IO_AND_ALARM();
+ 		}
+ 
+@@ -1142,19 +1132,8 @@
+ 			rbuf = get_full_recv_buffer();
+ 			while (rbuf != NULL)
+ 			{
+-				if (alarm_flag)
+-				{
+-					was_alarmed = 1;
+-					alarm_flag = 0;
+-				}
+ 				UNBLOCK_IO_AND_ALARM();
+ 
+-				if (was_alarmed)
+-				{	/* avoid timer starvation during lengthy I/O handling */
+-					timer();
+-					was_alarmed = 0;
+-				}
+-
+ 				/*
+ 				 * Call the data procedure to handle each received
+ 				 * packet.
diff -Nru ntp-4.2.6.p2+dfsg/debian/patches/series ntp-4.2.6.p2+dfsg/debian/patches/series
--- ntp-4.2.6.p2+dfsg/debian/patches/series	2010-05-24 05:28:33.000000000 -0500
+++ ntp-4.2.6.p2+dfsg/debian/patches/series	2011-01-18 09:35:16.000000000 -0600
@@ -9,3 +9,4 @@
 autotools.patch
 mod_nano.patch
 nanokernel-status.patch
+ntpd-sleep.patch



More information about the pkg-ntp-maintainers mailing list