【问题标题】:Self-correcting periodic timer using gettimeofday()使用 gettimeofday() 进行自校正周期性定时器
【发布时间】:2014-09-29 21:48:59
【问题描述】:

我有一个循环,它运行每个 X usecs,其中包括执行一些 I/O,然后为剩余的 X usecs 休眠。为了(粗​​略)计算睡眠时间,我所做的就是在 I/O 之前和之后获取时间戳,然后从 X 中减去差值。这是我用于时间戳的函数:

long long getus ()
{
        struct timeval time;
        gettimeofday(&time, NULL);
        return (long long) (time.tv_sec + time.tv_usec);
}

您可以想象,这开始漂移得非常快,并且 I/O 突发之间的实际时间通常比 X 长几毫秒。 为了让它更准确一点,我想也许如果我记录上一个开始时间戳,每次我开始一个新周期时,我都可以计算上一个周期花费了多长时间(这个开始时间戳和上一个时间戳之间的时间)一)。然后,我知道它比 X 长了多少,并且我可以修改我的睡眠以补偿这个周期。

这是我尝试实现它的方式:

    long long start, finish, offset, previous, remaining_usecs;
    long long delaytime_us = 1000000;

    /* Initialise previous timestamp as 1000000us ago*/
    previous = getus() - delaytime_us;
    while(1)
    {
            /* starting timestamp */
            start = getus();

            /* here is where I would do some I/O */

            /* calculate how much to compensate */
            offset = (start - previous) - delaytime_us;

            printf("(%lld - %lld) - %lld = %lld\n", 
                    start, previous, delaytime_us, offset);

            previous = start;

            finish = getus();

            /* calculate to our best ability how long we spent on I/O.
             * We'll try and compensate for its inaccuracy next time around!*/
            remaining_usecs = (delaytime_us - (finish - start)) - offset;

            printf("start=%lld,finish=%lld,offset=%lld,previous=%lld\nsleeping for %lld\n",
                    start, finish, offset, previous, remaining_usecs);

            usleep(remaining_usecs);

    }

它似乎在循环的第一次迭代中工作,但之后事情变得一团糟。

这是循环 5 次迭代的输出:

(1412452353 - 1411452348) - 1000000 = 5
start=1412452353,finish=1412458706,offset=5,previous=1412452353
sleeping for 993642

(1412454788 - 1412452353) - 1000000 = -997565
start=1412454788,finish=1412460652,offset=-997565,previous=1412454788
sleeping for 1991701

(1412454622 - 1412454788) - 1000000 = -1000166
start=1412454622,finish=1412460562,offset=-1000166,previous=1412454622
sleeping for 1994226

(1412457040 - 1412454622) - 1000000 = -997582
start=1412457040,finish=1412465861,offset=-997582,previous=1412457040
sleeping for 1988761

(1412457623 - 1412457040) - 1000000 = -999417
start=1412457623,finish=1412463533,offset=-999417,previous=1412457623
sleeping for 1993507

输出的第一行显示上一个周期时间是如何计算的。看起来前两个时间戳基本上相隔1000000us(1412452353 - 1411452348 = 1000005)。然而,在此之后,起始时间戳之间的距离以及偏移量开始看起来不太合理。 有谁知道我在这里做错了什么?

编辑:我也欢迎提出更好的方法来获得准确的计时器并成为 可以在延迟期间睡觉!

【问题讨论】:

    标签: timer gettimeofday


    【解决方案1】:

    经过更多研究,我发现这里有两点错误- 首先,我计算的时间戳错误。 getus() 应该像这样返回:

    return (long long) 1000000 * (time.tv_sec + time.tv_usec);

    其次,我应该将时间戳存储在unsigned long longuint64_t 中。 所以 getus() 应该是这样的:

    uint64_t getus ()
    {
            struct timeval time;
            gettimeofday(&time, NULL);
            return (uint64_t) 1000000 * (time.tv_sec + time.tv_usec);
    }
    

    我实际上要到明天才能测试这个,所以我会回来报告。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-20
      • 1970-01-01
      • 2021-11-30
      • 1970-01-01
      • 1970-01-01
      • 2013-08-21
      相关资源
      最近更新 更多