【发布时间】:2010-06-26 17:38:28
【问题描述】:
我的系统需要至少 10 毫秒的计时器精度。
我选择了 timerfd,因为它非常适合我,但发现即使在长达 15 毫秒的时间内它也完全不准确,或者我不明白它是如何工作的。
在 10 毫秒计时器上,我测量的时间最长为 21 毫秒。
我整理了一个快速测试来显示我的问题。
这里是一个测试:
#include <sys/timerfd.h>
#include <time.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <inttypes.h>
int main(int argc, char *argv[]){
int timerfd = timerfd_create(CLOCK_MONOTONIC,0);
int milliseconds = atoi(argv[1]);
struct itimerspec timspec;
bzero(&timspec, sizeof(timspec));
timspec.it_interval.tv_sec = 0;
timspec.it_interval.tv_nsec = milliseconds * 1000000;
timspec.it_value.tv_sec = 0;
timspec.it_value.tv_nsec = 1;
int res = timerfd_settime(timerfd, 0, &timspec, 0);
if(res < 0){
perror("timerfd_settime:");
return 1;
}
uint64_t expirations = 0;
int iterations = 0;
while( res = read(timerfd, &expirations, sizeof(expirations))){
if(res < 0){ perror("read:"); continue; }
if(expirations > 1){
printf("%" PRIu64 " expirations, %d iterations\n", expirations, iterations);
break;
}
iterations++;
}
return 0;
}
并像这样执行:
Zack ~$ for i in 2 4 8 10 15; do echo "intervals of $i milliseconds"; ./test $i;done
intervals of 2 milliseconds
2 expirations, 1 iterations
intervals of 4 milliseconds
2 expirations, 6381 iterations
intervals of 8 milliseconds
2 expirations, 21764 iterations
intervals of 10 milliseconds
2 expirations, 1089 iterations
intervals of 15 milliseconds
2 expirations, 3085 iterations
即使假设有一些可能的延迟,15 毫秒的延迟对我来说听起来也太过分了。
【问题讨论】:
-
我关于该地区的数据相当生疏。听起来你想实时做一些事情。检查实时 Linux。否则,调度程序使用更长的粒度来避免更高的开销。您可能希望将您的进程作为 RT(实时)进程 (
man sched_setparam) 并且可能在 root 下运行。对于正常流程(例如游戏或多媒体),您会(1)在紧密循环中等待或(2)在每个计时器事件上计算错误(预期与实际唤醒时间)并在推进内部时间时将其计入帐户 -依赖状态。 -
感谢您的提示,但我不认为 20 毫秒间隔是实时域的一部分。我的意思是,一个被要求等待 10 毫秒的标准系统永远不应该等待 21 毫秒,RT 听起来太多了。
-
您可以尝试将您的程序设置为以实时优先级运行,您可能不需要使用 RT Linux 内核,这些天主线在实时方面非常好,并且考虑到它从未错过超过仅以 RT 优先级运行的一次到期应该足以让您永远不会错过一个
-
另外你应该考虑天气与否你绝对不能容忍错过唤醒,如果你有时会错过,不要担心它会发生,但这不是世界末日,你会得到其中的大部分。我正在我的系统上运行它,它还没有错过 4ms 循环上的计时器,而且我已经运行了一段时间......
-
@Arkaitz Jimenez:实时是指有严格的要求,而不是任何实际的准确度下限。影响计时器交付及时性的因素有很多,包括您使用的 Linux(内核)版本、编译时使用的配置、您使用的硬件以及系统上运行的其他内容。