代码之家  ›  专栏  ›  技术社区  ›  Bernard

GetTimeOfDay()是否保证具有微秒分辨率?

  •  88
  • Bernard  · 技术社区  · 17 年前

    我正在将最初为win32 api编写的游戏移植到linux(好吧,将win32端口的os x端口移植到linux)。

    我已经实施了 QueryPerformanceCounter 通过给出过程启动后的使用条件:

    BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
    {
        gettimeofday(&currentTimeVal, NULL);
        performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
        performanceCount->QuadPart *= (1000 * 1000);
        performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);
    
        return true;
    }
    

    这个,再加上 QueryPerformanceFrequency() 给定一个常数1000000作为频率,效果很好 在我的机器上 ,给我一个包含 uSeconds 从程序启动开始。

    所以 这是便携式的吗? 我不想发现如果内核是以某种方式或类似的方式编译的,它的工作方式会有所不同。不过,我认为它不可移植到Linux以外的其他地方。

    10 回复  |  直到 7 年前
        1
  •  56
  •   Paul Fleming    12 年前

    也许吧。但你有更大的问题。 gettimeofday() 如果系统上有进程更改计时器(即ntpd),则可能导致不正确的计时。不过,在“普通”Linux上,我相信 GETTimeFay.() 是10US。因此,它可以根据系统上运行的进程向前、向后和计时。这有效地回答了你的问题。

    你应该调查一下 clock_gettime(CLOCK_MONOTONIC) 用于定时间隔。由于多核系统和外部时钟设置等原因,它的问题较少。

    此外,请查看 clock_getres() 功能。

        2
  •  41
  •   Evan Teran    15 年前

    英特尔处理器的高分辨率、低开销定时

    如果您使用的是Intel硬件,下面介绍如何读取CPU实时指令计数器。它将告诉您自启动处理器以来执行的CPU周期数。这可能是用于性能度量的最好的粒度计数器。

    请注意,这是CPU周期数。在Linux上,您可以从/proc/cpuinfo获得CPU速度,然后除以得到秒数。把这个换成双份的非常方便。

    当我把这个放在我的盒子上时,我会

    11867927879484732
    11867927879692217
    it took this long to call printf: 207485
    

    这里是 Intel developer's guide 这提供了大量的细节。

    #include <stdio.h>
    #include <stdint.h>
    
    inline uint64_t rdtsc() {
        uint32_t lo, hi;
        __asm__ __volatile__ (
          "xorl %%eax, %%eax\n"
          "cpuid\n"
          "rdtsc\n"
          : "=a" (lo), "=d" (hi)
          :
          : "%ebx", "%ecx");
        return (uint64_t)hi << 32 | lo;
    }
    
    main()
    {
        unsigned long long x;
        unsigned long long y;
        x = rdtsc();
        printf("%lld\n",x);
        y = rdtsc();
        printf("%lld\n",y);
        printf("it took this long to call printf: %lld\n",y-x);
    }
    
        3
  •  18
  •   Tony Delroy    14 年前

    @伯纳德:

    我不得不承认,你的大多数例子都是直接在我的头脑中出现的。不过,它确实可以编译,而且似乎可以工作。这对SMP系统或SpeedStep安全吗?

    这是个好问题…我想代码没问题。 从实际出发,我们每天都在公司使用它, 我们在一个相当宽的盒子上运行,从2到8个核心。 当然,YMMV等,但它似乎是一个可靠的低开销 (因为它不会使上下文切换到系统空间)方法 计时的

    一般来说,它的工作原理是:

    • 将代码块声明为汇编程序(和volatile,因此 优化器将单独使用它)。
    • 执行cpuid指令。除了获得一些CPU信息 (我们不做任何事情)它同步CPU的执行缓冲区 这样时间就不会受到无序执行的影响。
    • 执行RDTSC(读取时间戳)执行。这将获取 自处理器复位后执行的机器周期。这是64位的 值,所以在当前的CPU速度下,它将大约每194年一次。 有趣的是,在最初的Pentium引用中,他们注意到它围绕 5800年左右。
    • 最后几行将寄存器中的值存储到 变量hi和lo,并将其放入64位返回值中。

    具体说明:

    • 无序执行可能导致错误的结果,因此我们执行 “cpuid”指令,除了提供一些信息 关于CPU还同步任何无序的指令执行。

    • 大多数操作系统在启动时同步CPU上的计数器,因此 答案很好,在几纳米之内。

    • 冬眠的评论可能是真的,但实际上你 可能不在乎冬眠的时间。

    • 关于speedstep:更新的Intel CPU补偿了速度 更改并返回调整后的计数。我做了个快速扫描 我们网络上的一些盒子只找到一个盒子 没有:奔腾3运行着一些旧的数据库服务器。 (这些是Linux框,所以我选择了:grep constant_tsc/proc/cpuinfo)

    • 我不确定AMD的CPU,我们主要是一家英特尔公司, 虽然我知道我们的一些低级系统大师 AMD评价。

    希望这能满足你的好奇心,这是一个有趣的(imho) 在编程的研究领域。你知道杰夫和乔尔什么时候 讨论程序员是否应该知道C?我是 对他们大喊大叫,“嘿,忘了那些高级的C级东西……汇编程序 如果你想知道电脑是什么,你应该学什么 “干!”

        4
  •  14
  •   CesarB    16 年前
        5
  •  11
  •   Vincent Robert    17 年前

    Wine实际上使用getTimeOfDay()来实现queryPerformanceCounter(),它可以使许多Windows游戏在Linux和Mac上运行。

    开始 http://source.winehq.org/source/dlls/kernel32/cpu.c#L312

    导致 http://source.winehq.org/source/dlls/ntdll/time.c#L448

        6
  •  10
  •   vitaut    11 年前

    所以它明确地表示微秒,但表示系统时钟的分辨率是未知的。我想,在这种情况下,分辨率意味着它将以何种方式递增?

    数据结构被定义为以微秒为测量单位,但这并不意味着时钟或操作系统实际上能够精确测量。

    就像其他人建议的那样, gettimeofday() 这很糟糕,因为设置时间可能会导致时钟偏移,从而导致计算错误。 clock_gettime(CLOCK_MONOTONIC) 是你想要的,而且 clock_getres() 会告诉你时钟的精度。

        7
  •  9
  •   Vineet Jain    7 年前

    getTimeOfDay()的实际分辨率取决于硬件体系结构。Intel处理器和SPARC机器提供可测量微秒的高分辨率计时器。其他硬件架构会退回到通常设置为100Hz的系统计时器。在这种情况下,时间分辨率将不太准确。

    我是从 High Resolution Time Measurement and Timers, Part I

        8
  •  5
  •   CodingWithoutComments    17 年前

    根据我的经验,以及我在互联网上看到的,答案是“不”,这是不确定的。它取决于CPU的速度、操作系统、Linux的风格等。

        9
  •  5
  •   Community CDub    8 年前

    This answer 提到正在调整时钟的问题。你的问题,保证蜱单位和问题的时间调整,解决了在C++ 11与 <chrono> 图书馆。

    时钟 std::chrono::steady_clock 它保证不会被调整,而且相对于实时,它将以恒定的速度前进,所以像speedstep这样的技术一定不会影响它。

    您可以通过转换为 std::chrono::duration 专业化,如 std::chrono::microseconds . 对于这种类型,勾号值使用的单位没有歧义。但是,请记住,时钟不一定有这个分辨率。您可以将持续时间转换为阿秒,而实际上没有精确的时钟。

        10
  •  3
  •   CesarB    16 年前

    在SMP系统中读取RDTSC是不可靠的,因为每个CPU都维护自己的计数器,并且每个计数器不保证与另一个CPU同步。

    我建议你试试 clock_gettime(CLOCK_REALTIME) . POSIX手册指出,这应该在所有兼容系统上实现。它可以提供纳秒计数,但您可能需要检查 clock_getres(CLOCK_REALTIME) 在您的系统上查看实际分辨率。