[英]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.