如何在Linux用户空间中实现高度准确的计时器?

时间:2014-06-05 04:52:02

标签: linux timer beagleboard

我在BeagleBoard上安装了Angstrom Linux。

我想实现非常准确的计时器,可以每500us开火一次。我读到了hrtimers,但我找到的所有实现都是针对内核空间的。我想在用户空间中实现它。

是否有任何可以调用这些hrtimers的API,我可以在用户空间中使用它或在linux中实现精确计时器的任何其他方式?

我已将jiffy设置为几纳秒。

1 个答案:

答案 0 :(得分:3)

最后,经过一些努力,我找到了一个建议使用timer_create()clock_gettime()和信号处理(处理SIGALRM)的代码,类似于 Basile Starynkevitch 在他的评论中提出。

我在时钟类型为CLOCK_MONOTONIC的1 GHz Beaglebone上尝试了500us的间隔。

10000次计时器到期,2%的时间内,它正好是500us(我忽略了纳秒级差异)。以及96.6%范围内的500 +/- 10uscount。其余时间,平均误差不超过+/- 50us。

This is the link for the code

我在这里发布了稍微修改过的代码版本。我对代码进行了以下修改:

  1. 对于小间隔~10us count无限递减,因此我在信号处理程序本身内添加了对测试次数(printf)的控制。

  2. 在运行计时器的过程中添加unsigned long需要花费大量时间。因此,我将时差存储在一个数组中,然后在最后,即在最后一次测试之后,我打印了所有内容。

  3. 我认为计算double(即以纳秒为单位)的时差优于timerdiff(以秒为单位)计算,因为它更准确且可能更快。因此,我修改了unsigned long宏以输出以纳秒为单位的差异。由于我使用500us或更短的间隔,差异永远不会超出#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; } 的范围。

  4. 正如您在修改后所看到的,只有2%的结果准确到<1us。因此,现在我正在尝试一些更多的修改,比如不运行不必要的linux进程,简化我的程序等等。

    {{1}}