繁体   English   中英

openmp并行性能

[英]openmp parallel performance

我正在尝试使用openmp并行实现距离矩阵,在其中计算每个点与所有其他点之间的距离,所以到目前为止我想到的最佳算法的成本为O(n ^ 2),而我的算法的性能为就运行时间而言,在8处理器计算机上使用10线程的openmp并不比串行方法好,所以我想知道我在openmp方法上的实现是否存在任何错误,因为这是我第一次使用openmp,所以请我的方法中有任何错误或任何更好的“更快”方法,请告诉我。 以下是我的代码,其中“ dat”是包含数据点的向量。

map <int, map< int, double> > dist;   //construct the distance matrix 

int c=count(dat.at(0).begin(),dat.at(0).end(),delm)+1;

#pragma omp parallel for shared (c,dist)

for(int p=0;p<dat.size();p++)
{

    for(int j=p+1;j<dat.size();j++)
    {
        double ecl=0;

        string line1=dat.at(p);
        string line2=dat.at(j);

        for (int i=0;i<c;i++)
        {

            double num1=atof(line1.substr(0,line1.find_first_of(delm)).c_str());

            line1=line1.substr(line1.find_first_of(delm)+1).c_str();

            double num2=atof(line2.substr(0,line2.find_first_of(delm)).c_str());

            line2=line2.substr(line2.find_first_of(delm)+1).c_str();

            ecl += (num1-num2)*(num1-num2);
        }

        ecl=sqrt(ecl);

#pragma omp critical
        {
            dist[p][j]=ecl;
            dist[j][p]=ecl;
        }
    }
}

#pragma omp critical具有序列化循环的效果,因此摆脱该循环应该是您的首要目标。 这应该是朝正确方向迈出的一步:

ptrdiff_t const c = count(dat[0].begin(), dat[0].end(), delm) + 1;
vector<vector<double> > dist(dat.size(), vector<double>(dat.size()));

#pragma omp parallel for
for (size_t p = 0; p != dat.size(); ++p)
{
  for (size_t j = p + 1; j != dat.size(); ++j)
  {
    double ecl = 0.0;
    string line1 = dat[p];
    string line2 = dat[j];
    for (ptrdiff_t i = 0; i != c; ++i)
    {
      double const num1 = atof(line1.substr(0, line1.find_first_of(delm)).c_str());
      double const num2 = atof(line2.substr(0, line2.find_first_of(delm)).c_str());

      line1 = line1.substr(line1.find_first_of(delm) + 1);
      line2 = line2.substr(line2.find_first_of(delm) + 1);
      ecl += (num1 - num2) * (num1 - num2);
    }

    ecl = sqrt(ecl);
    dist[p][j] = ecl;
    dist[j][p] = ecl;
  }
}

还有其他一些明显的事情可以使整体速度更快,但是修复并行化是最重要的。

正如已经指出的那样,使用关键部分会减慢速度,因为一次只能在该部分中允许一个线程。 绝对不需要使用关键部分,因为每个线程都写入数据的互斥部分,读取未修改的数据显然不需要保护。

我对代码缓慢的怀疑归结为线程上工作分配不均。 默认情况下,我认为openmp在线程之间平均分配迭代。 例如,请考虑何时有8个线程和8个点:

-thread 0将获得7个距离计算

-thread 1将获得6个距离计算

...

-thread 7将获得0距离计算

即使有更多的迭代,仍然存在类似的不等式。 如果您需要说服自己,可以将线程设为私有计数器,以跟踪每个线程实际执行了多少次距离计算。

使用并行的工作共享结构,您可以指定各种工作分配策略。 就您而言,最好搭配

#pragma omp for schedule(guided)

当每个线程请求for循环的某些迭代时,它将获得剩余循环数(尚未分配给线程)除以线程数。 因此,最初您得到的是大块,后来您得到的是小块。 这是一种自动负载平衡的形式,请注意,在将迭代动态分配给线程时会有一些开销(可能很小)。

为避免第一个线程进行不公平的大量工作,应更改循环结构,以使较低的迭代次数较少,例如将内部for循环更改为

for (j=0; j<p-1; j++)

要考虑的另一件事是,当使用大量内核时,内存可能成为瓶颈。 您有8个处理器争夺2个或3个DRAM通道(同一通道上的独立存储棒仍在争夺带宽)。 片上CPU缓存最多可在所有处理器之间共享,因此您的缓存仍然不超过该程序的串行版本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM