草庐IT

c - Linux,timerfd精度

coder 2023-06-19 原文

我的系统需要至少 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 毫秒的延迟对我来说听起来太多了。

最佳答案

尝试按如下方式更改它,这几乎可以保证它永远不会错过唤醒,但要小心,因为如果它不休眠,运行实时优先级会很难锁定你的机器,你也可能需要设置让你的用户能够以实时优先级运行东西(参见 /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

A hard real time task or system is one where an activity simply must be completed - always - by a specified deadline. The deadline may be a particular time or time interval, or may be the arrival of some event. Hard real time tasks fail, by definition, if they miss such a deadline.

Notice this definition makes no assumptions about the frequency or period of the tasks. A microsecond or a week - if missing the deadline induces failure, then the task has hard real time requirements.

软实时几乎是一样的,除了错过最后期限,虽然不受欢迎,但并不是世界末日(例如视频和音频播放是软实时任务,你不想错过显示帧,或缓冲区用完,但如果你这样做只是暂时的打嗝,你只需继续)。如果你想做的是“软”实时,我不会为以实时优先级运行而烦恼,因为你通常应该及时唤醒(或至少接近它)。

编辑:

如果您不是实时运行,内核将默认为您设置一些“松弛”的任何计时器,以便它可以将您的唤醒请求与其他在您要求的时间附近发生的事件合并(即如果另一个事件在你的“闲暇”时间之内,它不会在你要求的时间唤醒你,而是早一点或晚一点,同时它已经在做其他事情,这样可以节省电量)。

有关更多信息,请参阅 High- (but not too high-) resolution timeoutsTimer slack (请注意,我不确定这些东西中的任何一个是否正是内核中真正存在的东西,因为这两篇文章都是关于 lkml 邮件列表讨论的,但是像第一篇这样的东西确实存在于内核中。

关于c - Linux,timerfd精度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3124852/

有关c - Linux,timerfd精度的更多相关文章

  1. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

  2. ruby-on-rails - ruby on rails 模型验证中的浮点精度 - 2

    我正在尝试使用正则表达式验证美元金额:^[0-9]+\.[0-9]{2}$这工作正常,但每当用户提交表单并且美元金额以0(零)结尾时,ruby(或rails?)将0砍掉。所以500.00变成500.0,因此正则表达式验证失败。有没有办法让ruby​​/rails保持用户输入的格式,而不管尾随零? 最佳答案 我假设您的美元金额是小数类型。因此,用户在字段中输入的任何值在保存到数据库之前都会从字符串转换为适当的类型。验证适用于已转换为数字类型的值,因此在您的情况下,正则表达式并不是真正合适的验证过滤器。不过,您有几种可能性可以解决这个问

  3. 【Linux操作系统】——网络配置与SSH远程 - 2

    Linux操作系统——网络配置与SSH远程安装完VMware与系统后,需要进行网络配置。第一个目标为进行SSH连接,可以从本机到VMware进行文件传送,首先需要进行网络配置。1.下载远程软件首先需要先下载安装一款远程软件:FinalShell或者xhell7FinalShellxhell7FinalShell下载:Windows下载http://www.hostbuf.com/downloads/finalshell_install.exemacOS下载http://www.hostbuf.com/downloads/finalshell_install.pkg2.配置CentOS网络安装好

  4. Linux磁盘分区中物理卷(PV)、卷组(VG)、逻辑卷(LV)创建和(LVM)管理 - 2

    文章目录一基础定义二创建逻辑卷2-1准备物理设备2-2创建物理卷2-3创建卷组2-4创建逻辑卷2-5创建文件系统并挂载文件三扩展卷组和缩减卷组3-1准备物理设备3-2创建物理卷3-3扩展卷组3-4查看卷组的详细信息以验证3-5缩减卷组四扩展逻辑卷4-1检查卷组是否有可用的空间4-2扩展逻辑卷4-3扩展文件系统五删除逻辑卷5-1备份数据5-2卸载文件系统5-3删除逻辑卷5-4删除卷组5-5删除物理卷六LVM逻辑卷缩容6-1缩容注意事项6-2标准缩容步骤一基础定义LVM,LogicalVolumeManger,逻辑卷管理,Linux磁盘分区管理的一种机制,建立在硬盘和分区上的一个逻辑层,提高磁盘分

  5. ruby - Ruby 的任意精度算术 - 2

    Ruby到底是怎么做到的?Jörg或其他人是否知道幕后发生的事情?不幸的是,我不太了解C,所以bignum.c对我帮助不大。我只是有点好奇有人可以解释(用简单的英语)它使用的任何神奇算法背后的理论。irb(main):001:0>999**99936806348825922326789470084006052186583833823203735320465595962143702560930047223153010387361450517521869134525758989639113039318944796977164583238219236607653663113200177617

  6. ruby - 如何在 Ruby 中获取 linux 系统信息 - 2

    如何在Ruby中获取linux系统(这必须适用于Fedora、Ubuntu等)的软件/硬件信息? 最佳答案 Chef背后的优秀人才,拥有一颗名为Ohai的优秀gemhttps://github.com/opscode/ohai以散列形式返回系统信息,例如操作系统、内核、规范、fqdn、磁盘、空间、内存、用户、接口(interface)、sshkey等。它非常完整,非常好。它还会安装命令行二进制文件(也称为ohai)。 关于ruby-如何在Ruby中获取linux系统信息,我们在Stack

  7. ruby - rbenv:在 Linux Mint 上找不到 gem 命令 - 2

    我在LinuxMint17.2上。我最近使用apt-getpurgeruby​​删除了ruby​​。然后我安装了rbenv然后rbenvinstall2.3.0所以现在,~/.rbenv/versions/2.3.0/bin/ruby存在。但是现在,我无法执行geminstallrubocop。我明白了:$geminstallrubocoprbenv:gem:commandnotfoundThe`gem'commandexistsintheseRubyversions:2.3.0但是我可以~/.rbenv/versions/2.3.0/bin/geminstallrubocop。但是,

  8. ruby - 在 Linux 上编译 Ruby 1.9.2 所需的先决条件? - 2

    我是Ruby和RoR的新手。我有一个带有Ubuntu镜像的干净Linode实例,我想从源代码编译Ruby而不是使用apt-get。我已经在谷歌上搜索了执行此操作的说明,但经过一些尝试后,当我尝试运行一些教程示例时,我不断收到有关缺少zlib和其他一些包的错误。任何人都可以给我详细的说明(或链接),教我如何在从源代码编译Ruby之前安装必要的必备包吗?我的目的是编译Ruby的最新稳定版本,然后安装Rubygems和Rails。提前感谢您的帮助!!! 最佳答案 Thisblogpost涵盖从源代码编译ruby​​所需的包和安装过程;它引

  9. ruby-on-rails - Rails 2.3.11 DateTime BigDecimal 精度 - 2

    我目前有一个运行Ruby1.8.7和Rails2.3.2的RubyonRails项目我有一些从数据库中读取数据的单元测试,特别是两个连续项目的日期时间列,这两个项目应该相隔24小时。在一项测试中,我将项目2的日期时间设置为与项目1的日期时间相同。当我执行断言以确保两个值相等时,测试在rails2.3.2下工作正常。当我升级到rails2.3.11时,测试失败显示两次之间的差异将关闭并出现以下错误:expectedbutwas.这两个版本的rails中似乎存在浮点转换问题。如何解决float问题? 最佳答案 这也发生在我身上,我最终这

  10. Linux网络编程必备的POSIX API的细节 - 2

    目录POSIXAPI大集合五元组三次握手的过程,内核协议栈分析listen函数DDOS攻击,洪水攻击DDOS攻击的应对措施数据发送 怎么保证顺序?如何保证包地顺序到达(序号+确认应答机制+重传)TCP断开连接的过程问题1.大量的CLOSE_WAIT+FIN_WAIT2是为啥?time_wait状态存在的原因?POSIXAPI大集合五元组(sip,sport,dip,dport,protocol)三次握手的过程,内核协议栈分析内核协议栈中是有内核数据结构的.  我们send/write数据,都是先发送到内核协议栈中,然后由内核协议栈封装发送到物理介质中传输到对端的对端的接收过程也是经有内核协议栈

随机推荐