Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parallel processing 前缀和占用太长的OpenMP_Parallel Processing_Openmp - Fatal编程技术网

Parallel processing 前缀和占用太长的OpenMP

Parallel processing 前缀和占用太长的OpenMP,parallel-processing,openmp,Parallel Processing,Openmp,我正在OpenMP中实现前缀和问题,并且似乎没有得到任何加速。实际上,并行实现比顺序实现花费的时间更长 以下是我的前缀和代码: for (k = 1; k < n; k = kk) { kk = k << 1; #pragma omp parallel for for (i = kk - 1; i < n; i += kk) { x[i] = x[i-k] + x[i]; } } for (k = k >>

我正在OpenMP中实现前缀和问题,并且似乎没有得到任何加速。实际上,并行实现比顺序实现花费的时间更长

以下是我的前缀和代码:

for (k = 1; k < n; k = kk) {
    kk = k << 1;

    #pragma omp parallel for 
    for (i = kk - 1; i < n; i += kk) {
        x[i] = x[i-k] + x[i];
    }
 }

for (k = k >> 1; k > 1; k = kk) {
    kk = k >> 1;

    #pragma omp parallel for
    for (i = k - 1; i < n - kk; i += k) {
        x[i + kk] = x[i] + x[i + kk];
    }
}
对于并行实现(在4个内核上重新运行5次):

有人能解释一下问题出在哪里吗?实现提供了正确的输出,但为什么需要这么长时间


谢谢。

由于每个元素都依赖于前一个元素,因此必须将算法分为两步。每个线程在第一步中只计算整数子集上的前缀(这样每个线程就不会依赖于任何其他线程),并将添加其他相关线程的结果

例如: x[3]依赖于x[0]、x[1]、x[2]和x[3]。您可以将x[4]的计算分为两个子集。让一个线程通过将1和2相加来计算x[1],让第二个线程将3和4相加到x[4]。在此步骤之后,线程必须同步(如果您开始第二个并行循环,openMP会为您同步),第二个线程将通过将x[2]添加到x[4]来计算最终答案。如果您有很多整数和线程,那么将计算分解为三个步骤甚至可能是有益的

这基本上是一种并行归约,可用于大多数迭代算法的并行化。在理论上,给出了平行归约的精确定义,并给出了一些图像


Ps:仔细检查一下你的算法,似乎你实现的前缀和问题相当复杂。它仍然有很多依赖关系(我确实仔细研究过),但我认为我上面的陈述仍然有效,您可以进行并行简化。但我想知道:您是否实现了一种实际用于创建硬件电路的算法?

前缀和可以对MIMD(例如OpenMP)和SIMD(例如SSE/AVX)进行并行处理

使用OpenMP进行前缀求和有点麻烦,但也不算太糟糕。我已经在这里详细讨论了这个问题

编辑:您正在原地(原地)进行前缀和。上面的链接不在适当的位置(异地)我修改了代码(请参见下文),以便在您进行测试时对其进行前缀求和。您可能需要两个以上的物理内核才能看到任何benfit

基本上你可以分两次完成。在第一个过程中,你做部分和,然后在第二个过程中,你用一个常数为每个部分和修正部分和。第二个过程将由一个好的编译器进行矢量化(例如,使用GCC,但不使用MSVC)。在第一个过程中也可以使用SIMD,但我使用的编译器都不会对其进行矢量化,因此您必须自己使用内部函数

该算法以O(n)的形式运行,因此它很快成为内存限制,而不是计算限制。这意味着对于仅适合一级缓存的阵列,OpenMP开销太大。在这种情况下,最好只使用SIMD(它没有开销)。对于较大的阵列,您可以同时使用SIMD和MIMD,但在某些情况下,该算法会受到内存限制,并且不会比非并行算法快多少

#include <stdio.h>
#include <omp.h>

void prefixsum_inplace(float *x, int N) {
    float *suma;
    #pragma omp parallel
    {
        const int ithread = omp_get_thread_num();
        const int nthreads = omp_get_num_threads();
        #pragma omp single
        {
            suma = new float[nthreads+1];
            suma[0] = 0;
        }
        float sum = 0;
        #pragma omp for schedule(static)
        for (int i=0; i<N; i++) {
            sum += x[i];
            x[i] = sum;
        }
        suma[ithread+1] = sum;
        #pragma omp barrier
        float offset = 0;
        for(int i=0; i<(ithread+1); i++) {
            offset += suma[i];
        }
        #pragma omp for schedule(static)
        for (int i=0; i<N; i++) {
            x[i] += offset;
        }
    }
    delete[] suma;
}

int main() {
    const int n = 20;
    float x[n];
    for(int i=0; i<n; i++) x[i] = 1.0*i;
    prefixsum_inplace(x, n);
    for(int i=0; i<n; i++) printf("%f %f\n", x[i], 0.5*i*(i+1));
}
#包括
#包括
空前缀sum_在位(浮点*x,整数N){
浮动*苏马;
#pragma-omp并行
{
const int ithread=omp_get_thread_num();
const int nthreads=omp_get_num_threads();
#布拉格omp单曲
{
suma=新浮点[n次读取+1];
suma[0]=0;
}
浮点数和=0;
#计划的pragma omp(静态)
对于(int i=0;i
0.025851
0.005493
0.006327
0.007092
0.030720
#include <stdio.h>
#include <omp.h>

void prefixsum_inplace(float *x, int N) {
    float *suma;
    #pragma omp parallel
    {
        const int ithread = omp_get_thread_num();
        const int nthreads = omp_get_num_threads();
        #pragma omp single
        {
            suma = new float[nthreads+1];
            suma[0] = 0;
        }
        float sum = 0;
        #pragma omp for schedule(static)
        for (int i=0; i<N; i++) {
            sum += x[i];
            x[i] = sum;
        }
        suma[ithread+1] = sum;
        #pragma omp barrier
        float offset = 0;
        for(int i=0; i<(ithread+1); i++) {
            offset += suma[i];
        }
        #pragma omp for schedule(static)
        for (int i=0; i<N; i++) {
            x[i] += offset;
        }
    }
    delete[] suma;
}

int main() {
    const int n = 20;
    float x[n];
    for(int i=0; i<n; i++) x[i] = 1.0*i;
    prefixsum_inplace(x, n);
    for(int i=0; i<n; i++) printf("%f %f\n", x[i], 0.5*i*(i+1));
}