-----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]