-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Mon, 03 Nov 2003 12:30:15 +0200, Ami Chayun <[EMAIL PROTECTED]> wrote: > > A couple of results: > 1) The rdtscll Pentium instruction (Eran's answer) is very useful. It's > super accurate and right now I decided to use it mostly to benchmark > other solutions, and to estimate the CPU frequency with a fancy version > of - > <CODE> > rdtscll(time1); > sleep(1); > rdtscll(time2); > frequency = time2 - time1; > </CODE> > The use of rdtscll as a long sleep function (above 1 msec) is not very > recommended, since even with the nops, it hogs most of the CPU.
I don't understand why you need to know the CPU speed (see my tight loop below). The sleep call is exact to 10 milli seconds at most. > 2) The select method is very CPU friendly. It is also the way > microsecond sleep is implemented in xmms and alsa (xmms_usleep, and > doSleep in alsa) > XMMS's code: > > unsigned long usec... > <CODE> > struct timeval tv; > > tv.tv_sec = usec / 1000000; > usec -= tv.tv_sec * 1000000; > tv.tv_usec = usec; > select(0, NULL, NULL, NULL, &tv); > </CODE> > > It's pretty stable for time periods of ~1 msec and above. I tested the select call on various machines. 1. It is not accurate enough (2 ms deviations). 2. It can not be used for delays < 10 ms. This is the program used to test the select call: #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/time.h> /* for gettimeofday */ #include <sys/resource.h> /* for setpriority */ void my_usleep ( int u_sec ) ; int main ( int argc, char *argv[] ) { int usec = 1 , cnt = 0 , elapsed , loop = 1000 ; struct timeval bfr, aftr ; /* computer time before / after */ setpriority ( PRIO_PROCESS , 0 , atoi ( argv [ 2 ] ) ) ; /* setpriority (no check) */ fprintf ( stderr , "Run at %d priority " , getpriority ( PRIO_PROCESS , 0 ) ) ; /* get process priority */ usec = atoi ( argv [ 1 ] ) ; /* time to sleep (Milli seconds) */ gettimeofday ( & bfr , NULL ) ; /* computer time - before */ while ( cnt < loop ) { my_usleep ( usec ) ; /* sleep usec micro seconds (mine) */ cnt++ ; } gettimeofday ( & aftr , NULL ) ; /* computer time - after */ elapsed = ( aftr.tv_sec - bfr.tv_sec ) * 1000 + ( aftr.tv_usec - bfr.tv_usec ) / 1000 ; fprintf ( stderr , "sleeped %d usec * %d times, Elapsed %d msecs\n" , usec , cnt , elapsed ) ; return ( 0 ) ; } /*=========================================================================*/ void my_usleep ( int u_sec ) { struct timeval wt ; wt.tv_sec = u_sec / 1000000 ; wt.tv_usec = u_sec % 1000000 ; /* for select */ if ( u_sec > 0 ) select(0, NULL, NULL, NULL, &wt); /* sleep (release cpu) */ } /*=========================================================================*/ > In the end I think we'll implement some sort of combination of all the 3 > solutions including the kernel HZ value (thanks Gilad, the link was > great!). Since the delay doesn't change often, we have the freedom to > decide which of the 3 functions is best during runtime, and select it. Here is my solution (my_usleep) embedded in a test program. This function has an accuracy of about 1 micro second. /* Sleep for arg1 micro seconds 10**N times, and print statistics arg2 is priority (-20 .. 19) If arg3 is given, call system usleep. */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/time.h> /* for gettimeofday */ #include <sys/resource.h> /* for setpriority */ void my_usleep ( int u_sec ) ; /* my usleep */ int main ( int argc, char *argv[] ) { int usec , cnt = 0 , elapsed , loop = 10000 ; struct timeval bfr, aftr ; /* computer time before / after */ setpriority ( PRIO_PROCESS , 0 , atoi ( argv [ 2 ] ) ) ; /* setpriority (no check) */ fprintf ( stderr , "Run at %d priority " , getpriority ( PRIO_PROCESS , 0 ) ) ; /* get process priority */ usec = atoi ( argv [ 1 ] ) ; /* time to sleep (milli seconds) */ if ( usec > 200000 ) loop = 1 ; else while ( ( usec * loop ) > 2000000 ) /* total time > 2 seconds */ loop /= 10 ; gettimeofday ( & bfr , NULL ) ; /* computer time - before */ while ( cnt < loop ) { if ( argc < 4 ) my_usleep ( usec ) ; /* sleep usec micro seconds (mine) */ else usleep ( usec ) ; /* sleep usec micro seconds (standard) */ cnt ++ ; } gettimeofday ( & aftr , NULL ) ; /* computer time - after */ elapsed = ( aftr.tv_sec - bfr.tv_sec ) * 1000 + ( aftr.tv_usec - bfr.tv_usec ) / 1000 ; fprintf ( stderr , "sleeped %d usec * %d times, Elapsed %d msecs\n" , usec , cnt , elapsed ) ; return ( 0 ) ; } /*=========================================================================*/ void my_usleep ( int u_sec ) /* my usleep */ { struct timeval bfr, aftr , wt ; /* computer time before / after */ #define ofst 3000 /* time in microseconds to check by cpu loop */ u_sec -= ofst ; /* for wait, decrease time waited by cpu */ wt.tv_sec = u_sec / 1000000 ; wt.tv_usec = u_sec % 1000000 ; /* for select */ gettimeofday ( & bfr , NULL ) ; /* computer time - before */ bfr.tv_sec += wt.tv_sec ; /* add sleep time (seconds) */ bfr.tv_usec += wt.tv_usec + ofst ; /* add sleep time (micro seconds) */ if ( bfr.tv_usec > 999999 ) { bfr.tv_sec ++ ; bfr.tv_usec -= 1000000 ; } if ( ( wt.tv_sec > 0 ) || ( wt.tv_usec >= 9000 ) ) /* wait more than 9 milli seconds ? */ select(0, NULL, NULL, NULL, &wt); /* sleep (release cpu) */ aftr.tv_sec = 0 ; while ( aftr.tv_sec < bfr.tv_sec ) gettimeofday ( & aftr , NULL ) ; /* computer time - after */ while ( ( aftr.tv_sec <= bfr.tv_sec ) && /* for rare race occasions */ ( aftr.tv_usec < bfr.tv_usec ) ) gettimeofday ( & aftr , NULL ) ; /* computer time - after */ } /*=========================================================================*/ Ehud. - -- Ehud Karni Tel: +972-3-7966-561 /"\ Mivtach - Simon Fax: +972-3-7966-667 \ / ASCII Ribbon Campaign Insurance agencies (USA) voice mail and X Against HTML Mail http://www.mvs.co.il FAX: 1-815-5509341 / \ GnuPG: 98EA398D <http://www.keyserver.net/> Better Safe Than Sorry -----BEGIN PGP SIGNATURE----- Comment: use http://www.keyserver.net/ to get my key (and others) iD8DBQE/p571LFvTvpjqOY0RArvDAJ9eHBLGRBX+M+TmPApEijf+tI0gwACggiUa jYdhEPgPkPXpiVKxqj4B2b4= =W1xW -----END PGP SIGNATURE----- ================================================================= To unsubscribe, send mail to [EMAIL PROTECTED] with the word "unsubscribe" in the message body, e.g., run the command echo unsubscribe | mail [EMAIL PROTECTED]