如何测量每秒的增量数

时间:2019-07-29 13:57:46

标签: c++ performance

我想测量PC可以递增计数器N倍的速度(例如N = 10^9)。

我尝试了以下代码:

using namespace std
auto start = chrono::steady_clock::now();
for (int i = 0; i < N; ++i)
{
}
auto end = chrono::steady_clock::now();

但是,编译器足够聪明,只需设置i = N即可,无论N的值如何,我都能得到start==end

如何更改代码以测量增量速度? (在循环中添加昂贵的操作会控制运行时,并且无法确保测量结果正确。)

我使用Windows 10和Visual Studio 15.9.7。


有点动机:我的代码在N = 10 ^ 9的情况下大约需要2秒。我想知道是否还有剩余的“肉”可用于进一步优化(例如,它可能会下降到1秒?还是循环本身需要更多时间?)

3 个答案:

答案 0 :(得分:4)

这个问题在C或C ++中实际上没有任何意义。编译器旨在生成满足您的源代码定义的约束的最快代码。在您的问题中,您没有定义编译器必须执行循环的约束。由于循环无效,因此优化程序将其删除。

Gabriel Staple's answer可能是您最明智地回答问题的方法,但它也不是正确的,因为它定义了太多限制,限制了编译器实现最佳代码的自由。易失性经常迫使编译器在每次修改变量时将结果写回内存。

例如此代码:

void foo(int N) {
    for (volatile int i = 0; i < N; ++i)
    {
    }
}

成为此程序集(在我尝试过的x64编译器上):

        mov     DWORD PTR [rsp-4], 0
        mov     eax, DWORD PTR [rsp-4]
        cmp     edi, eax
        jle     .L1
.L3:
        mov     eax, DWORD PTR [rsp-4] # Read i from mem
        add     eax, 1                 # i++
        mov     DWORD PTR [rsp-4], eax # Write i to mem
        mov     eax, DWORD PTR [rsp-4] # Read it back again before
                                       # evaluating the loop condition.
        cmp     eax, edi               # Is i < N?
        jl      .L3                    # Jump back to L3 if not.
.L1:

听起来您的真实问题更像是多快:

L1:    add     eax, 1
       jmp     L1

即使答案很复杂,也需要了解CPU管道的内部情况。

我建议与Godbolt一起玩,以了解有关编译器正在做什么的更多信息。例如https://godbolt.org/z/59XUSu

答案 1 :(得分:1)

您可以直接测量“空循环”的速度,但是要说服C ++编译器发出它并不容易。可以用asm volatile("")欺骗GCC和Clang,但是MSVC内联汇编一直不同,并且对于64位程序完全禁用。

可以use MASM来回避该限制:

.MODEL FLAT
.CODE

_testfun PROC
    sub ecx, 1
    jnz _testfun
    ret
_testfun ENDP

END

使用extern "C" void testfun(unsigned N);将其导入您的代码中。

答案 2 :(得分:0)

在您的for循环中尝试volatile int i = 0volatile关键字告诉编译器此变量可能由于外部事件或线程而随时更改,因此,对于将来的变量可能无法做出相同的假设。