我正在运行一段代码来测试 log() 函数是否可以缩放。我在4核机器上运行它,结果显示它没有扩展。我的代码如下:
#include<iostream>
#include<cmath>
#include<omp.h>
#include<chrono>
using namespace std;
typedef std::chrono::milliseconds ms;
int main(){
#pragma omp parallel for schedule(static)
for(int i=0;i<4;i++){
auto start = std::chrono::high_resolution_clock::now();
double tmp=1.0;
for(double j=0.0;j<10000000;j++){
tmp=log(j);
}
auto end = std::chrono::high_resolution_clock::now();
#pragma omp critical
{
cout<<"tmp="<<tmp<<endl;
cout<<"Thread "<<omp_get_thread_num()<<" calculated tmp, time used: "<<std::chrono::duration_cast<ms>(end - start).count() << "ms" << endl;
}
}
return 0;
}
如果我使用4个线程,结果是:
Thread 1 calculated tmp, time used: 21ms
Thread 0 calculated tmp, time used: 21ms
Thread 2 calculated tmp, time used: 21ms
Thread 3 calculated tmp, time used: 21ms
如果只使用1个线程,结果是:
Thread 0 calculated tmp, time used: 20ms
Thread 0 calculated tmp, time used: 16ms
Thread 0 calculated tmp, time used: 16ms
Thread 0 calculated tmp, time used: 15ms
因此,并行运行时,每个线程比顺序运行花费的时间更长。有谁知道为什么它不能扩展? std::log 实际上是如何工作的(线程可能必须共享某些内容)?有没有办法让 log() 函数可以扩展?谢谢!
编辑1: 我将迭代次数增加到 10e10 次,但结果表明并行版本甚至更慢,所以也许这里的主导因素不是线程创建时间。 4 个线程:
Thread 0 calculated tmp, time used: 17890ms
Thread 2 calculated tmp, time used: 17890ms
Thread 1 calculated tmp, time used: 17892ms
Thread 3 calculated tmp, time used: 17892ms
1 个线程:
Thread 0 calculated tmp, time used: 15664ms
Thread 0 calculated tmp, time used: 15659ms
Thread 0 calculated tmp, time used: 15660ms
Thread 0 calculated tmp, time used: 15647ms
EDIT2:我让 tmp 变量最后打印出来,这样 log() 就无法优化出来。但结果还是和以前一样。还有其他想法吗?
EDIT3:所以总执行时间的加速比是3.5,即使迭代次数增加,它也不会变得更高。我不确定这是否是一个合理的加速比,因为我预计像这样的简单程序会有 3.7 或 3.8 的加速比。
最佳答案
简而言之
你说得完全正确。但要充分衡量多核性能的改进,您不应仅仅依赖于对各个线程进行计时:您还应该衡量整体执行的时间。
多核架构似乎可以实现更高的吞吐量,但代价是当其中几个核心处于事件状态时,每个核心的数量会略有下降。这里another benchmark (使用 std::thread 而不是 OMP)具有类似的观察结果。
因此,每个单独的日志计算都无法扩展,但整体系统表现得很好。
其他详细信息
如果您要运行一些总体端到端测量:
int main()
{
auto common_start = std::chrono::high_resolution_clock::now();
...
auto common_end = std::chrono::high_resolution_clock::now();
cout << "Overall calculated time : " << std::chrono::duration_cast<ms>(common_end - common_start).count() << "ms" << endl;
return 0;
}
您肯定会同时观察到更好的整体性能。
这是我自己的 4 个线程的计时:
Thread 2 calculated tmp, time used: 269ms
Thread 3 calculated tmp, time used: 274ms
Thread 0 calculated tmp, time used: 281ms
Thread 1 calculated tmp, time used: 289ms
Overall calculated time : 296ms
还有一个:
Thread 0 calculated tmp, time used: 218ms
Thread 0 calculated tmp, time used: 218ms
Thread 0 calculated tmp, time used: 229ms
Thread 0 calculated tmp, time used: 224ms
Overall calculated time : 903ms
正如您所观察到的,使用一个线程,计算速度提高了 22%。但总的来说,完成相同数量的计算需要多线程所需时间的 3 倍。
所以这一切都与吞吐量有关:单线程运行速度仅为 44 K 迭代/毫秒,而多线程运行速度为 135 K 迭代/毫秒。
关于C++ std::log 函数无法缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38279689/