【发布时间】:2019-12-11 09:36:33
【问题描述】:
我有一个简单的代码:
#include <iostream>
#include <chrono>
int main(int argc, char ** argv)
{
int I=0;
double time=0.0;
for(int i=0; i<10; ++i)
{
auto begin1=std::chrono::steady_clock::now();
#pragma omp parallel for simd
for(int j=0; j<1000000; ++j) I=j;
auto end1=std::chrono::steady_clock::now();
auto timei=std::chrono::duration_cast<std::chrono::milliseconds>(end1-begin1).count();
std::cout<<"time 1:"<<time<<std::endl;
time+=timei;
std::cout<<"time 2:"<<time<<std::endl;
}
return 0;
}
使用 g++ 5.3.1 并编译行:
cmake . -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS="-O2 -fopenmp"
但是输出是:
time 1:0
time 2:11
time 1:11
time 2:16
time 1:16
time 2:16
time 1:16
time 2:16
time 1:16
time 2:16
time 1:16
time 2:16
time 1:16
time 2:16
time 1:16
time 2:16
time 1:16
time 2:16
time 1:16
time 2:16
你看,我无法使用 std::chrono 正确测量执行时间!
为什么?到底是怎么回事?如何衡量执行时间?
这用于“-O2”和“-O1”编译器优化标志。使用“-O0”一切正常。为什么?
同样的情况是当我使用 Intel 编译器 icpc 19.0.1.144 和编译行时:
cmake .-DCMAKE_C_COMPILER=icc -DCMAKE_CXX_COMPILER=icpc -DCMAKE_CXX_FLAGS="-march=native -mtune=native -O2 -ipo16 -mcmodel=large"
如果使用“-O2”和“-O1”编译器标志,时间测量不正确,但如果用“-O0”替换它们,std::chrono可以正常工作。
说实话,我很震惊。
但问题是一样的:为什么使用 std::chrono 的执行时间测量在“-O1”和“-O2”中不能正常工作而在“O0”中工作?以及如何正确测量这段代码的执行时间?
请让我更新一下代码示例:
#include <iostream>
#include <chrono>
#include <ctime>
#include <omp.h>
int array[10000000]{0};
int main(int argc, char ** argv)
{
clock_t t;
double time=0.0;
for(int i=0; i<10; ++i)
{
auto begin1=std::chrono::steady_clock::now();
t=clock();
#pragma omp parallel for simd
for(int j=0; j<1000000; ++j) array[j]=j;
auto end1=std::chrono::steady_clock::now();
auto timei=std::chrono::duration_cast<std::chrono::milliseconds>(end1-begin1).count();
std::cout<<"time 1:"<<time<<std::endl;
time+=timei;
std::cout<<"time 2:"<<time<<std::endl;
t=clock()-t;
printf(\nt%i=%f\n", i, (double)t/CLOCKS_PER_SEC);
}
return 0;
}
现在 std:chrono 计时器正确更新。但有时 std::clock 和 std::chrono 的结果差异很大。假设,std::chrono 更准确,应该使用它的计时。
因此,正如@Hamza 在下面回答的那样,编译器只是丢弃了无用的代码块。但是 Intel 和 g++ 编译器都没有警告我任何事情。
因此,对于未来,不要编写什么都不做的 for 循环。编译器可能会简单地丢弃一段没有效果的代码。
在我的完整代码中,我尝试比较 2 个函数的相对性能,返回相同的结果:1 - 返回插入表格的值,2 - 从公式计算它(公式是表格点的近似值)。我的错误是我将结果写在临时堆栈变量的内部循环中,根本没有做任何事情。编译器把它扔掉了。我应该将内部循环中的值写入一个数组,或者以任何其他方式将它们累积起来,简单地说,做一些有用的事情,编译器不会丢弃的。
我是这么理解的。
【问题讨论】:
-
您尝试过更精细的分辨率吗?例如纳秒。此外,您的工作循环没有做任何有用的事情,编译器可能只是将其扔出窗口,因此您实际上什么也没有测量。所以你没有时间增加。而且我不熟悉openmp。访问
I时是否线程安全? -
我想,它应该被隐式地设为#pragma omp parallel for simd private(I) 并且工作正常。
-
我当然可以做出更精细的分辨率,但我不明白:如您所见,for(int j=0; j
标签: c++ g++ openmp compiler-optimization chrono