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

Reply via email to