如何测量每秒增量的数量

How to measure the number of increments per second

本文关键字:何测量 测量      更新时间:2023-10-16

我想测量我的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,而我得到的start==end不管n。

的值如何

如何更改代码来测量增量速度?(在循环中添加昂贵的操作将主导运行时,并且不允许测量正确(。

我使用Windows 10和Visual Studio 15.9.7。


有些动机:我的代码大约需要2秒钟的n = 10^9。我想知道是否还有任何"肉"进一步优化它(例如,它可能会降低到1秒?还是循环本身需要更多?(

这个问题在C或C 中确实没有意义。编译器旨在生成满足源代码定义的约束的最快代码。在您的问题中,您没有定义编译器必须完全循环的约束。因为循环没有效果,所以优化器将删除它。

Gabriel Staple的答案可能是您可以找到问题的最接近的问题,但这也不是正确的,因为它定义了太多的约束,以限制编译器实现最佳代码的自由。每次修改变量时,挥发性通常会迫使编译器将结果写回内存。

例如,此代码:

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

您可以直接测量"空环"的速度,但是说服C 编译器发射它并不容易。GCC和Clang可以用asm volatile("")欺骗,但是MSVC内联装配始终是不同的,并且完全被64位程序禁用。

可以使用MASM侧步,限制:

.MODEL FLAT
.CODE
_testfun PROC
    sub ecx, 1
    jnz _testfun
    ret
_testfun ENDP
END

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

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