C++ 将openmp c+中的一些嵌套+;

C++ 将openmp c+中的一些嵌套+;,c++,multithreading,c++11,parallel-processing,openmp,C++,Multithreading,C++11,Parallel Processing,Openmp,我的用于矩阵和内核之间卷积的串行代码如下所示: int index1, index2, a, b; for(int x=0;x<rows;++x){ for(int y=0;y<columns;++y){ for(int i=0;i<krows;++i){ for(int j=0;j<kcolumns;++j){ a=x+i-krows/2; b=y+j-k

我的用于矩阵和内核之间卷积的串行代码如下所示:

int index1, index2, a, b;
for(int x=0;x<rows;++x){
    for(int y=0;y<columns;++y){
        for(int i=0;i<krows;++i){
            for(int j=0;j<kcolumns;++j){
                a=x+i-krows/2;  
                b=y+j-kcolumns/2;                   
                if(a<0)
                    index1=rows+a;
                else if(a>rows-1)
                    index1=a-rows;
                else 
                    index1=a;

                if(b<0)
                    index2=columns+b;
                else if(b>columns-1)
                    index2=b-columns;
                else 
                    index2=b;

                output[x*columns+y]+=input[index1*columns+index2]*kernel[i*kcolumns+j];

            }
        }

    }
}
int index1,index2,a,b;

对于(int x=0;x我的建议是完全改变方法。如果您对边界使用循环处理(即您的问题是周期性的),则快速方法基于基于fft的频谱方法:

-傅里叶变换矩阵与核 -计算乘积 -对乘积进行傅里叶逆变换(你有卷积)


这(1)效率更高(除非内核的维度比矩阵的维度小得多),并且(2)可以使用支持多线程的fft库(如FFTW)让它来处理。

您不需要更改for循环。您可以让每个线程迭代一列中的所有行或一行中的所有列。此外,请记住,如果线程数高于物理核心数,性能不会有太大变化

OpenMP已经使用逻辑内核计数来处理它应该创建的线程数量,这在Intel i3和i7上可能是个问题,因为它们具有超线程,因此每个额外线程的性能增益不会很大

在简历中,您可以选择:

#pragma omp parallel for private (x,y,a,b,index1,index2)
for(int x=0;x<rows;++x){
    for(int y=0;y<columns;++y){
        // ...
    }
}
#专用的pragma omp并行(x,y,a,b,index1,index2)

对于(int x=0;x如果您使用的是OpenMP 3.0或更高版本,您可以利用循环工作共享结构的
collapse
子句:

collapse子句可用于指定循环的数量 与循环构造关联。折叠的参数 子句必须是常量正整数表达式。如果没有折叠 子句存在,是与该循环关联的唯一循环 构造是紧跟在loop指令之后的构造

这意味着您可以编写以下内容:

#pragma omp parallel for collapse(2)
for(int x=0;x<rows;++x){
    for(int y=0;y<columns;++y){
        /* Work here */
    }
}
用于折叠的pragma omp并行(2)
对于(int x=0;x您使用的是哪种编译器?最近的openmp IMMPlutations有循环折叠指令。另外,根据需要声明循环变量-这更干净,并且在并行区域内声明的变量自动是私有的。是的,我知道折叠指令,但不确定我的代码是否将在兼容的环境中进行测试e系统。对于其余部分,我知道你的意思,但这些不是我的问题。无论如何,谢谢。请提供额外信息,您使用的是哪种CPU?我使用1.70 Ghz的i5,但我在vmware虚拟机中编程(为了使用linux)。我将处理器的数量设置为4。@user73793,如果您的系统有两个具有hyper-treading的内核,那么您已经做得很好了。您不能期望线性速度超过物理内核的数量。另外,在虚拟机中开发也可以(我经常做同样的事情)我不会以这种方式进行性能测试。安装Visual Studio Express 2013(它是免费的-从免费啤酒的意义上讲,不是从自由的意义上讲)或者双引导到Linux。即使这样,您将测试两种不同的OpenMP实现,我从经验中知道这也会产生很大的不同。我认为这个解决方案需要大量的编程工作,是的,内核比输入矩阵小得多,所以我认为它不值得。@user73793仅仅就代码行而言,需要做很多工作,但如果您对fft一点也不熟悉,那么可能需要一些努力才能确定。如果您的内核总是9乘9,我同意这不值得,因为“直接”方法的复杂性已经是O(N)(N是矩阵的元素数)。如果将来您可能需要推广到不受紧凑支持的内核,如高斯内核,我认为这是值得投资的。我总是发现融合循环非常简单,以至于我没有真正看到使用
折叠
的意义。然而,我想关键是,如果您在没有OpenMP的情况下编译,那么您将获得原始未使用的代码。更一般地说,除了任务(减少最小值和最大值以及原子相等性,我可以自己做)之外,我只使用OpenMP 2.0缺少什么大功能?@Zboson我假设崩溃点并不是修改初始未融合的循环(主要是为了可读性).关于大功能,我假设您缺少3.X和SIMD中的任务,以及4.0中的卸载指令。我必须承认,尽管我还没有时间全面了解最新标准,所以我可能忘记了一些东西。。。
for(int x=0;x<rows;++x){
    #pragma omp parallel for private (y,a,b,index1,index2)
    for(int y=0;y<columns;++y){
        // ...
    }
}
#pragma omp parallel for collapse(2)
for(int x=0;x<rows;++x){
    for(int y=0;y<columns;++y){
        /* Work here */
    }
}
#pragma omp parallel for 
for(int z=0;z<rows*columns;z++){
    x=z/columns;
    y=z%columns;
    /* Work here */
}