了解块和块循环矩阵分布

时间:2015-06-26 15:26:52

标签: matrix mpi distributed-computing scalapack

在处理矩阵的并行分解时,我熟悉一个块分布,我们有(比方说)4个进程,每个进程都有自己的矩阵子区域:

Block Matrix Decomposition

因此,例如,我们在一行(procrows)中的进程数等于2,列中的进程数(proccols)也等于2,并且如果原始矩阵大小为A_local,则矩阵N/2 x M/2的大小为N x M

我正在读这个example,它使用" block-cyclic"分发,在这部分:

/* Begin Cblas context */
/* We assume that we have 4 processes and place them in a 2-by-2 grid */
int ctxt, myid, myrow, mycol, numproc;
int procrows = 2, proccols = 2;
Cblacs_pinfo(&myid, &numproc);
Cblacs_get(0, 0, &ctxt);
Cblacs_gridinit(&ctxt, "Row-major", procrows, proccols);

他们procrowsproccols是硬编码的,很好,但对于读入的矩阵,有一个标题:

  

Nb和Mb将是[矩阵]

的块的行数和列数

我不明白这一点;是不是NbMb完全由N,M,procrows和proccols决定?

修改

从运行示例中我可以看到进程0上的子矩阵具有矩阵左上角的所有元素,就像我上面的图片一样,这与Jonathan的答案相矛盾。但是,它与ScaLAPACK的Cholesky一起工作正常。

1 个答案:

答案 0 :(得分:7)

如你在问题中描述的那样阻止矩阵的分解是一种非常有效的分布矩阵的方法,但它并不是唯一的方法。

特别是,块数据分布(将矩阵分解为procrows x process子矩阵)有点不灵活。如果矩阵大小不能被行或列中的进程数整除 - 并且通常您无法控制矩阵的大小,并且只有procrows / proccols的一些灵活性 - 您最终可能会遇到严重的负载平衡问题。而且,有时能够“过度分解”问题非常方便;将它分解成比你有任务更多的碎片。特别是,对于MPI,由于每个任务都是一个过程,因此有时可以为每个进程运行多个子矩阵,以便您可以通过线程处理这种额外的并行度(内置于大多数单过程线性代数库)。

获得大多数灵活性以实现负载平衡并具有最高程度的进程间并行性的方法是纯循环分发。在1d循环分布中,比如在4个处理器之间划分15个项目,处理器1将获得项目1,2将获得项目2,3将获得项目3,4将获得4,然后处理器1将获得项目5,因此上;你在处理器上循环项目。

另一方面,在1d块分解中,处理器1将获得项目1-4,处理器2将获得5-9,依此类推。

随后是有用的LLNL parallel computing tutorial的数字,每个颜色标记哪个处理器得到了数据的区域:

enter image description here

因此,循环分解对于并行和负载平衡最大,但对于数据访问来说,它是可怕的;您希望能够访问的每个相邻数据都可以执行线性代数操作。另一方面,块分解对数据访问最有利;你有尽可能大的连续数据块,所以你可以在漂亮的大子矩阵上进行矩阵运算;但它对于并行性来说是不灵活的,并且在负载平衡方面可能会花费。

Block-Cyclic是两者之间的插值;您将矩阵分解为块,并在进程间循环分配这些块。这使您可以调整数据访问连续​​性和灵活性之间的权衡。如果块循环块大小为1,则表示循环分布;如果它们是N/procrowsN/proccols,则您有块分发;但你也可以在两者之间有任何东西。

请注意,在2D中,您原则上可以选择沿行和列的不同分解,有时如果您的矩阵仅用于某种​​计算,则这种分解很有用;但更常见的情况是所有维度的分解是相同的,因此当人们说“块分解”或“块循环分解”时,它们通常意味着沿着所有维度。

对此的一个很好的描述是Scalapack pages at netlib