我想写使用MPI矩阵向量乘法程序。 我试图发送矩阵独立的进程的列和本地计算的结果。 最后我做一个MPI_Reduce
使用MPI_SUM
操作。
发送矩阵的行很容易在行主顺序C存储阵列,但列不是(如果你没有一个给他们一个)。 我读到这里的问题是:
MPI_Scatter -发送2D阵列的列
乔纳森·德西使用新的MPI数据类型,并建议在这里就是我的适应他的代码,以我自己的需要做:
double matrix[10][10];
double mytype[10][10];
int part_size; // stores how many cols a process needs to work on
MPI_Datatype col, coltype;
// ...
MPI_Type_vector(N, 1, N, MPI_DOUBLE, &col);
MPI_Type_commit(&col);
MPI_Type_create_resized(col, 0, 1*sizeof(double), &coltype);
MPI_Type_commit(&coltype);
// ...
MPI_Scatter(matrix, part_size, coltype,
mypart, part_size, coltype,
0, MPI_COMM_WORLD);
// calculations...
MPI_Reduce(local_result, global_result,
N, MPI_DOUBLE,
MPI_SUM,
0, MPI_COMM_WORLD);
这完美的作品,但我不能说我真正了解它是如何工作的。
- 如何
MPI_Type_vector
存储在存储器? - 如何
MPI_Type_create_resized()
的作品,以及它具体做什么?
请记住,我在MPI共初学者。 提前致谢。
有这个问题在相当长的说明我的回答到这个问题 :事实上,许多人都有这种问题,这证明了它的并不明显,一些习惯的思路走。
要知道最重要的事情是什么内存布局的MPI数据类型描述。 调用序列MPI_Type_vector
是:
int MPI_Type_vector(int count,
int blocklength,
int stride,
MPI_Datatype old_type,
MPI_Datatype *newtype_p)
它创建了一个新的类型,它描述的内存布局,每一个stride
项目,有块blocklength
的物品拉出,共有count
这些块。 这里的项目是什么单位的old_type
了。 因此,举例来说,如果你叫(这里命名的参数,你不能真正做到在C,但:)
MPI_Type_vector(count=3, blocklength=2, stride=5, old_type=MPI_INT, &newtype);
然后newtype
会在这样的内存描述的布局:
|<----->| block length
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| X | X | | | | X | X | | | | X | X | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|<---- stride ----->|
count = 3
其中每个正方形的是存储器中的一个整数大小的块,大概4个字节。 需要注意的是步幅是从一个块的开始块之间的未来,而不是距离的起点在整数的距离。
好了,你的情况,你叫
MPI_Type_vector(N, 1, N, MPI_DOUBLE, &col);
这将需要count = N
块,每个块大小的blocklength=1
MPI_DOUBLE
S,与每个块的开始之间的空间stride=N
MPI_DOUBLE
秒。 换句话说,它会采取每第N个双,共N次; 完美的出双打的(连续存储的)的N×N阵列的提取一列。 一个方便的检查是查看被多少数据跨距上( count*stride = N*N
其中是矩阵,支票的全尺寸)实际上包括多少数据( count*blocksize = N
,它的大小列的,检查)。
如果你所要做的就是打电话MPI_SEND和MPI_RECV交换各列,你会做; 您可以使用此类型来描述列的布局,你会被罚款。 但有一两件事。
你要调用MPI_Scatter
,它发送第一coltype(说)处理器0,下coltype到处理器等。如果你这样做了简单的一维数组,可以很容易地找出“下一个”数据,其中类型是; 如果你散射1点INT到每个处理器,“下一个”整数开头的第一个INT结束之后。
但是,新的coltype列有一个总的程度从柱开始进入N*N
MPI_DOUBLE
晚节-如果MPI_Scatter遵循同样的逻辑(它),它会开始寻找外部的“下一个”列矩阵存储器完全,所以在与下一个和下一个。 不仅你会得不到你想要的答案,该方案很可能会崩溃。
解决这个问题的方法是告诉MPI的计算里的“下一个”一个谎言的目的,这种数据类型的“大小”是在一点开始下一列开始之间的内存大小; 也就是说,只有一个MPI_DOUBLE
。 这不会影响发送的数据的量,这还是值得的数据1列; 它不仅影响计算“看齐下一个”。 在一个阵列列(或行),你可以发送这种规模是在内存中的适当的步长和MPI会选择正确的下一列送。 如果没有这个大小调整操作,你的程序可能会崩溃。
当你有更复杂的数据布局,如在链接到一个以上的2D阵列实施例的2D-块,则有“下一个”项之间没有一个单一的步长大小; 你仍然需要做调整大小的技巧,使大小是一些有用的单位,但随后你需要使用MPI_Scatterv ,而不是分散明确指定要由发送的位置。