如何使矢量 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,块长度 1MPI_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);

您现在可以使用 typeMPI_Send/MPI_Recv 任意 send/receive 计数。