【问题标题】:Not getting the expected speedup using OpenMP on non-trivial calculations在非平凡计算中使用 OpenMP 未获得预期的加速
【发布时间】:2016-09-14 05:15:27
【问题描述】:

我正在尝试学习 OpenMP 以并行化我的部分代码,并且我正在尝试弄清楚为什么使用 2 个线程而不是 1 个线程时它不会更快。这是代码的最小工作示例:

#include <iostream>
#include <omp.h>

using namespace std;

class My_class
{
    public :

        // Constructor
        My_class(int nuIterations) 
            : prVar_(0),
              nuIters_(nuIterations)
        {} // Empty

        // Do something expensive involving the class' private vars
        void do_calculations()
        {
            for (int i=0;i<nuIters_;++i){
                prVar_=prVar_+i+2*i+3*i+4*i-5*i-4*i;
            }
        }

        // Retrieve result
        double getResult()
        {
            return prVar_;
        }

    private:

        double prVar_;
        int nuIters_;

};

int main()
{
    // Initialize one object for every thread
    My_class *test_object1, *test_object2;
    test_object1 = new My_class(1000000000);
    test_object2 = new My_class(500000000);

    // Set number of threads (use one line at a time)
    omp_set_num_threads(1); // One thread executes in 11.5 real seconds
    //omp_set_num_threads(2); // Two threads execute in 13.2 real seconds
    double start = omp_get_wtime(); // Start timer
#pragma omp parallel sections // Do calculations in parallel
    {
#pragma omp section
        {
            test_object1->do_calculations();
        }
#pragma omp section
        {
            test_object2->do_calculations();
        }
    }// End of parallel sections
    // Print results
    double end = omp_get_wtime();
    cout<<"Res 1 : "<<test_object1->getResult()<<endl;
    cout<<"Res 2 : "<<test_object2->getResult()<<endl;
    cout<<"Time  : "<<end-start<<endl;

    return 0;
}

使用 g++ myomp.cpp -O0 -std=c++11 -fopenmp 编译和运行它会为 1 个和 2 个线程提供以下执行时间:

  1. 1 个线程:11.5 秒
  2. 2 个线程:13.2 秒

有什么方法可以加快 2 个线程的速度吗? 我在 4 核 Intel i7-4600U 和 Ubuntu 上运行它。

编辑:更改了大部分帖子,使其遵循指导方针。

【问题讨论】:

  • 您必须以minimal reproducible example 的形式向我们提供更多信息以及您的硬件规格,否则答案只是猜测。猜测包括:写入共享缓存行、受内存限制、隐式同步、使用您不知道的共享资源或其组合。
  • 感谢您的评论,我将尝试制定一个合适的示例并编辑帖子!
  • 完成,希望现在有意义!
  • 如果有什么安慰的话,我的 iMac 1 线程需要 8.9 秒,2 线程需要 5.6 秒。我用-O3编译。
  • 我故意关闭优化以避免影响结果,我的实际代码是使用 O3 编译的,但很难重现.. :(

标签: c++ multithreading openmp


【解决方案1】:

这里有两种效果:

  1. 缓存行争用:您在动态内存中分配了两个非常小的对象。如果它们最终在同一个缓存行(通常为 64 字节)中,则想要更新 prVar_ 的线程都将竞争 1 级缓存,因为它们需要独占(写入)访问。您应该随机观察到这一点:有时它会明显更快/更慢,具体取决于内存位置。尝试打印指针地址并除以64。要解决这个问题,你需要pad / align the memory

  2. 负载严重不平衡。一项任务只是计算两倍的工作量,因此即使在理想化条件下,您也只能实现 1.5 倍的加速。

【讨论】:

  • 我在私有变量中添加了一个包含 1,000 个元素的双精度数组(尝试将两个对象分隔得比一个缓存行更远),它根本没有任何区别......
  • “没有区别”是什么意思?如果您已经获得了 1.5 倍的加速,那么您可能一开始就不会受到 1) 的影响。
  • 同意。我试图说似乎没有任何缓存行争用,但我措辞很糟糕。我还尝试使两个工作负载大小相同,并且加速确实是 2 倍。所以,至少在我的机器上,它似乎几乎完全是你的第二个效果。投我一票:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多