www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to sleep accurately

reply Jason House <jason.james.house gmail.com> writes:
I've been trying for a while now to get a sleep routine that actually 
works as I expect it to (sleeping for the time specified within a 
practical error margin).


Let's say you want to sleep for 0.1 seconds (wall clock).

msleep(100); // Not available under linux

usleep(100000); // Not guaranteed to be reentrant...

timespec ts;
ts.sec = 0;
ts.nsec = 100000000;
nanosleep(ts,cast(timespec)null); // Thread safe


Unfortunately, all of those can be interrupted by signals (such as the 
garbage collector running).  Ignoring the reentrant issue (which seems 
to not affect stuff in practice), I tried the following:

time_t now = clock();
time_t stop = now + 100000/CLOCKS_PER_SECOND;
while(now<stop){
   usleep(stop-now);
   now = clock();
}


On windows, that seemed to work.  Under linux, clock() keeps returning 
zero!  It appears that it returns the process time that elapsed since 
the last call to clock rather than using any kind of absolute reference 
and is useless.

Does anyone have a good way of doing this?
Jun 27 2007
next sibling parent reply Daniel Giddings <danielg microforte.com> writes:
I'm not sure of the best way to do it but I'm interested in what people 
think ;-)

You can use gettimeofday under linux instead of clock. It's in 
std.c.linux.linux.

long getTime() // in ms
{
	timeval t;
	struct_timezone z;

	gettimeofday(&t, &z);

	return t.tv_sec * 1000 + t.tv_usec / 1000;
}


Jason House wrote:
 I've been trying for a while now to get a sleep routine that actually 
 works as I expect it to (sleeping for the time specified within a 
 practical error margin).
 
 
 Let's say you want to sleep for 0.1 seconds (wall clock).
 
 msleep(100); // Not available under linux
 
 usleep(100000); // Not guaranteed to be reentrant...
 
 timespec ts;
 ts.sec = 0;
 ts.nsec = 100000000;
 nanosleep(ts,cast(timespec)null); // Thread safe
 
 
 Unfortunately, all of those can be interrupted by signals (such as the 
 garbage collector running).  Ignoring the reentrant issue (which seems 
 to not affect stuff in practice), I tried the following:
 
 time_t now = clock();
 time_t stop = now + 100000/CLOCKS_PER_SECOND;
 while(now<stop){
   usleep(stop-now);
   now = clock();
 }
 
 
 On windows, that seemed to work.  Under linux, clock() keeps returning 
 zero!  It appears that it returns the process time that elapsed since 
 the last call to clock rather than using any kind of absolute reference 
 and is useless.
 
 Does anyone have a good way of doing this?

Jun 27 2007
parent reply Jason House <jason.james.house gmail.com> writes:
Daniel Giddings wrote:
 I'm not sure of the best way to do it but I'm interested in what people 
 think ;-)
 
 You can use gettimeofday under linux instead of clock. It's in 
 std.c.linux.linux.
 
 long getTime() // in ms
 {
     timeval t;
     struct_timezone z;
 
     gettimeofday(&t, &z);
 
     return t.tv_sec * 1000 + t.tv_usec / 1000;
 }

Thanks. I'm using that and it seems to be working well... I'll have to add some kind of check for the end of the day. Will this have issues with daylight savings time? Can I force it to use a timezone without that?
Jun 27 2007
next sibling parent Daniel Giddings <danielg microforte.com> writes:
I don't thin so, but to be honest I've never tried it. The man page 
indicates that the timezone field is obsolete and null can be passed:

http://www.rt.com/man/gettimeofday.2.html

Jason House wrote:
 Daniel Giddings wrote:
 I'm not sure of the best way to do it but I'm interested in what 
 people think ;-)

 You can use gettimeofday under linux instead of clock. It's in 
 std.c.linux.linux.

 long getTime() // in ms
 {
     timeval t;
     struct_timezone z;

     gettimeofday(&t, &z);

     return t.tv_sec * 1000 + t.tv_usec / 1000;
 }

Thanks. I'm using that and it seems to be working well... I'll have to add some kind of check for the end of the day. Will this have issues with daylight savings time? Can I force it to use a timezone without that?

Jun 27 2007
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Jason House wrote:
 Daniel Giddings wrote:
 I'm not sure of the best way to do it but I'm interested in what 
 people think ;-)

 You can use gettimeofday under linux instead of clock. It's in 
 std.c.linux.linux.

 long getTime() // in ms
 {
     timeval t;
     struct_timezone z;

     gettimeofday(&t, &z);

     return t.tv_sec * 1000 + t.tv_usec / 1000;
 }

Thanks. I'm using that and it seems to be working well... I'll have to add some kind of check for the end of the day.

""" The gettimeofday() function shall obtain the current time, expressed as seconds and microseconds since the Epoch, and store it in the timeval structure pointed to by tp. The resolution of the system clock is unspecified. """ So no, you don't have to worry about the end of the day, just the end of something like 2^32 or 2^64 seconds from around January 1970, depending on your platform. --bb
Jun 27 2007
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Jason,

 I've been trying for a while now to get a sleep routine that actually
 works as I expect it to (sleeping for the time specified within a
 practical error margin).
 
 Let's say you want to sleep for 0.1 seconds (wall clock).
 
 msleep(100); // Not available under linux
 
 usleep(100000); // Not guaranteed to be reentrant...
 
 timespec ts;
 ts.sec = 0;
 ts.nsec = 100000000;
 nanosleep(ts,cast(timespec)null); // Thread safe
 Unfortunately, all of those can be interrupted by signals (such as the
 garbage collector running).  Ignoring the reentrant issue (which seems
 to not affect stuff in practice), I tried the following:
 
 time_t now = clock();
 time_t stop = now + 100000/CLOCKS_PER_SECOND;
 while(now<stop){
 usleep(stop-now);
 now = clock();
 }
 On windows, that seemed to work.  Under linux, clock() keeps returning
 zero!  It appears that it returns the process time that elapsed since
 the last call to clock rather than using any kind of absolute
 reference and is useless.
 
 Does anyone have a good way of doing this?
 

if you are on x86 and if you can get the clock speed and if you don't mind asm you can get a clock cycle resolution busy wait using: |long first,stop; |asm |{ | rdtsc; | mov first, EAX; | mov 4+first, EDX; |} | |stop = first + TimeInCPUCycles(); | |while(first < stop) | asm | { | rdtsc; | mov first, EAX; | mov 4+first, EDX; | }
Jun 28 2007
parent reply Jason House <jason.james.house gmail.com> writes:
BCS wrote:
 if you are on x86 and if you can get the clock speed and if you don't 
 mind asm you can get a clock cycle resolution busy wait using:

I'm trying to stay as cross platform as possible. It's currently used on x86 and mac. I'm discovering that gettimeofday is not available on the mac. I still have to find another solution.
Jun 28 2007
parent BCS <ao pathlink.com> writes:
Reply to Jason,

 BCS wrote:
 
 if you are on x86 and if you can get the clock speed and if you don't
 mind asm you can get a clock cycle resolution busy wait using:
 

on x86 and mac. I'm discovering that gettimeofday is not available on the mac. I still have to find another solution.

well if you are using x86 mac you would be potable and PPC has a similar CPU clock counter. But you would still need something else for any other system.
Jul 02 2007