这个时钟滴答声在Intel i3上适用吗?

10

我采用在线方式来衡量SSE性能。

#ifndef __TIMER_H__
#define __TIMER_H__

#pragma warning (push)
#pragma warning (disable : 4035)    // disable no return value warning

__forceinline  unsigned int GetPentiumTimer()
{
    __asm
    {
        xor   eax,eax             // VC won't realize that eax is modified w/out this
                                  //   instruction to modify the val.
                                  //   Problem shows up in release mode builds
        _emit 0x0F                // Pentium high-freq counter to edx;eax
        _emit 0x31                // only care about low 32 bits in eax

        xor   edx,edx             // so VC gets that edx is modified
    }
}

#pragma warning (pop)

#endif

我对我的 Pentium D E2200 CPU 进行了测量,结果很好(显示对齐的 SSE 指令更快)。 但是在我的 i3 CPU 上,70% 的测试中未对齐的指令更快。

你们认为这个时钟滴答测量方法不适用于 i3 CPU 吗?


我非常确定VC支持内联汇编中的RDTSC指令。另外,为什么你不关心高32位,并且你应该使用__declspec(naked)或者更好的方式返回值。此外,我想使用QueryPerformanceCounter或类似的函数(注意频率缩放/多核处理器等问题)。 - user786653
1
RDTSC不是一个序列化指令,这意味着它可以/将会乱序执行。如果您坚持直接使用它,通常需要使用CPUID来强制序列化(它是您可以在用户模式下执行的少数序列化指令之一)。 - Jerry Coffin
我也有QueryPerformanceCounter。根据结果来看,它并不是非常可靠。对于nxn矩阵乘法,当n = 10000或更高时,时间仅需要0.3秒?我认为这根本不准确(在控制台上需要超过2秒才能看到结果),所以我转向时钟滴答声。我现在要尝试RDTSC。谢谢。 - CppLearner
如果您使用的是Windows平台,我也建议使用QueryPerformanceCounter - AJG85
如果您想使用原始的 rdtsc,请使用 __rdtsc() 内置函数。如何获取 CPU 周期计数? - Peter Cordes
4个回答

4
在Windows系统中,QueryPerformanceCounter函数明显比内联汇编更好。我看不出使用内联汇编的理由(在Visual Studio上编译x64时,它会给你带来问题,因为它不支持内联汇编)。

2

对于短代码片段的性能测量,RDTSC指令(0F 31)仍然可能有用,即使是对于i3 CPU。如果任务切换和线程迁移到不同的核心的影响没有打扰到你,那么使用RDTSC是可以的。在许多情况下,通过CPUID强制序列化可以获得更精确的结果。

至于你的测量,很可能i3上未对齐的SSE表现更快。最新的英特尔处理器(Nehalem和Sandy Bridge架构)可以非常高效地处理未对齐的内存操作数。肯定不会超过对齐指令,但如果其他因素影响了测试性能,则对齐指令可能似乎工作更慢。

编辑:

请参见http://www.agner.org/optimize/#testp。这是使用RDTSC指令的一个很好的示例。


2

正如其他人所指出的那样,你应该使用QueryPerformanceCounter。

但如果你真的想使用汇编语言,最好的方法可能是使用内置函数__rdtsc。

如果你不想使用内置函数,那么这可能是最好的方法:

unsigned __int64 __declspec(naked) GetPentiumTimer() {
    __asm {
        rdtsc
        ret
    }
}

据我所知,Visual C++ 拒绝为任何使用内联汇编的函数进行内联。通过使用 __declspec(naked),您可以告诉编译器正确处理寄存器使用。

但是使用内在函数将是最好的选择,这样编译器将知道使用了哪些寄存器,并以适当的方式进行内联。


不,MSVC可以内联使用__asm的函数,如果你不将它们设置为naked。但是一定要使用__rdtsc内置函数;它在32/64位和gcc/clang/ICC之间是可移植的。如何获取CPU周期计数? - Peter Cordes

1

QueryPerformanceCounter() 是在 Windows 上获取高频计时器最简单的方法。然而,它有一些开销,因为它是一个系统调用,大约需要 ½μs 的时间。如果你要计时非常快的事件或需要非常高的精度,这可能会成为问题。

如果你需要比 250 纳秒更好的精度,可以使用 rdtsc 内置函数 直接获取硬件计数器。在我的 i7 上,延迟约为 10ns。


rdtsc没有输入,因此其延迟从发出到其输出寄存器准备好的时间可能会有所不同。只有在分支错误或其他前端停顿之后才有意义,并且很难测量。也许你指的是吞吐量? - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接