【问题标题】:Linux clock_gettime() elapse spikes?Linux clock_gettime() 过去的尖峰?
【发布时间】:2014-05-29 06:55:56
【问题描述】:

我正在尝试在 linux 上获取高分辨率时间戳。使用clock_gettime(),如下所示,我得到了“尖峰”时间,在将近26微秒的时间里看起来非常可怕。大多数“dt”约为 30 ns。我在 linux 2.6.32,Red Hat 4.4.6 上。 'lscpu' 显示 CPU MHz=2666.121。我认为这意味着每个时钟滴答需要大约 2 ns。因此,在这里要求 ns 分辨率似乎并不过分。

程序的输出(抱歉无法在没有列出列表的情况下发布此内容。它认为它是某种方式的代码)

  • 1397534268,40823395 1397534268,40827950,dt=4555
  • 1397534268,41233555 1397534268,41236716,dt=3161
  • 1397534268,41389902 1397534268,41392922,dt=3020
  • 1397534268,46488430 1397534268,46491674,dt=3244
  • 1397534268,46531297 1397534268,46534279,dt=2982
  • 1397534268,46823368 1397534268,46849336,dt=25968
  • 1397534268,46915657 1397534268,46918663,dt=3006
  • 1397534268,51488643 1397534268,51491791,dt=3148
  • 1397534268,51530490 1397534268,51533496,dt=3006
  • 1397534268,51823307 1397534268,51826904,dt=3597
  • 1397534268,55823359 1397534268,55827826,dt=4467
  • 1397534268,60531184 1397534268,60534183,dt=2999
  • 1397534268,60823381 1397534268,60844866,dt=21485
  • 1397534268,60913003 1397534268,60915998,dt=2995
  • 1397534268,65823269 1397534268,65827742,dt=4473
  • 1397534268,70823376 1397534268,70835280,dt=11904
  • 1397534268,75823489 1397534268,75828872,dt=5383
  • 1397534268,80823503 1397534268,80859500,dt=35997
  • 1397534268,86823381 1397534268,86831907,dt=8526

有什么想法吗?谢谢

#include <vector>
#include <iostream>
#include <time.h>
long long elapse( const timespec& t1, const timespec& t2 ) 
{
    return ( t2.tv_sec * 1000000000L + t2.tv_nsec ) - 
        t1.tv_sec * 1000000000L + t1.tv_nsec ); 

}
int main()
{
    const unsigned n=30000;
    timespec ts;
    std::vector<timespec> t( n );
    for( unsigned i=0; i < n; ++i )
    {
        clock_gettime( CLOCK_REALTIME, &ts );
        t[i] = ts;
    }
    std::vector<long> dt( n );
    for( unsigned i=1; i < n; ++i )
    {
        dt[i] = elapse( t[i-1], t[i] );
        if( dt[i] > 1000 )
        {
            std::cerr << 
                t[i-1].tv_sec << "," 
                << t[i-1].tv_nsec << " " 
                << t[i].tv_sec << "," 
                << t[i].tv_nsec 
                << ",dt=" << dt[i] << std::endl;
        }
        else 
        { 
            //normally I get dt[i] = approx 30-35 nano secs 
        }
    }
    return 0;
}

【问题讨论】:

  • 你的进程是由内核调度的。所以它不能一直运行。
  • @Basile - 谢谢。无论如何它总是运行?我实际上尝试修改代码以使用 pthread_setaffinity_np 将其绑定到 cpu。但似乎对结果影响不大。
  • 不,内核负责调度进程(但你可以让你的进程成为实时进程)。

标签: linux time clock


【解决方案1】:

你能用clock_getres()检查分辨率吗?

【讨论】:

  • tv_sec 返回 0,tv_nsec 返回 1。
【解决方案2】:

您引用的数字在 3 到 30 微秒范围内(3,000 到 30,000 纳秒)。时间太短,无法将上下文切换到另一个线程/进程,让另一个线程运行,然后将上下文切换回您的线程。很可能您的进程正在运行的内核被内核用于服务外部中断(例如网卡、磁盘、计时器),然后返回运行您的进程。

您可以使用此命令查看 linux 中断计数器(每个 CPU 内核和每个源)

watch -d -n 0.2 cat /proc/interrupts

-n 0.2 将使命令以 5Hz 发出,-d 标志将突出显示已更改的内容。

中断源也可以是TLB shootdown,这会导致IPI (Inter-Processor Interrupt)。你可以阅读更多关于TLB shootdowns here的信息。

如果您想减少运行线程/进程的内核所服务的中断数量,您需要设置中断亲和性。您可以了解有关 Red Hat 中断和 IRQ(中断请求)调整 here 和 here 的更多信息。

值得注意的是,您使用的 CLOCK_REALTIME 不能保证“流畅”,它可能会因为系统时钟为 "disciplined" 而跳来跳去,以通过 NTP(网络时间协议)等服务保持准确的时间或 PTP(精确时间协议)。出于您的目的,最好使用CLOCK_MONOTONIC,您可以阅读更多关于here 的区别。当时钟被“训练”时,时钟可以跳“步” - 这是不寻常的,当然不是你看到的许多尖峰的原因。

【讨论】:

    【解决方案3】:

    我怀疑您在这里测量的是所谓的“操作系统噪音”。这通常是由于您的程序被操作系统抢占了。然后操作系统执行其他工作。原因有很多,但通常是:其他可运行的任务、硬件中断或定时器事件。

    FTQ/FWQ 基准测试旨在衡量这一特征,摘要包含一些进一步的信息: https://asc.llnl.gov/sequoia/benchmarks/FTQ_summary_v1.1.pdf

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-14
      • 1970-01-01
      • 2010-09-19
      • 2012-12-28
      • 2015-04-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多