短函数c++的执行时间
Execution time of a short function c++
我想计算一个非常小的函数的执行时间,以比较递归函数与迭代函数的执行时间。
当然,如果分辨率不够,clock()
根本无法做到这一点。你能告诉我如何使用其他时间源,如 GetThreadTimes()
。在微软网站上看到了描述,没看懂原理。
此外,<chrono>
header 在 MS Visual 10 中不起作用。
代码:
int search (int a[], int size, int& num) {
if (size >0) {
if (a[size-1] == 17) {num = size-1; return num;}
else {return search (a, --size, num);}}
else {return num=-1;};
}
int searchit (int a[], int size, int& num) {
for (int i =0; i< size; i++) {
if (a[i] == 17) {num = i;}
else num = -1;
}
return num;}
int main () {
srand ((unsigned int) time(0));
int num = 0;
const int size = 40;
int a[size];
for (int i =0; i< size; i++) {
a[i] = rand()%100;
cout << a[i] << endl;}
cout << '\n';
search (a, size, num);
cout << num << endl;
cin.get();
cin.ignore();
}
只需搜索 100 次并取平均值:
time_t begin,end,total;
const int iterations = 100;
begin = clock();
for (int i = 0;i<iterations;i++)
search (a, size, num);
end = clock();
total = (end-begin)/static_cast<double>(CLOCKS_PER_SEC);
cout<<"Average time for "<<iterations<<" iterations: "<<total/iterations<<endl;
编译器将展开 for 循环 :)。反正For循环的消耗可以忽略不计
一个解决方案是按照@amchacon 的建议进行多次迭代。这样做的好处是简单明了。
它的缺点是可能导致不准确或不正确的结果,这既是由于编译器使用不同的启发式内联 and/or 指令流水线,也是由于指令和数据缓存在第一次迭代后已经预热.
因此,虽然您的函数可能确实由于错误的内存访问模式而性能很差(可能导致两次缓存未命中,每次都花费您 500 个周期),但当您 运行 函数一百次时,这可能根本不会显示,如果缓存行的总集合适合缓存。
有哪些选择?
a) 不适用于你的问题(因为你想测试递归算法),但我还是会针对 "general" 的情况说明它:使用 IACA。它专为对一小段代码进行微基准测试而设计,直至指令。
b) 使用精度更高的计时器或使用 根本不是计时器的计时器。为此,您可以在 Windows 下使用 QueryPerformanceCounter
和 QueryThreadCycleTime
(Vista 及更高版本)。周期可能比时间更可取,具体取决于您要测量的内容。
c) 查询 thread times。在我看来,这是最好的方法,因为您可以获得可靠、精确、准确的时间(与计时器非常不同,它可能包括上下文切换和在其他进程中花费的时间!),并且它适用于任何类型的代码,让您区分内核和用户时间,以防您的代码调用系统函数,并区分 CPU 和墙时间。
在函数 运行 之前和之后分别调用 GetThreadTimes
一次,然后分别减去 UserTime
和 KernelTime
值。
或者,如果您也对 wall time 感兴趣,则启动一个工作线程(对于 wall time,您将从 ExitTime
中减去 CreationTime
,并且您显然只会得到有效的 ExitTime
after 线程已经退出!)。如果您的代码还涉及阻塞 I/O 操作,计算挂钟时间可能会有用。
我想计算一个非常小的函数的执行时间,以比较递归函数与迭代函数的执行时间。
当然,如果分辨率不够,clock()
根本无法做到这一点。你能告诉我如何使用其他时间源,如 GetThreadTimes()
。在微软网站上看到了描述,没看懂原理。
此外,<chrono>
header 在 MS Visual 10 中不起作用。
代码:
int search (int a[], int size, int& num) {
if (size >0) {
if (a[size-1] == 17) {num = size-1; return num;}
else {return search (a, --size, num);}}
else {return num=-1;};
}
int searchit (int a[], int size, int& num) {
for (int i =0; i< size; i++) {
if (a[i] == 17) {num = i;}
else num = -1;
}
return num;}
int main () {
srand ((unsigned int) time(0));
int num = 0;
const int size = 40;
int a[size];
for (int i =0; i< size; i++) {
a[i] = rand()%100;
cout << a[i] << endl;}
cout << '\n';
search (a, size, num);
cout << num << endl;
cin.get();
cin.ignore();
}
只需搜索 100 次并取平均值:
time_t begin,end,total;
const int iterations = 100;
begin = clock();
for (int i = 0;i<iterations;i++)
search (a, size, num);
end = clock();
total = (end-begin)/static_cast<double>(CLOCKS_PER_SEC);
cout<<"Average time for "<<iterations<<" iterations: "<<total/iterations<<endl;
编译器将展开 for 循环 :)。反正For循环的消耗可以忽略不计
一个解决方案是按照@amchacon 的建议进行多次迭代。这样做的好处是简单明了。
它的缺点是可能导致不准确或不正确的结果,这既是由于编译器使用不同的启发式内联 and/or 指令流水线,也是由于指令和数据缓存在第一次迭代后已经预热.
因此,虽然您的函数可能确实由于错误的内存访问模式而性能很差(可能导致两次缓存未命中,每次都花费您 500 个周期),但当您 运行 函数一百次时,这可能根本不会显示,如果缓存行的总集合适合缓存。
有哪些选择?
a) 不适用于你的问题(因为你想测试递归算法),但我还是会针对 "general" 的情况说明它:使用 IACA。它专为对一小段代码进行微基准测试而设计,直至指令。
b) 使用精度更高的计时器或使用 根本不是计时器的计时器。为此,您可以在 Windows 下使用 QueryPerformanceCounter
和 QueryThreadCycleTime
(Vista 及更高版本)。周期可能比时间更可取,具体取决于您要测量的内容。
c) 查询 thread times。在我看来,这是最好的方法,因为您可以获得可靠、精确、准确的时间(与计时器非常不同,它可能包括上下文切换和在其他进程中花费的时间!),并且它适用于任何类型的代码,让您区分内核和用户时间,以防您的代码调用系统函数,并区分 CPU 和墙时间。
在函数 运行 之前和之后分别调用 GetThreadTimes
一次,然后分别减去 UserTime
和 KernelTime
值。
或者,如果您也对 wall time 感兴趣,则启动一个工作线程(对于 wall time,您将从 ExitTime
中减去 CreationTime
,并且您显然只会得到有效的 ExitTime
after 线程已经退出!)。如果您的代码还涉及阻塞 I/O 操作,计算挂钟时间可能会有用。