当前位置: 首页 > 面试题库 >

Linux,timerfd准确性

李和昶
2023-03-14
问题内容

我的系统需要至少10毫秒的计时器精度。
我选择了timerfd,因为它非常适合我,但是发现即使在长达15毫秒的时间内,它也不是完全准确的,或者是我不理解它是如何工作的。

在一个10毫秒的计时器上,我测量的时间高达21毫秒。
我已经进行了一次快速测试,以显示我的问题。
这里是一个测试:

#include <sys/timerfd.h>
#include <time.h>
#include <string.h>
#include <stdint.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:");
    }
    uint64_t expirations = 0;
    int iterations = 0;
    while( res = read(timerfd, &expirations, sizeof(expirations))){
        if(res < 0){ perror("read:"); continue; }
        if(expirations > 1){
            printf("%lld expirations, %d iterations\n", expirations, iterations);
            break;
        }
        iterations++;
    }
}

像这样执行:

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毫秒的延迟听起来也太多了。


问题答案:

尝试按以下方式进行更改,这应该确保它永远不会丢失唤醒,但要谨慎行事,因为运行实时优先级会在机器不hibernate时将其锁定,因此您可能需要进行设置您的用户可以实时运行内容(请参阅参考资料/etc/security/limits.conf

#include <sys/timerfd.h>
#include <time.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <sched.h>

int main(int argc, char *argv[]) 
{
    int timerfd = timerfd_create(CLOCK_MONOTONIC,0);
    int milliseconds = atoi(argv[1]);
    struct itimerspec timspec;
    struct sched_param schedparm;

    memset(&schedparm, 0, sizeof(schedparm));
    schedparm.sched_priority = 1; // lowest rt priority
    sched_setscheduler(0, SCHED_FIFO, &schedparm);

    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:");
    }
    uint64_t expirations = 0;
    int iterations = 0;
    while( res = read(timerfd, &expirations, sizeof(expirations))){
        if(res < 0){ perror("read:"); continue; }
        if(expirations > 1){
            printf("%ld expirations, %d iterations\n", expirations, iterations);
            break;
        }
        iterations++;
    }
}

如果您使用的是线程,则应使用pthread_setschedparam而不是sched_setscheduler

实时也与低延迟无关,它与保证有关,RT表示,如果您想每秒精确地每秒唤醒一次,那么您将,正常的调度不会给您这样做,它可能会决定将您唤醒100毫秒后来,因为当时还是有其他工作要做。如果您确实需要每10毫秒唤醒一次,那么您应该将自己设置为作为实时任务运行,然后内核将每10毫秒唤醒您一次,而不会失败。除非更高优先级的实时任务忙于做事。

如果您需要确保唤醒间隔恰好是某个时间,那么它是1毫秒还是1秒无关紧要,除非您作为实时任务运行,否则您不会得到它。内核会为您做到这一点有充分的理由(节省功率是其中之一,更高的吞吐量是另外一个,还有其他方面),但是这样做是有权利的,因为您从未告诉过您需要更好的保证。大多数东西实际上并不需要那么精确,或者永远不要错过,所以您应该认真考虑您是否真的需要它。

引用http://www.ganssle.com/articles/realtime.htm

硬实时任务或系统是必须在指定的截止日期之前(总是)完成一项活动的系统。截止日期可以是特定时间或时间间隔,也可以是某个事件的到来。根据定义,如果硬实时任务错过了这样的期限,它们就会失败。

请注意,此定义不对任务的频率或周期做出任何假设。一微秒或一周-如果错过最后期限会导致失败,那么任务对实时性有严格要求。

软实时几乎是相同的,只是错过了最后期限,尽管不是很理想,但这并不是世界末日(例如,视频和音频播放是软实时任务,您不想错过显示帧或用尽时间)缓冲区,但是如果您这样做只是暂时的打hi,您可以继续执行)。如果您想做的是“软”实时的,那么我不会为实时优先运行而烦恼,因为您通常应该及时(或至少接近)唤醒您。

编辑:

如果您不是实时运行的,则内核默认会给您提供一些“松弛”的计时器,以便它可以合并您的请求以唤醒其他事件,这些事件在接近您要求的时间发生(即是否另一个事件是在您的“空闲”时间内,它不会在您询问时唤醒您,但会早一点或晚一点,同时已经在做其他事情了,这样可以节省电量。

有关更多信息,请参阅高分辨率(但不是太高)超时和计时器松弛(请注意,我不确定这些事情中的任何一个是否真正在内核中真正存在,因为这两篇文章都是关于lkml邮件列表的讨论,但是像第一个这样的东西确实在内核中。



 类似资料:
  • 本文向大家介绍Linux 新的API signalfd、timerfd、eventfd使用说明,包括了Linux 新的API signalfd、timerfd、eventfd使用说明的使用技巧和注意事项,需要的朋友参考一下 三种新的fd加入linux内核的的版本: signalfd:2.6.22 timerfd:2.6.25 eventfd:2.6.22 三种fd的意义: lsignalfd 传统

  • 问题内容: 我需要一种非常准确的方式来计时程序的各个部分。我可以为此使用常规的高分辨率时钟,但这将返回挂钟时间,这不是我所需要的:我只需要花时间运行我的进程。 我清楚地记得看到过一个Linux内核补丁,该补丁可以使我将进程的时间定为纳秒级,但我忘了给它加上书签,也忘了补丁的名称了:(。 我记得它是如何工作的: 在每个上下文切换上,它将读取高分辨率时钟的值,并将最后两个值的增量添加到正在运行的进程的

  • 我试图在caffe中训练一个二元分类模型,它告诉输入图像是狗还是背景。我有8223个阳性样本,33472个阴性样本。我的验证集包含1200个样本,每个类600个。事实上,我的优点是摘自MS-COCO数据集的片段。所有的图像都被调整大小,所以比格维度不超过92,较小的维度不小于44。在使用create_imagenet.sh(resize=false)创建LMDB文件之后,我开始使用求解器进行训练,

  • 我注意到消息的EnqueueTimeUtc值不准确 我正在为我的系统使用ServiceBus主题和订阅者 发送方在.NET中使用“Microsoft.Azure.ServiceBus”version=“4.1.1”NuGet包编写,使用SendAsync()方法将消息发送到主题 订阅方是使用Azure.ServiceBus.Control_Client(azure-servicebus versi

  • 关于使用Lenet5网络解释MNIST上某些优化器的性能,我有几个问题,以及验证损失/精度与训练损失/精度图确切地告诉我们什么。因此,所有的事情都是在Keras中使用标准的LeNet5网络完成的,它运行了15个历元,批处理大小为128。 有两个图,列车acc vs val acc和列车损失vs val损失。我生成了4个图,因为我运行了两次,一次是validation_split=0.1,一次是va

  • 我正在开发一个网络语音识别应用程序。我正在使用recorderJS捕获声音并将其发送到后端,在那里应该使用CMU Sphinx进行处理。 在发现最新版本5Realpha的库时,我遇到了准确性问题,该库使用了默认的声学模型、语言模型和词典,后来又使用JSGF语法减少了识别的单词数量,因此我使用了1.0 beta6版本。 1.0 beta6版本的麦克风识别非常准确。然而,当我转录声音时,它总是很差。如