Chrono C++ 计时不正确
Chrono C++ timings not correct
我只是比较几个斐波那契函数的速度,一个几乎立即给出输出并读取它在 500 纳秒内完成,而另一个,取决于深度,可能会坐在那里加载很多秒,然而当它完成时,它会显示只用了 100 纳秒......在我坐在那里等了 20 秒之后。
这没什么大不了的,因为我可以证明另一个只是人类原始感知速度较慢,但为什么 chrono 不起作用?与递归有关?
PS 我知道 fibonacci2() 在奇数深度上没有给出正确的输出,我只是在测试一些东西,输出实际上就在那里,所以编译器没有优化它离开什么的。继续,只需复制此代码,您将立即看到 fibonacci2() 输出,但您必须等待 5 秒才能看到 fibonacci()。谢谢。
#include <iostream>
#include <chrono>
int fibonacci2(int depth) {
static int a = 0;
static int b = 1;
if (b > a) {
a += b; //std::cout << a << '\n';
}
else {
b += a; //std::cout << b << '\n';
}
if (depth > 1) {
fibonacci2(depth - 1);
}
return a;
}
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
int main() {
int f = 0;
auto start2 = std::chrono::steady_clock::now();
f = fibonacci2(44);
auto stop2 = std::chrono::steady_clock::now();
std::cout << f << '\n';
auto duration2 = std::chrono::duration_cast<std::chrono::nanoseconds>(stop2 - start2);
std::cout << "faster function time: " << duration2.count() << '\n';
auto start = std::chrono::steady_clock::now();
f = fibonacci(44);
auto stop = std::chrono::steady_clock::now();
std::cout << f << '\n';
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start);
std::cout << "way slower function with incorrect time: " << duration.count() << '\n';
}
我不知道您使用的是什么编译器以及使用哪些编译器选项,但我在 godbolt 中使用 /O2
测试了 x64 msvc v19.28。这里编译的指令被重新排序,这样它在调用 fibonacci(int)
函数之前查询 perf_counter 两次,在代码中看起来像
auto start = ...;
auto stop = ...;
f = fibonacci(44);
禁止这种重新排序的解决方案可能是在 fibonacci
函数调用前后使用 atomic_thread_fence。
正如 Mestkon 回答的那样,编译器可以重新排序您的代码。
如何防止编译器重新排序的示例 Memory Ordering - Compile Time Memory Barrier
如果您提供有关您使用的编译器的信息,这将对将来有所帮助。
例如带有 -O2 的 gcc 7.5 不会在此给定场景中重新排序定时器指令。
我只是比较几个斐波那契函数的速度,一个几乎立即给出输出并读取它在 500 纳秒内完成,而另一个,取决于深度,可能会坐在那里加载很多秒,然而当它完成时,它会显示只用了 100 纳秒......在我坐在那里等了 20 秒之后。
这没什么大不了的,因为我可以证明另一个只是人类原始感知速度较慢,但为什么 chrono 不起作用?与递归有关?
PS 我知道 fibonacci2() 在奇数深度上没有给出正确的输出,我只是在测试一些东西,输出实际上就在那里,所以编译器没有优化它离开什么的。继续,只需复制此代码,您将立即看到 fibonacci2() 输出,但您必须等待 5 秒才能看到 fibonacci()。谢谢。
#include <iostream>
#include <chrono>
int fibonacci2(int depth) {
static int a = 0;
static int b = 1;
if (b > a) {
a += b; //std::cout << a << '\n';
}
else {
b += a; //std::cout << b << '\n';
}
if (depth > 1) {
fibonacci2(depth - 1);
}
return a;
}
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
int main() {
int f = 0;
auto start2 = std::chrono::steady_clock::now();
f = fibonacci2(44);
auto stop2 = std::chrono::steady_clock::now();
std::cout << f << '\n';
auto duration2 = std::chrono::duration_cast<std::chrono::nanoseconds>(stop2 - start2);
std::cout << "faster function time: " << duration2.count() << '\n';
auto start = std::chrono::steady_clock::now();
f = fibonacci(44);
auto stop = std::chrono::steady_clock::now();
std::cout << f << '\n';
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start);
std::cout << "way slower function with incorrect time: " << duration.count() << '\n';
}
我不知道您使用的是什么编译器以及使用哪些编译器选项,但我在 godbolt 中使用 /O2
测试了 x64 msvc v19.28。这里编译的指令被重新排序,这样它在调用 fibonacci(int)
函数之前查询 perf_counter 两次,在代码中看起来像
auto start = ...;
auto stop = ...;
f = fibonacci(44);
禁止这种重新排序的解决方案可能是在 fibonacci
函数调用前后使用 atomic_thread_fence。
正如 Mestkon 回答的那样,编译器可以重新排序您的代码。 如何防止编译器重新排序的示例 Memory Ordering - Compile Time Memory Barrier
如果您提供有关您使用的编译器的信息,这将对将来有所帮助。
例如带有 -O2 的 gcc 7.5 不会在此给定场景中重新排序定时器指令。