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@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; }