Wednesday, February 14, 2007

hrtimers

I recently read that the hrtimers patches are finally gonna be merged into the official Linux tree soon.

To see how this will benefit realtime related programming, I wrote a little benchmark. The code basically tries to wake up every 1/85 seconds and then measures the delay between ideal and actual wakeup time. The code was run once as a normal user, once as root with SCHED_FIFO scheduling. All values are in nanoseconds.

These are the results:

2.6.19rc6 vanilla2.6.20-hrt-dynticks1
userroot (SCHED_FIFO)userroot (SCHED_FIFO)
min2809853233181229392803
max1087715110091750393117226885
avg686227662082663778830500





As you can see, the latencies are greatly reduced. From a worst case of about 10 milliseconds without hrtimers to a worst case of about 0.4 milliseconds with the patch. The average latency even goes down from about 6 milliseconds to 0.04 milliseconds.

Here is the code (remember to compile with -lrt):

#include
#include
#include
#include
#include

#define FREQUENCY 85
#define PERIOD ( 1000000000 / FREQUENCY )
#define ITERATIONS ( FREQUENCY * 10 )

int64_t timespec_to_nsec( struct timespec* ts ) {

return (int64_t)ts->tv_sec * 1000000000LL + (int64_t)ts->tv_nsec;
}

int main( int argc, char** argv ) {

int err;
struct timespec t;
int i;
int64_t errors[ ITERATIONS ];

struct sched_param sp;

memset( &sp, 0, sizeof( sp ) );
sp.sched_priority = 99;

err = sched_setscheduler( getpid(), SCHED_FIFO, &sp );
if( err != 0 ) perror( "sched_setscheduler" );

err = clock_gettime( CLOCK_MONOTONIC, &t );
if( err != 0 ) { perror( "clock_gettime" ); exit( 1 ); }

for( i = 0; i < ITERATIONS; i++ ) {

struct timespec t2;

t.tv_nsec += PERIOD;

while( t.tv_nsec >= 1000000000 ) {

t.tv_sec += 1;
t.tv_nsec -= 1000000000;
}

err = clock_nanosleep( CLOCK_MONOTONIC, TIMER_ABSTIME, &t, 0 );
if( err != 0 ) { perror( "clock_nanosleep" ); exit( 1 ); }

err = clock_gettime( CLOCK_MONOTONIC, &t2 );
if( err != 0 ) { perror( "clock_gettime" ); exit( 1 ); }

errors[ i ] = timespec_to_nsec( &t2 ) - timespec_to_nsec( &t );
}

int64_t min = 1000000000;
int64_t max = 0;
int64_t acc = 0;

for( i = 0; i < ITERATIONS; i++ ) {

int64_t e = errors[ i ];

printf( " %lld\n", e );


if( e > max ) max = e;
if( e < min ) min = e;
acc += e;
}

acc /= ITERATIONS;

printf( "min: %lld\n", min );
printf( "max: %lld\n", max );
printf( "avg: %lld\n", acc );

return 0;
}

0 comments: