【问题标题】:Sub-millisecond precision timing in C or C++C 或 C++ 中的亚毫秒精度计时
【发布时间】:2011-02-23 16:42:12
【问题描述】:

有哪些技术/方法可以在 C 或 C++ 中获取亚毫秒级精度的时序数据,它们提供的精度和准确度如何?我正在寻找不需要额外硬件的方法。该应用程序需要等待大约 50 微秒 +/- 1 微秒,同时一些外部硬件会收集数据。

编辑:操作系统是 Wndows,可能是 VS2010。如果我可以在 Linux 上获得硬件的驱动程序和 SDK,我可以使用最新的 GCC 去那里。

【问题讨论】:

  • 获得精度的唯一方法是通过硬件......
  • 主机上有哪些操作系统和硬件?它变化很大,几乎总是有警告;通常,您必须寻求“足够好”的解决方案,并且仍然对诸如时间倒流之类的事情有些偏执。
  • 什么类型的接口用于与硬件通信?

标签: c++ c time


【解决方案1】:

在处理现成的操作系统时,准确的计时是一项极其困难和复杂的任务。如果您真的需要有保证的时间,唯一真正的选择是完整的实时操作系统。但是,如果“几乎总是”足够好,那么您可以使用以下技巧,在商品 Windows 和 Linux 下提供良好的准确性

  1. 使用Sheilded CPU 基本上,这意味着关闭选定 CPU 的 IRQ 关联并为机器上的所有其他进程设置处理器关联掩码以忽略目标 CPU。在您的应用程序上,将 CPU 关联设置为仅在您的屏蔽 CPU 上运行。实际上,这应该可以防止操作系统暂停您的应用,因为它将始终是该 CPU 的唯一可运行进程。
  2. 永远不要让您的进程自愿将控制权交给操作系统(对于非实时操作系统而言,这本质上是不确定的)。没有内存分配,没有套接字,没有互斥体,nada。使用 RDTSC 在 while 循环中旋转,等待您的目标时间到达。它会消耗 100% 的 CPU,但这是最准确的方法。
  3. 如果数字 2 有点过于苛刻,您可以“短暂睡眠”,然后将 CPU 烧到您的目标时间。在这里,您可以利用操作系统以设定的时间间隔调度 CPU 的事实。通常每秒 100 次或每秒 1000 次,具体取决于您的操作系统和配置(在 Windows 上,您可以使用多媒体 API 将默认调度周期从 100/s 更改为 1000/s)。这可能有点难以正确解决,但本质上您需要确定操作系统调度周期何时发生并计算目标唤醒时间之前的时间。睡眠这段时间,然后在醒来时旋转 RDTSC(如果您在单个 CPU 上...使用 QueryPerformanceCounter 或 Linux 等价物,如果不是),直到您的目标时间到达。有时,操作系统调度会导致您错过,但总的来说,这种机制工作得很好。

这似乎是一个简单的问题,但您的时序约束越严格,获得“良好”时序的难度就越大。祝你好运!

【讨论】:

    【解决方案2】:

    硬件(因此分辨率)因机器而异。在 Windows 上,特别是(我不确定其他平台),您可以使用 QueryPerformanceCounterQueryPerformanceFrequency,但请注意,您应该从同一个线程调用两者,并且没有关于分辨率的严格保证(QueryPerformanceFrequency 允许返回 0 表示没有高分辨率计时器可用)。但是,在大多数现代桌面上,应该有一个精确到微秒的时间。

    【讨论】:

    • 您最终可能会轮询不同的 CPU 内核。 BIOS 或其他固件中的错误可能会产生不良结果。高性能计时器是我个人解决高分辨率计时问题的选择。它可以达到每个时钟的精度。
    • 如果您想要可预测的结果,请不要不要使用这些函数。该周期可能取决于 CPU 时钟频率,现在该频率因工作负载而异。
    【解决方案3】:

    boost::datetime 具有微秒精度的时钟,但其精度取决于平台。

    文档说明:

    ptime microsec_clock::local_time() “使用亚秒分辨率时钟获取本地时间。在 Unix 系统上,这是使用 GetTimeOfDay 实现的。在大多数 Win32 平台上,它是使用 ftime 实现的。Win32 系统通常无法通过此 API 实现微秒分辨率。如果更高的分辨率对您的应用程序测试您的平台以查看达到的分辨率。”

    http://www.boost.org/doc/libs/1_43_0/doc/html/date_time/posix_time.html#date_time.posix_time.ptime_class

    【讨论】:

      【解决方案4】:

      您可以尝试以下方法:

      结构时间 t; gettimeofday(&t,0x0);

      这将为您提供以微秒为单位的当前时间戳。我不确定准确性。

      【讨论】:

        【解决方案5】:

        您可以尝试here 中描述的技术,但它不可移植。

        【讨论】:

          【解决方案6】:

          大多数现代处理器都有用于计时或其他检测目的的寄存器。例如,自 Pentium 时代以来的 x86 上就有 RDTSC 指令。您的编译器可能会让您访问此指令。

          请参阅wikipedia 了解更多信息。

          【讨论】:

          • 这真是个坏主意,因为频率会根据现代 CPU 上的工作负载而变化。此外,TSC 在某些多核 CPU 上不同步,因此当线程在不同核上运行时,您可以获得较低的值。
          • +1:我用过这个宏:#define rdtscl(low) __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
          • @Alex,好吧,问题确实是“大约”,当然答案将取决于操作系统和特定的处理器。这就是为什么我指向解释权衡的维基百科页面。
          • @Axel:这个想法还不错,但是您必须在每次程序启动时对您的硬件进行 etalonate。还有其他缺点,例如您的硬件可能会根据负载改变频率(通常在记事本上)。
          • @Doug 运行程序时频率从 3Ghz 下降到 1Ghz 的可能性不大。这不再属于“大约”类别。
          【解决方案7】:

          sys/time.h 中的 timeval 有一个成员 'tv_usec',单位为微秒。

          此链接和下面的代码将有助于说明:

          http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/time.h.html

          timeval start;
          timeval finish;
          
          long int sec_diff;
          long int mic_diff;
          
          gettimeofday(&start, 0);
          cout << "whooo hooo" << endl;
          gettimeofday(&finish, 0);
          
          sec_diff = finish.tv_sec - start.tv_sec;
          mic_diff = finish.tv_usec - start.tv_usec;
          
          cout << "cout-ing 'whooo hooo' took " << sec_diff << "seconds and " << mic_diff << " micros." << endl;
          
          gettimeofday(&start, 0);
          printf("whooo hooo\n");
          gettimeofday(&finish, 0);
          
          sec_diff = finish.tv_sec - start.tv_sec;
          mic_diff = finish.tv_usec - start.tv_usec;
          
          cout << "fprint-ing 'whooo hooo' took " << sec_diff << "seconds and " << mic_diff << " micros." << endl;
          

          【讨论】:

            【解决方案8】:

            祝你好运尝试使用 MS Windows 做到这一点。你需要一个实时操作系统,也就是说,一个保证定时可重复的操作系统。 Windows 可以在不合时宜的时候切换到另一个线程甚至另一个进程。您也无法控制缓存未命中。

            当我在做实时机器人控制时,我使用了一个名为 OnTime RTOS32 的非常轻量级的操作系统,它具有部分 Windows API 仿真层。我不知道它是否适合你正在做的事情。但是,对于 Windows,您可能永远无法证明它永远不会不及时响应。

            【讨论】:

              【解决方案9】:

              GetSystemTimeAsFileTimeQueryPerformanceCounter 的组合可以生成一套可靠的代码,以在 Windows 上获得微秒级分辨率时间服务。

              在此处的另一个线程中查看this 评论。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-03-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-01-20
                相关资源
                最近更新 更多