如何使用 OpenMP 减少嵌套循环?

How can I do Reduction in Nested Loops using OpenMP?

本文关键字:嵌套循环 何使用 OpenMP      更新时间:2023-10-16

我正在尝试并行化嵌套循环:

#pragma omp parallel reduction(+: Q)
for (uint32_t i = 0; i < num_vertices; i++)
{
for (uint32_t j = 0; j < num_vertices; j++)
{
if (coms[i] == coms[j])
{
edge_t edge(i,j);
int val = 0;
if (edgeSet.find(edge) != edgeSet.end()) val = 1;
Q += val - (double(degrees[i] * degrees[j])/double(2*num_edges));
}
}
if (i % 1000000 == 0) std::cout << "calculated for " << i << " nodes" << std::endl;
}

该程序运行得很慢。我可以做些什么来提高性能吗?我是否正确使用reduction? 据我了解,在内部循环中#pragma omp parallel reduction(+: Q)会对性能产生负面影响,因为它会为外部循环的每次迭代创建和破坏线程。

我已经在 64 个Intel(R) Xeon(R) CPU E5-4650 2.7 GHz个内核上测试了该程序,用于具有大约 4M 顶点(num_vertices = 4000000的数据集。该程序运行了一个多小时,但仍未完成。问题是,对于其他数据集,num_vertices可能高达110M。因此,我想知道是否有任何技巧可以减少多线程开销并提高并行化的性能。

你只是忘记了在线程之间分配工作。

您可以使用parallel指令创建一个并行区域,这意味着从此时开始创建许多线程(默认:操作系统看到的核心数(。每个线程在下面的代码中执行所有迭代(即num_vertices * num_vertices 次迭代(,这解释了为什么你没有得到任何加速。

#pragma omp parallel reduction(+: Q)
for (uint32_t i = 0; i < num_vertices; i++)
{
for (uint32_t j = 0; j < num_vertices; j++)
{
}
}

发生这种情况是因为您没有告诉 OpenMP 共享工作(即在可用线程之间拆分迭代集(。例如,在循环i之前请求与#pragma omp for共享for循环的工作共享,这将平均分配线程上的迭代i。如果没有schedule子句,线程 0 处理迭代 [0,..,num_vertices/T-1],线程 1 处理迭代 [num_vertices/T, .., 2*num_vertices/T-1],...,其中 T 是并行区域中的线程数。

由于迭代域是一个正方形,因此可以增加要分发的迭代次数(如果num_vertices较小(,#pragma omp for collapse(2)ij分发迭代。

最后,由于您的#pragma omp for会立即跟随您的#pragma omp parallel,人们通常使用速记parallel for来组合这两个指令。

然后,您的程序将读取:

#pragma omp parallel for reduction(+: Q)
for (uint32_t i = 0; i < num_vertices; i++)
{
for (uint32_t j = 0; j < num_vertices; j++)
{
}
}