如何使矢量 MPI 数据类型独立于计数?
How can I make a vector MPI datatype independent of the count?
我有步幅为 2 的数据(例如),我想通过多个不同 length.
的消息发送此数据
如果元素的数量(到 count
)是固定的,我可以简单地 create a vector type 包括计数。这有效:
int stride = 2;
MPI_Datatype type;
MPI_Type_vector(count, 1, stride, MPI_INT, &type);
MPI_Type_commit(&type);
MPI_Send(buffer, 1, type, 1, 123, MPI_COMM_WORLD); // or Recv
(注意我将 1
传递给 MPI_Send
。)
但是,如果 count
是可变的(例如,在一个循环中,固定步长 = 2 时更改计数),我将不得不为每个长度创建并提交一个数据类型。
我想我可以定义一个带有单位计数的类型,并将计数放在消息发送函数本身中,但在我的测试中结果不同:
int stride = 2;
MPI_Datatype type;
MPI_Type_vector(1, 1, stride, MPI_INT, &type);
MPI_Type_commit(&type);
MPI_Send(buffer, count, type, 1, 123, MPI_COMM_WORLD); // or Recv
上面这段代码与第一个代码的作用不同,因此我推断计数在数据类型和消息调用中具有不同的含义。
如何创建独立于计数的跨步数据类型?
这段代码更接近目标场景。如果我将计数放入数据类型创建并将所有代码放入循环中,这将起作用。
int stride = 2;
MPI_Datatype type;
MPI_Type_vector(1, 1, stride, MPI_INT, &type);
MPI_Type_commit(&type);
for(int count = 1; count != N; ++count){
MPI_Send(buffer + count*10, count, type, 1, 123, MPI_COMM_WORLD); // or Recv
}
TL;DR 您需要使用 MPI_Type_create_resized
调整向量数据类型的大小,以在末尾包含 stride - 1
个元素的间隙。
首先,类型构造函数的参数顺序错误 - 步幅在块长度之后,即它应该是 MPI_Type_vector(1, 1, stride, MPI_INT, &type)
。但是解决这个问题并不足以让它与多个块一起工作,并且需要对 MPI 数据类型有一些了解。
MPI 数据类型只是原始类型及其相应偏移量(称为类型映射)的列表。当您告诉 MPI 从位置 buffer
发送类型 type
的元素时,库会遍历类型映射并从相对于 buffer
指定的位置读取每个基本类型的值相应的偏移量。例如,具有类型映射 {(int,0),(char,6)}
的数据类型导致 MPI 从位置 buffer + 0
读取 int
并从位置 buffer + 6
读取 char
(这些是字节偏移量) .偏移量可以是正的也可以是负的。预定义的 MPI 数据类型(例如 MPI_INT
)具有类型映射,该映射由单个条目组成,将相应语言类型的值放置在偏移量 0 处,即 {(int,0)}
.
每个 MPI 数据类型都有两个基本属性 - 它的下限 (LB) 和它的范围。下限是类型映射中的最低偏移量。范围是(最高偏移量 + 位于那里的原始数据类型的大小 + 对齐填充)和下限之间的差异。可以用任意值覆盖 LB 和范围,从而改变数据类型的外观形状。后者在 sending/receiving 数据类型数组时很重要,因为 MPI 使用 buffer + i * extent
作为第 i 元素到 read/write 的位置,因此具有正确的范围是至关重要的。
当您创建具有给定步幅的向量类型时,MPI 会设置类型映射的元素,以便在块之间留出适当的间隙,但不会在末尾留下间隙最后一个块。 MPI_INT
的向量,步长 stride
,块计数 1
,块长度 1
与 MPI_INT
完全相同,即使 stride
超过1
。实际上,如果您阅读 MPI standard(第 4.7 节,第 87 页),它会说 MPI_Type_vector(1, count, n, oldtype, &newtype)
等同于 MPI_Type_contiguous(count, oldtype, &newtype)
对于 n
.[=42= 的任何值]
要使其实际工作,您需要告诉 MPI 人为地扩大范围以包含末尾的间隙。这是使用 MPI_Type_create_resized
完成的。如果块的长度为 1
,您可以简单地调整原始预定义数据类型的大小,如 Gilles 的评论所示:
MPI_Datatype type;
MPI_Type_create_resized(MPI_INT, 0, stride * sizeof(int), &type);
MPI_Type_commit(&type);
否则,您需要先创建矢量类型,然后调整它的大小:
MPI_Datatype type1, type;
MPI_Type_vector(1, count, stride, MPI_INT, &type1);
MPI_Type_create_resized(type1, 0, stride * sizeof(int), &type);
MPI_Type_free(&type1);
MPI_Type_commit(&type);
您现在可以使用 type
到 MPI_Send
/MPI_Recv
任意 send/receive 计数。
我有步幅为 2 的数据(例如),我想通过多个不同 length.
的消息发送此数据如果元素的数量(到 count
)是固定的,我可以简单地 create a vector type 包括计数。这有效:
int stride = 2;
MPI_Datatype type;
MPI_Type_vector(count, 1, stride, MPI_INT, &type);
MPI_Type_commit(&type);
MPI_Send(buffer, 1, type, 1, 123, MPI_COMM_WORLD); // or Recv
(注意我将 1
传递给 MPI_Send
。)
但是,如果 count
是可变的(例如,在一个循环中,固定步长 = 2 时更改计数),我将不得不为每个长度创建并提交一个数据类型。
我想我可以定义一个带有单位计数的类型,并将计数放在消息发送函数本身中,但在我的测试中结果不同:
int stride = 2;
MPI_Datatype type;
MPI_Type_vector(1, 1, stride, MPI_INT, &type);
MPI_Type_commit(&type);
MPI_Send(buffer, count, type, 1, 123, MPI_COMM_WORLD); // or Recv
上面这段代码与第一个代码的作用不同,因此我推断计数在数据类型和消息调用中具有不同的含义。
如何创建独立于计数的跨步数据类型?
这段代码更接近目标场景。如果我将计数放入数据类型创建并将所有代码放入循环中,这将起作用。
int stride = 2;
MPI_Datatype type;
MPI_Type_vector(1, 1, stride, MPI_INT, &type);
MPI_Type_commit(&type);
for(int count = 1; count != N; ++count){
MPI_Send(buffer + count*10, count, type, 1, 123, MPI_COMM_WORLD); // or Recv
}
TL;DR 您需要使用 MPI_Type_create_resized
调整向量数据类型的大小,以在末尾包含 stride - 1
个元素的间隙。
首先,类型构造函数的参数顺序错误 - 步幅在块长度之后,即它应该是 MPI_Type_vector(1, 1, stride, MPI_INT, &type)
。但是解决这个问题并不足以让它与多个块一起工作,并且需要对 MPI 数据类型有一些了解。
MPI 数据类型只是原始类型及其相应偏移量(称为类型映射)的列表。当您告诉 MPI 从位置 buffer
发送类型 type
的元素时,库会遍历类型映射并从相对于 buffer
指定的位置读取每个基本类型的值相应的偏移量。例如,具有类型映射 {(int,0),(char,6)}
的数据类型导致 MPI 从位置 buffer + 0
读取 int
并从位置 buffer + 6
读取 char
(这些是字节偏移量) .偏移量可以是正的也可以是负的。预定义的 MPI 数据类型(例如 MPI_INT
)具有类型映射,该映射由单个条目组成,将相应语言类型的值放置在偏移量 0 处,即 {(int,0)}
.
每个 MPI 数据类型都有两个基本属性 - 它的下限 (LB) 和它的范围。下限是类型映射中的最低偏移量。范围是(最高偏移量 + 位于那里的原始数据类型的大小 + 对齐填充)和下限之间的差异。可以用任意值覆盖 LB 和范围,从而改变数据类型的外观形状。后者在 sending/receiving 数据类型数组时很重要,因为 MPI 使用 buffer + i * extent
作为第 i 元素到 read/write 的位置,因此具有正确的范围是至关重要的。
当您创建具有给定步幅的向量类型时,MPI 会设置类型映射的元素,以便在块之间留出适当的间隙,但不会在末尾留下间隙最后一个块。 MPI_INT
的向量,步长 stride
,块计数 1
,块长度 1
与 MPI_INT
完全相同,即使 stride
超过1
。实际上,如果您阅读 MPI standard(第 4.7 节,第 87 页),它会说 MPI_Type_vector(1, count, n, oldtype, &newtype)
等同于 MPI_Type_contiguous(count, oldtype, &newtype)
对于 n
.[=42= 的任何值]
要使其实际工作,您需要告诉 MPI 人为地扩大范围以包含末尾的间隙。这是使用 MPI_Type_create_resized
完成的。如果块的长度为 1
,您可以简单地调整原始预定义数据类型的大小,如 Gilles 的评论所示:
MPI_Datatype type;
MPI_Type_create_resized(MPI_INT, 0, stride * sizeof(int), &type);
MPI_Type_commit(&type);
否则,您需要先创建矢量类型,然后调整它的大小:
MPI_Datatype type1, type;
MPI_Type_vector(1, count, stride, MPI_INT, &type1);
MPI_Type_create_resized(type1, 0, stride * sizeof(int), &type);
MPI_Type_free(&type1);
MPI_Type_commit(&type);
您现在可以使用 type
到 MPI_Send
/MPI_Recv
任意 send/receive 计数。