关于SO,有很多关于性能分析的问题,但我似乎没有找到全貌。涉及的问题很多,大多数问答一次都忽略了几个问题,或者没有证明他们的建议是合理的。
我在想什么。如果我有两个功能做同样的事情,并且我对速度上的差异感到好奇,那么在没有外部工具、使用计时器的情况下测试它是否有意义,或者在测试中编译会不会对结果产生很大影响?
我问这个是因为如果它是明智的,作为一个 C++ 程序员,我想知道它应该如何最好地完成,因为它们比使用外部工具简单得多。如果有道理,让我们继续处理所有可能的陷阱:
考虑这个例子。以下代码显示了执行同一操作的两种方法:
#include <algorithm>
#include <ctime>
#include <iostream>
typedef unsigned char byte;
inline
void
swapBytes( void* in, size_t n )
{
for( size_t lo=0, hi=n-1; hi>lo; ++lo, --hi )
in[lo] ^= in[hi]
, in[hi] ^= in[lo]
, in[lo] ^= in[hi] ;
}
int
main()
{
byte arr[9] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
const int iterations = 100000000;
clock_t begin = clock();
for( int i=iterations; i!=0; --i )
swapBytes( arr, 8 );
clock_t middle = clock();
for( int i=iterations; i!=0; --i )
std::reverse( arr, arr+8 );
clock_t end = clock();
double secSwap = (double) ( middle-begin ) / CLOCKS_PER_SEC;
double secReve = (double) ( end-middle ) / CLOCKS_PER_SEC;
std::cout << "swapBytes, for: " << iterations << " times takes: " << middle-begin
<< " clock ticks, which is: " << secSwap << "sec." << std::endl;
std::cout << "std::reverse, for: " << iterations << " times takes: " << end-middle
<< " clock ticks, which is: " << secReve << "sec." << std::endl;
std::cin.get();
return 0;
}
// Output:
// Release:
// swapBytes, for: 100000000 times takes: 3000 clock ticks, which is: 3sec.
// std::reverse, for: 100000000 times takes: 1437 clock ticks, which is: 1.437sec.
// Debug:
// swapBytes, for: 10000000 times takes: 1781 clock ticks, which is: 1.781sec.
// std::reverse, for: 10000000 times takes: 12781 clock ticks, which is: 12.781sec.
问题:
- 要使用哪些计时器以及如何获取相关代码实际消耗的 CPU 时间?
- 编译器优化的效果如何(因为这些函数只是来回交换字节,最有效的做法显然是什么都不做)?
- 考虑到此处显示的结果,您认为它们准确吗(我可以向您保证,多次运行给出的结果非常相似)?如果是,考虑到自定义函数的简单性,您能否解释一下 std::reverse 如何变得如此之快。我没有用于此测试的 vc++ 版本的源代码,但是 here is the implementation来自 GNU。它归结为函数 iter_swap ,这对我来说是完全无法理解的。这是否也有望比该自定义函数的运行速度快两倍?如果是,为什么?
思考:
似乎正在提议两个高精度计时器:clock()和 QueryPerformanceCounter (在 window 上)。显然我们想测量我们代码的 cpu 时间而不是实时,但据我了解,这些函数不提供该功能,因此系统上的其他进程会干扰测量。 This page在 gnu c 库上似乎与此相矛盾,但是当我在 vc++ 中放置一个断点时,调试的进程即使被挂起也会得到很多时钟滴答声(我没有在 gnu 下测试过)。我是否缺少替代计数器,或者我们至少需要特殊的库或类吗?如果不是,时钟在此示例中是否足够好,或者是否有理由使用 QueryPerformanceCounter?
如果没有调试、反汇编和分析工具,我们能确定什么?真的有什么事情发生吗?函数调用是否被内联?在调试器中检查时,字节确实被交换了,但我宁愿从理论上知道为什么,而不是通过测试。
感谢任何指示。
更新
感谢hint来自 tojas swapBytes 函数现在运行速度与 std::reverse 一样快。我没有意识到字节的临时拷贝必须只是一个寄存器,因此非常快。优雅会让你盲目。
inline
void
swapBytes( byte* in, size_t n )
{
byte t;
for( int i=0; i<7-i; ++i )
{
t = in[i];
in[i] = in[7-i];
in[7-i] = t;
}
}
感谢tip来自 ChrisW我发现在 Windows 上,您可以通过 Windows Management Instrumentation 获得(阅读:您的)进程消耗的实际 CPU 时间。 .这看起来肯定比高精度计数器更有趣。
最佳答案
Obviously we would like to measure the cpu time of our code and not the real time, but as far as I understand, these functions don't give that functionality, so other processes on the system would interfere with measurements.
我做了两件事,以确保挂钟时间和 CPU 时间大致相同:
测试相当长的时间,即几秒钟(例如,通过测试包含数千次迭代的循环)
测试机器何时或多或少相对空闲,除了我正在测试的内容。
或者,如果您只想/更准确地测量每个线程的 CPU 时间,可以将其用作性能计数器(参见例如 perfmon.exe
)。
What can we know for certain without debugging, dissassembling and profiling tools?
几乎没有(除了 I/O 往往相对较慢)。
关于c++ - 在没有分析器的情况下在 C++ 中测试代码速度的最佳方法,或者尝试没有意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3128095/