2017-03-17 65 views
2

我正在使用MPI实现分布式图像(灰度)卷积。我现有的模式是在根进程中将图像作为一维扁平数组读取,然后将它们分散到所有进程(行分解),然后在根进程中执行一个MPI_Gather,然后将该图像再次写入为一维扁平化阵列。显然,这并没有给出预期的结果,因为在图像卷积时,情况在边界处变得棘手。MPI中的鬼细胞交换模式

因此,为了提高在上述模式,我想要实现所谓的ghost cell exchange图案,其中的过程中ghost rows.伪代码交换他们行:

if (rank == 0) { 
    src = null 
    dest = rank + 1 
} 

if (rank == size - 1) { 
    src = rank - 1 
    dest = null 
} else { 
    src = rank - 1 
    dest = rank + 1 
} 

MPI_SendRecv(&sendbuf[offset], slen, dest.. 
      &recvbuf[offset], rlen, src); 

如何分配内存“鬼行“在每个过程?我应该预分配内存然后分散吗?我不想去“自定义数据类型”解决方案,因为这对我正在考虑的问题的范围来说太过于夸张。

回答

2

理想情况下,重影单元应与您的单元格一样是同一个内存块的一部分。这样,你可以保持寻址方案简单。在该方案中,图像通过使用MPI_ScatterMPI_Gather的多个完整行来分布。在非边界排名中,您为两个额外的幻影行分配足够的内存:

height = total_hight/ranks; 
std::vector<float> data(width * (height + 2)); 
float* image = &data[width]; 
float* ghost_north = &data[0] 
float* ghost_south = &data[width * (height + 1)] 
float* inner_north = image; 
float* inner_south = &image[width * (height - 1)] 
MPI_Scatter(root_image, width * height, MPI_FLOAT, 
      image, width * height, MPI_FLOAT, ...); 
... 
iterations { 
    MPI_SendRecv(inner_north, width, MPI_FLOAT, north, tag, 
       ghost_north, width, MPI_FLOAT, north, tag, ...) 
    MPI_SendRecv(inner_south, width, MPI_FLOAT, south, tag, 
       ghost_south, width, MPI_FLOAT, south, tag, ...) 
    ... compute ... 
} 
MPI_Gather(image, width * height, MPI_FLOAT, 
      root_image, width * height, MPI_FLOAT, ...); 

此伪码不考虑特殊的边框情况。

简单的一维分裂的问题是通信成本和额外的晕数据是非最优的。特别是对于较小的图像和更多的参与队伍。

这是关于使用MPI的数据分解和晕环通信方法的excellent example by Rolf Rabenseifner。他还解释了如何改进沟通方法。对于二维分解,您需要派生MPI数据类型以用于初始通信和垂直边界。

+0

感谢您提供完整,明确的答案。你提到了一些关于通信成本的内容。现在,如果我要在增加图像尺寸时测试这个模型,那么我的表现应该会降低,对吧? –

+0

基本上,一维分解的通信成本将比二维分解*差。通信开销取决于图像大小(较大=较好),等级数量(较少=较好)和每次迭代的计算(更多=较好)的平衡。 – Zulan

+0

我同意那部分,第1d沟通会涉及很多交流。感谢你的帮助。我会尽快接受答案 –