Using setitimer of your favorite posix kernel
As this was requested in a comment of a previous post and knowing your kernel helps to write better performing systems here is a small information of how to use the interval timers provided by your posix kernel.
What is the interval itime?r
The interval timer is managed and provided by your kernel. Everytime the interval of the timer expires the kernel wil send a signal to your application. The kernel is providing three different interval timers for every application. The different timers are for measuring the real time passed on the system, the time your application is actually executed and finally the profiling timer which tmes the time when your application is executed and when the system is executing on behalf of your application. More information can be found in the manpage with the name setitimer.
Why is it useful?
In the QtWebKit Performance Measurement Utilities we are using the interval itimer as the timing implementation for our Benchmark Macros. To be more precise we are using the ITIMER_PROF to measure the time we spend executing in the system and in the application, we are using the smallest possible precision of this timer with one microsecond. The big benefit os using this instead of elapsed real time, e.g. with QTime::elapsed, is that we are not depending so much on system scheduling. This can be really nice as even with a lightly crouded system we can generate stable times, the only thing influecing the timing is the MHZ of the CPU.
How is it implemented?
It is a kernel timer, this means that it is implemented in your kernel. In case of Linux you should be able to find a file called kernel/itimer.c, it defines the syscall setitimer at the bottom of the file. In our case the SIGPROF seems to be generated in kernel/posix-cpu-timers.c in the check_cpu_itimer routine. Of course the timer needs to be accounted by things like kernel/sched.c when scheduling tasks to run…
How to make use of it?
We want to use ITIMER_PROF, according to the manpage this will generate the SIGPROF. This means we need to have a signal handler for that, then we need to have a way to start the timer. So let us start with the SIGPROF handling.
Elapsed time handling
static unsigned int sig_prof = 0;
static void sig_profiling()
{
++sig_prof;
}
The signal handler
struct sigaction sa;
sa.sa_handler = sig_profiling;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGPROF, &sa, 0) != 0) {
fprintf(stderr, “Failed to register signal handler.n”);
exit(-1);
}
Start the timer
tatic void startTimer()
{
sig_prof = 0;
struct itimerval tim;
tim.it_interval.tv_sec = 0;
tim.it_interval.tv_usec = 1;
tim.it_value.tv_sec = 0;
tim.it_value.tv_usec = 1;
setitimer(ITIMER_PROF, &tim, 0);
}
Discussion of the implementation
What is missing? We are using the sigaction API… we should make use of the siginfo_t passed inside the signal handler.
What if we need a higher precision or need to handle overflows?
There is the POSIX.1b timer API which provides timers in the nanosec region and also providers information about overflows (e.g. when the signal could not be delivered in timer). More information can be found when looking at the timer_create functions.
When is the interval timer not useufl?
Imagine you want to measure time it takes to complete a download and someone wrote code like this:
QTimer::singleShot(this, SLOT(finishDownload())), 300000);
In this case to finish the download a lot of real time will pass and the app might be considered very slow, but it in terms of the itimer only little will be executed as the time we just sleep is not accounted on us. This means the itimer can be the wrong thing to use when you want to measure real time, e.g. latency or time to complete network operations.