How to Implement Highly Accurate Timers in Linux Userspace

How to implement highly accurate timers in Linux Userspace?

Finally, after some more efforts I found a code which suggested to use timer_create(), clock_gettime() in conjunction with signal handling (handling SIGALRM), similar to what Basile Starynkevitch suggested in his comment.

I tried it on my 1 GHz Beaglebone with clock type CLOCK_MONOTONIC for the interval of 500us.

Out of 10000 times the timer expired, 2% of the time, it was exactly 500us (I ignored the nanosecond difference). and 96.6% of the time it was in the range of 500 +/- 10us. And the rest of the time, average error was not more than +/- 50us.

This is the link for the code

I have posted slightly modified version of code here. I did following modifications to the code:

  1. For small intervals ~10us the count was getting infinitely decremented, therefore I added the control on number of tests (count) inside the signal handler itself.

  2. Adding a printf in the middle of running timer costs a lot of time. Hence I stored the time difference in an array and then at the end i.e. after last test, I printed everything.

  3. I thought calculating time difference in unsigned long (i.e. in nanoseconds) is better than calculating in double (in seconds) as it is more accurate and may be fast. Hence I modified the timerdiff macro to output difference in nanoseconds. Since I am using interval of 500us or less the difference will never overflow the range of unsigned long.

As you can see even after the modifications, only 2% of the results were accurate to <1us. Therefore now I am trying some more modifications like not running unnecessary linux processes, simplifying my program more, etc.

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

#define NSEC_PER_SEC 1000000000L

#define MAX_TESTS 10000

#define timerdiff(a,b) (((a)->tv_sec - (b)->tv_sec) * NSEC_PER_SEC + \
(((a)->tv_nsec - (b)->tv_nsec)))

static struct timespec prev = {.tv_sec=0,.tv_nsec=0};
static int count = MAX_TESTS;
unsigned long diff_times[MAX_TESTS];

void handler( int signo )
{
struct timespec now;
register int i, correct=0;

if(count >= 0)
{
clock_gettime(CLOCK_MONOTONIC, &now);
diff_times[count]=timerdiff(&now, &prev);
prev = now;
count --;
}

else
{
for(i=0; i<MAX_TESTS; ++i)
{
if(diff_times[i]/1000 < 510 && diff_times[i]/1000 > 490)
{
printf("%d->\t", i);
correct++;
}
printf("%lu\n", diff_times[i]);
}
printf("-> %d\n", correct);
exit(0);
}
}

int main(int argc, char *argv[])
{
int i = 0;
timer_t t_id;

struct itimerspec tim_spec = {.it_interval= {.tv_sec=0,.tv_nsec=500000},
.it_value = {.tv_sec=1,.tv_nsec=0}};

struct sigaction act;
sigset_t set;

sigemptyset( &set );
sigaddset( &set, SIGALRM );

act.sa_flags = 0;
act.sa_mask = set;
act.sa_handler = &handler;

sigaction( SIGALRM, &act, NULL );

if (timer_create(CLOCK_MONOTONIC, NULL, &t_id))
perror("timer_create");

clock_gettime(CLOCK_MONOTONIC, &prev);

if (timer_settime(t_id, 0, &tim_spec, NULL))
perror("timer_settime");

while(1);

return 0;
}

linux high resolution timer in user space

The POSIX timers (created with timer_create()) are already high-resolution. Your problem is in the delivery method - if you want very precise timing then SIGEV_THREAD is not a good idea.

You could instead use SIGEV_SIGNAL so that timer expiry is notified via a signal, then use sigwaitinfo() to wait for it to expire. Alternately, you could use a timerfd instead of a POSIX timer (created with timerfd_create()).

Additionally, if you want your thread to preempt other running threads when the timer expires, you'll need to give it a real-time scheduling policy (SCHED_FIFO or SCHED_RR) with sched_setscheduler().

You will also want to ensure that your kernel is compiled with the CONFIG_PREEMPT option, which allows most kernel code to be preemptable. There will still be some level of jitter, caused by non-preemptible kernel work like hardware interrupts and softirqs. To reduce this further, you can try using the CONFIG_PREEMPT_RT kernel patchset.

High precision timing in userspace in Linux

clock_gettime allows you to get a nanosecond-precise time from the thread start, process start or epoch.

How to create a high resolution timer in Linux to measure program performance?

Check out clock_gettime, which is a POSIX interface to high-resolution timers.

If, having read the manpage, you're left wondering about the difference between CLOCK_REALTIME and CLOCK_MONOTONIC, see Difference between CLOCK_REALTIME and CLOCK_MONOTONIC?

See the following page for a complete example: http://www.guyrutenberg.com/2007/09/22/profiling-code-using-clock_gettime/

#include <iostream>
#include <time.h>
using namespace std;

timespec diff(timespec start, timespec end);

int main()
{
timespec time1, time2;
int temp;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
for (int i = 0; i< 242000000; i++)
temp+=temp;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
cout<<diff(time1,time2).tv_sec<<":"<<diff(time1,time2).tv_nsec<<endl;
return 0;
}

timespec diff(timespec start, timespec end)
{
timespec temp;
if ((end.tv_nsec-start.tv_nsec)<0) {
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
}
return temp;
}

Is there any high resolution clock (us) in User space (Linux)?

One option is to use rdtsc instruction via __builtin_ia32_rdtsc function. On modern Intel CPUs rdtsc ticks at base clock rate at any CPU frequency, so that you can convert the counter into nanoseconds by dividing the counter by the base (not boost) CPU frequency in GHz:

#include <regex>
#include <string>
#include <fstream>
#include <iostream>

double cpu_base_frequency() {
std::regex re("model name\\s*:[^@]+@\\s*([0-9.]+)\\s*GHz");
std::ifstream cpuinfo("/proc/cpuinfo");
std::smatch m;
for(std::string line; getline(cpuinfo, line);) {
regex_match(line, m, re);
if(m.size() == 2)
return std::stod(m[1]);
}
return 1; // Couldn't determine the CPU base frequency. Just count TSC ticks.
}

double const CPU_GHZ_INV = 1 / cpu_base_frequency();

int main() {
auto t0 = __builtin_ia32_rdtsc();
auto t1 = __builtin_ia32_rdtsc();
std::cout << (t1 - t0) * CPU_GHZ_INV << "nsec\n";
}

Some more info from Intel documentation:

Constant TSC behavior ensures that the duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if the processor core changes frequency. This is the architectural behavior moving forward.

The invariant TSC will run at a constant rate in all ACPI P-, C- and T-states. This is the architectural behavior moving forward. On processors with invariant TSC support, the OS may use the TSC for wall clock timer services (instead of ACPI or HPET timers). TSC reads are much more efficient and do not incur the overhead associated with a ring transition or access to a platform resource.

The invariant TSC is based on the invariant timekeeping hardware (called Always Running Timer or ART), that runs at the core crystal clock frequency.

The scalable bus frequency is encoded in the bit field MSR_PLATFORM_INFO[15:8] and the nominal TSC frequency can be determined by multiplying this number by a bus speed of 100 MHz.

How to get the most exact clock in linux user space application?

You want to use clock_gettime() for obtaining the current time (since startup) with either CLOCK_MONOTONIC (monotonic but not steady as it is influenced by NTP) or CLOCK_MONOTONIC_RAW (monotonic and steady, but Linux specific and requires a kernel >= 2.6.28).

For waking up at exact intervals, use clock_nanosleep() and specify TIMER_ABSTIME. Unfortunately clock_nanosleep() only supports CLOCK_MONOTONIC and not CLOCK_MONOTONIC_RAW, so you cannot pass a wakeup time obtained with CLOCK_MONOTONIC_RAW because these clocks may differ. Don't forget to check the return code for EINTR.

1ms resolution timer under linux recommended way

Polling in the main loop isn't an answer either - your process might not get much CPU time, so more than 10ms will elapse before your code gets to run, rendering it moot.

10ms is about the standard timer resolution for most non-realtime operating systems (RTOS). But it is moot in a non-RTOS - the behaviour of the scheduler and dispatcher is going to greatly influence how quickly you can respond to a timer expiring. For example even suppose you had a sub 10ms resolution timer, you can't respond to the timer expiring if your code isn't running. Since you can't predict when your code is going to run, you can't respond to timer expiration accurately.

There is of course realtime linux kernels, see http://www.linuxdevices.com/articles/AT8073314981.html for a list. A RTOS offers facilities whereby you can get soft or hard guarantees about when your code is going to run. This is about the only way to reliably and accurately respond to timers expiring etc.

Linux C/C++ Timer signal handler in userspace

setitimer(2) is a good start, but do you really want to go asynchronous with signals? Otherwise, you could have a main loop with select(2) or poll(2) and an appropiate timeout.



Related Topics



Leave a reply



Submit