[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Posix timers
From: |
Joe English |
Subject: |
Posix timers |
Date: |
Sat, 01 Feb 2003 11:21:49 -0800 |
Hello, and apologies if this is not the appropriate mailing list.
I've noticed some odd behaviour with the POSIX timers
interface (timer_create() / timer_settime()) on Linux/x86
when using a periodic timer. (Test program below).
It appears that timer_settime() rounds it_interval up to
the nearest multiple of 1/HZ seconds (10 milliseconds in
this case) and then *adds* another 1/HZ. So the smallest
achievable interval is 20 milliseconds.
I've tested this under a handful of Linux/x86 distributions:
a patched RedHat 7 (glibc 2.2.4, kernel 2.4.14-smp),
this week's Debian sarge (glibc 2.2.5, kernels 2.4.18
and 2.4.18-smp) and Mandrake 9.0 (glibc 2.2.5, kernel 2.4.20-2mdk),
the problem appears on all these platforms.
In addition, on some (but not all) of the above systems,
the signal handler is never invoked at all if I use
sigev_signo = SIGRTMIN in the timer_create() call.
Other signals (SIGRTMAX, SIGALRM) work OK. Oddly,
this depends on where the program is compiled, not
where it's run.
Most unusually, under Red Hat 8.0 (glibc "2.2.93", kernel
2.4.18-14smp) the timer resolution works *far better*
than expected. On this platform it appears to be accurate
to within a few microseconds, with any interval above 4
milliseconds. I would have expected to see at best 1/512
seconds granularity (the RH kernel sets HZ to 512 instead
of the usual 100), which is the case with BSD interval
timers on that platform.
So my questions: am I doing something wrong in the code?
If not, is this a known bug in glibc and/or the kernel?
What's different in Red Hat 8.0 that makes it work so well?
Can we expect to see these improvements in mainline glibc
versions/other Linux distros in the future?
Thanks for any advice.
====< test driver - cut here >====
/* Compile with: cc timertest -lrt
* Usage:
* ./a.out [#microseconds/step [#steps]]
*/
#define POSIX_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
static volatile sig_atomic_t timer_tick = 0;
void sigalarm(int signo)
{
++timer_tick;
/* write(2,".",1); */
}
int main(int argc, char *argv[])
{
clock_t clock = CLOCK_REALTIME;
int signum = SIGRTMAX;
int microsec = 10000;
int nsteps = 100;
int status;
struct timeval time0, time1;
double dt;
timer_t timer_id;
struct itimerspec ts;
struct sigevent se;
struct sigaction act;
sigset_t sigmask;
/* Command-line arguments: */
if (argc >= 2)
microsec = atol(argv[1]);
if (argc >= 3)
nsteps = atol(argv[2]);
/* Set up signal handler: */
sigfillset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = sigalarm;
sigaction(signum, &act, NULL);
/* Set up timer: */
memset(&se, 0, sizeof(se));
se.sigev_notify = SIGEV_SIGNAL;
se.sigev_signo = signum;
se.sigev_value.sival_int = 0;
status = timer_create(clock, &se, &timer_id);
if (status < 0) {
perror("timer_create");
return EXIT_FAILURE;
}
/* Start timer: */
ts.it_interval.tv_sec = microsec / 1000000;
ts.it_interval.tv_nsec = (microsec % 1000000) * 1000;
ts.it_value = ts.it_interval;
status = timer_settime(timer_id, 0, &ts, NULL);
if (status < 0) {
perror("timer_settime");
return EXIT_FAILURE;
}
/* Tick */
gettimeofday(&time0, NULL);
/* Loop: */
sigemptyset(&sigmask);
while (timer_tick < nsteps)
sigsuspend(&sigmask);
/* Tock */
gettimeofday(&time1, NULL);
time1.tv_usec -= time0.tv_usec;
time1.tv_sec -= time0.tv_sec;
dt = (double)time1.tv_sec + (((double)time1.tv_usec) / 1000000.0);
printf("\nTotal time: %f (%f%%)\n",
dt, (dt * 100.0 * 1000000.0) / (nsteps * (double)microsec) );
printf("Overruns: %d\n", timer_getoverrun(timer_id));
timer_delete(timer_id);
return EXIT_SUCCESS;
}
/*EOF*/
====< test driver - cut here >====
--Joe English
address@hidden
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Posix timers,
Joe English <=