MPI - 传达 1 个大型元素或多个小型元素?
MPI - communicate 1 element of a big type or more elements of a small type?
在我处理的具体问题中,排列在 3D 拓扑中的进程必须相互交换 3D 数组的部分 A(:,:,:)
。特别是,每个人都必须向六个方向上的进程发送给定数量的 A
切片(例如 A(nx-1:nx,:,:)
到正一维的进程, A(1:3,:,:)
在负一,A(:,ny-3:ny,:)
在正 y 维度上,依此类推)。
为此,我将定义一组子数组类型(通过 MPI_TYPE_CREATE_SUBARRAY
)用于通信(可能是 MPI_NEIGHBOR_ALLTOALL
,或其 V
或 W
扩展)。问题是就性能而言,更好的选择是:
- 定义 3 个子数组(每个维度一个),每个子数组实际上是一个二维数组,然后使通信沿每个维度在两个方向上发送不同数量的这些类型,或者
- 定义6个子数组(每个方向一个),每个仍然是一个三维数组,然后让通信沿每个维度发送两个方向上两种类型的一个元素?
最后,更笼统一点,如题中所说,是定义更多"basic" MPI派生数据类型并在通信中使用counts
大于1更好,还是定义"bigger" 在通讯中输入和使用 counts = 1
?
定义了 MPI 派生数据类型,以便为库提供一种打包和解包您发送的数据的方法。
对于基本类型(MPI_INT、MPI_DOUBLE等)没有问题,因为内存中的数据已经是连续的:内存中没有空洞。
更复杂的类型,例如多维数组或结构,按原样发送数据可能效率低下,因为您可能正在发送无用的数据。出于这个原因,数据被打包成一个连续的字节数组,发送到目的地,然后再次解包以恢复其原始形状。
也就是说,您需要为内存中的每个不同形状创建派生数据类型。例如,A(1:3,:,:)
和 A(nx-2:nx,:,:)
表示相同的数据类型。但是 A(nx-2:nx,:,:)
和 A(:,nx-2:nx,:)
不会。如果您正确指定了步幅访问(连续数据类型之间的差距),您甚至可以指定一个二维派生数据类型,然后改变 count
参数以获得更好的程序灵活性。
最后,回答你的最后一个问题,这可能值得进行基准测试,尽管我认为差异不会很明显,因为在这两种情况下它都会产生一条 MPI 消息。
在我处理的具体问题中,排列在 3D 拓扑中的进程必须相互交换 3D 数组的部分 A(:,:,:)
。特别是,每个人都必须向六个方向上的进程发送给定数量的 A
切片(例如 A(nx-1:nx,:,:)
到正一维的进程, A(1:3,:,:)
在负一,A(:,ny-3:ny,:)
在正 y 维度上,依此类推)。
为此,我将定义一组子数组类型(通过 MPI_TYPE_CREATE_SUBARRAY
)用于通信(可能是 MPI_NEIGHBOR_ALLTOALL
,或其 V
或 W
扩展)。问题是就性能而言,更好的选择是:
- 定义 3 个子数组(每个维度一个),每个子数组实际上是一个二维数组,然后使通信沿每个维度在两个方向上发送不同数量的这些类型,或者
- 定义6个子数组(每个方向一个),每个仍然是一个三维数组,然后让通信沿每个维度发送两个方向上两种类型的一个元素?
最后,更笼统一点,如题中所说,是定义更多"basic" MPI派生数据类型并在通信中使用counts
大于1更好,还是定义"bigger" 在通讯中输入和使用 counts = 1
?
定义了 MPI 派生数据类型,以便为库提供一种打包和解包您发送的数据的方法。
对于基本类型(MPI_INT、MPI_DOUBLE等)没有问题,因为内存中的数据已经是连续的:内存中没有空洞。
更复杂的类型,例如多维数组或结构,按原样发送数据可能效率低下,因为您可能正在发送无用的数据。出于这个原因,数据被打包成一个连续的字节数组,发送到目的地,然后再次解包以恢复其原始形状。
也就是说,您需要为内存中的每个不同形状创建派生数据类型。例如,A(1:3,:,:)
和 A(nx-2:nx,:,:)
表示相同的数据类型。但是 A(nx-2:nx,:,:)
和 A(:,nx-2:nx,:)
不会。如果您正确指定了步幅访问(连续数据类型之间的差距),您甚至可以指定一个二维派生数据类型,然后改变 count
参数以获得更好的程序灵活性。
最后,回答你的最后一个问题,这可能值得进行基准测试,尽管我认为差异不会很明显,因为在这两种情况下它都会产生一条 MPI 消息。