Skip to contentSkip to conversation

do_gettimeofday() fails to compensate for lost ticks

PATCH In review Khalid Aziz 4 participants 8 messages Sep 24, 2003

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 do_gettimeofday() fails to compensate for lost ticks

do_gettimeofday() needs to account for lost ticks before returning current time and it fails to do that. do_gettimeofday() on other architectures compensate for lost ticks correctly. Due to this bug, if you repeatedly do clock_settime() immediately followed by clock_gettime() and compare the time returned by clock_gettime() to the time set by clock_settime(), you will eventually see clock going backwards. I am attaching a test program from POSIX testsuite at the end that exposes this bug. Run this test in a continuous loop that stops when test fails.

Following patch should address this issue.

--
Khalid

===========

arch/ia64/kernel/time.c +1 -0
@@ -132,6 +132,7 @@
 
 		sec = xtime.tv_sec;
 		usec += xtime.tv_usec;
+		usec += (jiffies - wall_jiffies) * (1000000 / HZ);
 	}
 	read_unlock_irqrestore(&xtime_lock, flags);
 

========= Test program =========
/*
* Copyright (c) 2002, Intel Corporation. All rights reserved.
* Created by: julie.n.fleischer REMOVE-THIS AT intel DOT com
* This file is licensed under the GPL license. For the full content
* of this license, see the COPYING file at the top level of this
* source tree.

* Test that clock_settime() sets clock_id to tp.
*
* The clock_id chosen for this test is CLOCK_REALTIME.
* The date chosen is Nov 12, 2002 ~11:13am (date when test was first
* written).
*/
#include <stdio.h>
#include <time.h>
/*#include "posixtest.h"
#include "helpers.h"*/

#define TESTTIME 1037128358
#define ACCEPTABLEDELTA 1
#define PTS_UNRESOLVED 2
#define PTS_PASS 0
#define PTS_FAIL 1

int getBeforeTime(struct timespec *tpget)

{
	if (clock_gettime(CLOCK_REALTIME, tpget) != 0) {
		perror("clock_gettime() did not return success\n");
		perror("clock may not be reset properly\n");
		return PTS_UNRESOLVED;
	}
	return PTS_PASS;
}

int setBackTime(struct timespec tpset)

{
	if (clock_settime(CLOCK_REALTIME, &tpset) != 0) {
		perror("clock_settime() did not return success\n");
		perror("clock may not be reset properly\n");
		return PTS_UNRESOLVED;
	}
	return PTS_PASS;
}

int main(int argc, char *argv[])

{
	struct timespec tpset, tpget, tpreset;
	int delta;

	getBeforeTime(&tpreset);

	tpset.tv_sec = TESTTIME;
	tpset.tv_nsec = 0;
	if (clock_settime(CLOCK_REALTIME, &tpset) = 0) {
		if (clock_gettime(CLOCK_REALTIME, &tpget) = -1) {
			perror("Error in clock_gettime()");
			return 2;
		}
		delta = tpget.tv_sec-tpset.tv_sec;
		if ( (delta <= ACCEPTABLEDELTA) && (delta >= 0) ) {
			printf("Test PASSED\n");
			setBackTime(tpreset);
			return 0;
		} else {
			printf("delta = %d, tpget=%d,%d, tpset=%d,%d\n", delta, tpget.tv_sec, tpget.tv_nsec, tpset.tv_sec, tpset.tv_nsec);
			printf("clock does not appear to be set\n");
			setBackTime(tpreset);
			return 1;
		}
	} else {
		printf("clock_settime() failed\n");
		return 2;
	}

	printf("This code should not be executed.\n");
	return 2;
}
#1 lore raw
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Khalid Aziz

Khalid> do_gettimeofday() needs to account for lost ticks before Khalid> returning current time and it fails to do
Khalid> that. do_gettimeofday() on other architectures compensate Khalid> for lost ticks correctly. Due to this bug, if you repeatedly Khalid> do clock_settime() immediately followed by clock_gettime() Khalid> and compare the time returned by clock_gettime() to the time Khalid> set by clock_settime(), you will eventually see clock going Khalid> backwards. I am attaching a test program from POSIX Khalid> testsuite at the end that exposes this bug. Run this test in Khalid> a continuous loop that stops when test fails.

This explanation doesn't sound right. See the "lost" variable in gettimeoffset(). It's supposed to account for lost ticks.

	--david
#2 lore raw
In reply to Khalid Aziz
Quoted 14 lines · David Mosberger
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines · Khalid Aziz

Khalid> do_gettimeofday() needs to account for lost ticks before Khalid> returning current time and it fails to do
Khalid> that. do_gettimeofday() on other architectures compensate Khalid> for lost ticks correctly. Due to this bug, if you repeatedly Khalid> do clock_settime() immediately followed by clock_gettime() Khalid> and compare the time returned by clock_gettime() to the time Khalid> set by clock_settime(), you will eventually see clock going Khalid> backwards. I am attaching a test program from POSIX Khalid> testsuite at the end that exposes this bug. Run this test in Khalid> a continuous loop that stops when test fails.

Quoted 4 lines

This explanation doesn't sound right. See the "lost" variable in gettimeoffset(). It's supposed to account for lost ticks.

        --david

David,

So it would seem. What would then explain clock going backwards? Here is what I see when the test fails:

tpget37128357,995121000, tpset37128358,0

where tpget is what was returned by gettimeofday() and tpset is what was set by settimeofday(). Clock seems to have moved back by 4.879 msec.

Signature · 9 lines
Khalid

==================================
Khalid Aziz                                Linux and Open Source Lab
(970)898-9214                                        Hewlett-Packard
[email protected]                                       Fort Collins, CO

"The Linux kernel is subject to relentless development" 
				- Alessandro Rubini
#3 lore raw
In reply to Khalid Aziz
Quoted 7 lines · Khalid Aziz
Quoted 4 lines

This explanation doesn't sound right. See the "lost" variable in gettimeoffset(). It's supposed to account for lost ticks.

        --david

David,

Quoted 7 lines

So it would seem. What would then explain clock going backwards? Here is what I see when the test fails:

tpget37128357,995121000, tpset37128358,0

where tpget is what was returned by gettimeofday() and tpset is what was set by settimeofday(). Clock seems to have moved back by 4.879 msec.

Just FYI, Martin Hicks noticed recently that 2.6 on a machine with itc drift also has this problem. I think John Hawkes has some ideas on how to fix it, but I haven't had time to look at it yet.

Thanks,
Jesse

#4 lore raw
In reply to Khalid Aziz
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Khalid Aziz

Khalid> So it would seem. What would then explain clock going Khalid> backwards? Here is what I see when the test fails:

Khalid> tpget37128357,995121000, tpset37128358,0

Khalid> where tpget is what was returned by gettimeofday() and tpset Khalid> is what was set by settimeofday(). Clock seems to have moved Khalid> back by 4.879 msec.

Not sure off-hand and I haven't looked at the 2.4 code-base in a while, but aren't we double-compensating in do_settimeofday()? There, we have:

		tv->tv_usec -= gettimeoffset();
		tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);

Perhaps the second line just needs to go?

	--david
#5 lore raw
In reply to Khalid Aziz
Quoted 10 lines · David Mosberger

Not sure off-hand and I haven't looked at the 2.4 code-base in a while, but aren't we double-compensating in do_settimeofday()? There, we have:

                tv->tv_usec -= gettimeoffset();
                tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);

Perhaps the second line just needs to go?

        --david

I bet you are right. I will try taking that line out.

--
Khalid

==================================
Khalid Aziz Linux and Open Source Lab
(970)898-9214 Hewlett-Packard
[email protected] Fort Collins, CO

"The Linux kernel is subject to relentless development"
- Alessandro Rubini

#6 lore raw
In reply to Khalid Aziz
Quoted 5 lines · Khalid Aziz
Quoted 4 lines · David Mosberger

Not sure off-hand and I haven't looked at the 2.4 code-base in a while, but aren't we double-compensating in do_settimeofday()? There, we have:

Quoted 8 lines
Quoted 6 lines
                tv->tv_usec -= gettimeoffset();
                tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);

Perhaps the second line just needs to go?

        --david

I bet you are right. I will try taking that line out.

That was it. The same test that failed in less than 30 seconds, now has been running for more than 10 minutes without failure. Thanks, David.

Here is a new patch.

--
Khalid

================--- linux-2.4.22/arch/ia64/kernel/time.c Mon Aug 25 05:44:39 2003
+++ linux-2.4.22-clock_fix/arch/ia64/kernel/time.c Wed Sep 24 12:38:20 2003
@@ -93,7 +93,6 @@
* it!
*/
tv->tv_usec -= gettimeoffset();
- tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);

while (tv->tv_usec < 0) {
tv->tv_usec += 1000000;

#7 lore raw
In reply to Khalid Aziz
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Khalid Aziz

Khalid> That was it. The same test that failed in less than 30 Khalid> seconds, now has been running for more than 10 minutes Khalid> without failure.

Great! Thanks for tracking this down. I'm not surprised this bug has gone undetected so long---settimeofday() isn't really called all that often. I guess this shows the value of a good test-suite...

	--david