[gambit-list] heartbeat frequency problem in make check

Marc Feeley feeley at iro.umontreal.ca
Thu Oct 23 11:10:50 EDT 2008


On 23-Oct-08, at 7:47 AM, Cristian Baboi wrote:

> Hello!
>
> Since I joinded this list, I compiled from source (on RHEL4, RHEL5 and
> Debian 4; 32 and 64 bit arhitectures) various versions of gambit-c.
> The tests 4 and 6 from make check have given values close to the  
> expected
> ones for heartbeat frequency, EXCEPT for the latest few versions of
> gambit-c. (I don't remember the last good one)
>
> For the v4.3.0, regardless of the configuration options I use
> (--enable-single-host --enable-gcc-opts --enable-inline-jumps
> --enable-shared), the architecture (32/64 bits, amd/intel), I get ~  
> 40 Hz
> instead of close to 500 Hz expected.
>
> Why ?

This bug was introduced when I changed the default thread priority to  
be 0.  The program tests/mix.scm which tests the heartbeat interrupts  
did it with a thread whose priority was also set to 0 (which means the  
primordial thread and the heartbeat thread were being interleaved  
instead of the heartbeat thread running as soon as there was a  
heartbeat interrupt).  Note: the heartbeat interrupts on Unix system  
are obtained using the ITIMER_VIRTUAL timer (i.e. the interval is in  
user time, not real time).

So on Linux the test for heartbeat interrupts should be back to  
normal.  On Mac OS X the heartbeat interval is really not accurate,  
but it is the fault of the operating system...  To test this out I  
wrote the program below.  Read the comments for details.

To everyone on the list, if you have a non-Linux flavor of Unix (or an  
unusual Linux distribution or hardware), could you please try it out  
on your system and report any anomalies.

To those knowing how to report bugs to Apple, could you?

Marc


/*
  * File: "timer-perf.c".
  *
  * This program was written by Marc Feeley (feeley at iro.umontreal.ca).
  *
  * This program tests the accuracy of the ITIMER_VIRTUAL and  
ITIMER_REAL
  * timers.  When the setitimer is used to request a given timer  
interval
  * the system will setup the timer to deliver a "heartbeat interrupt"
  * at a certain interval, which generally is not exactly the one
  * requested (because the timers have a certain granularity and a
  * minimal interval).  With a call to getitimer it is possible to
  * determine which interval was set by the OS (the "claimed" interval).
  *
  * In this test, "accuracy" is measured as the ratio between the
  * claimed interval and the actual interval obtained.  The tests
  * on Mac OS X and Linux show that the timer granularity, minimal
  * interval and accuracy vary considerably between these operating
  * systems.
  *
  * Execution on Mac OS X 10.5.5 on a Mac Book Pro with Intel Core Duo:
  *
  *   % gcc timer-perf.c
  *   % time ./a.out
  *   ITIMER_REAL: requested, claimed and actual intervals in us and  
accuracy
  *       100000   100000   101318 (101%)
  *        50000    50000    50061 (100%)
  *        20000    20000    19884 (99%)
  *        10000    10000     9945 (99%)
  *         5000     5000     4957 (99%)
  *         2000     2000     1970 (98%)
  *         1000     1000      979 (97%)
  *          500      500      482 (96%)
  *          200      200      183 (91%)
  *          100      100       86 (86%)
  *   ITIMER_VIRTUAL: requested, claimed and actual intervals in us  
and accuracy
  *       100000   100000   103766 (103%)
  *        50000    50000    52527 (105%)
  *        20000    20000    22161 (110%)
  *        10000    10000    11818 (118%)
  *         5000     5000     7286 (145%)
  *         2000     2000     4527 (226%)
  *         1000     1000     3141 (314%)
  *          500      500     2762 (552%)
  *          200      200     2333 (1166%)
  *          100      100     2407 (2407%)
  *   done  (dummy = 1566934064)
  *
  *   real	1m27.405s
  *   user	1m25.414s
  *   sys	0m1.516s
  *
  * Execution on Linux:
  *
  *   % gcc timer-perf.c
  *   % time ./a.out
  *   ITIMER_REAL: requested, claimed and actual intervals in us and  
accuracy
  *       100000   100000   104387 (104%)
  *        50000    50000    50639 (101%)
  *        20000    20000    20074 (100%)
  *        10000    10000    10037 (100%)
  *         5000     5000     5018 (100%)
  *         2000     2000     4000 (200%)
  *         1000     1000     4007 (400%)
  *          500      500     4007 (801%)
  *          200      200     3978 (1989%)
  *          100      100     4000 (4000%)
  *   ITIMER_VIRTUAL: requested, claimed and actual intervals in us  
and accuracy
  *       100000   100006   104197 (104%)
  *        50000    52003    52098 (100%)
  *        20000    20001    20142 (100%)
  *        10000    12000    12043 (100%)
  *         5000     8000     8029 (100%)
  *         2000     4000     4007 (100%)
  *   done  (dummy = 2132937504)
  *
  *   real    0m35.339s
  *   user    0m35.302s
  *   sys     0m0.000s
  */

#include <sys/time.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/resource.h>

int dummy;
int count;

void heartbeat_interrupt_handler( int sig )
{
   count++;
}

int setup_heartbeat( int timer, int usecs )
{
   struct itimerval tv;
   struct sigaction act;
   int secs = 0;
   int SIG;

   if (timer == ITIMER_REAL)
     SIG = SIGALRM;
   else
     SIG = SIGVTALRM;

   if (usecs == 0)
     act.sa_handler = SIG_IGN;
   else
     act.sa_handler = heartbeat_interrupt_handler;

   act.sa_flags = 0;
#ifdef SA_INTERRUPT
   act.sa_flags |= SA_INTERRUPT;
#endif
   sigemptyset( &act.sa_mask );
   sigaction( SIG, &act, 0 );

   tv.it_interval.tv_sec  = secs;
   tv.it_interval.tv_usec = usecs;
   tv.it_value.tv_sec     = secs;
   tv.it_value.tv_usec    = usecs;
   setitimer( timer, &tv, 0 );
   getitimer( timer, &tv );

   return tv.it_interval.tv_usec;
}

int fib( int n )
{
   if (n < 2)
     return count;
   else
     return fib( n-1 ) + fib( n-2 );
}

void waste_time()
{
   dummy = fib( 40 );
}

void test( int timer )
{
   int usecs = 100000; /* 0.1 second */
   int div_seq = 0;
   int last_usecs = 0;
   int this_usecs;
   struct rusage start;
   struct rusage end;
   int duration;

   if (timer == ITIMER_REAL)
     printf( "ITIMER_REAL" );
   else
     printf( "ITIMER_VIRTUAL" );

   printf( ": requested, claimed and actual intervals in us and  
accuracy\n" );

   for (;;)
     {
       count = 0;
       this_usecs = setup_heartbeat( timer, usecs );
       if (this_usecs == last_usecs || this_usecs < 100)
         {
           setup_heartbeat( timer, 0 );
           break;
         }
       getrusage( RUSAGE_SELF, &start );
       waste_time();
       getrusage( RUSAGE_SELF, &end );
       setup_heartbeat( timer, 0 );
       duration = (end.ru_utime.tv_sec*1000000 + end.ru_utime.tv_usec) -
                  (start.ru_utime.tv_sec*1000000 +  
start.ru_utime.tv_usec);
       printf( "  %8d %8d %8d (%d%%)\n", usecs, this_usecs, duration/ 
count, 100*duration/(count*this_usecs) );
       last_usecs = this_usecs;
       switch (div_seq++)
         { case 0: usecs = usecs / 2; break;
           case 1: usecs = usecs * 2 / 5; break;
           case 2: usecs = usecs / 2; div_seq = 0; break;
         }
     }
}

int main( int argc, char *argv[] )
{
   test( ITIMER_REAL );
   test( ITIMER_VIRTUAL );
   printf( "done  (dummy = %d)\n", dummy );
   return 0;
}




More information about the Gambit-list mailing list