我该如何将长整型和/或无符号整型传递给MPI参数?

4

假设我有一个非常大的数组,我希望使用MPI(v1)发送或接收它。为了索引这个数组,我使用了一个无符号长整型。

现在,我看到所有MPI函数调用都使用int类型作为它们的“count”参数,例如在这个例子中:

MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)

但是,如果在我的实现中,我需要发送/接收一个比int可以容纳的最大数量更大的数组怎么办?当我尝试将无符号整数传递给“count”参数时,编译器自然会给出“无效转换”错误。我考虑过进行强制类型转换,但我担心这会缩小我的变量,所以我有点不知所措。


2
你可能需要将数据包分成多个较小的数据包。 - slugonamission
请参见 https://dev59.com/eX_aa4cB1Zd3GeqP5ZuJ。 - Jeff Hammond
2个回答

6

进行强制类型转换并不是解决方案,因为它只会截断长的计数。这里有两个障碍需要克服-一个容易,一个困难。

容易的障碍是计数参数的 int 类型。你可以通过创建一个更小的连续类型,并将数据作为新数据类型的倍数发送来解决这个问题。以下是一个示例代码:

// Data to send
int data[1000];

// Create a contiguous datatype of 100 ints
MPI_Datatype dt100;
MPI_Type_contiguous(100, MPI_INT, &dt100);
MPI_Type_commit(&dt100);

// Send the data as 10 elements of the new type
MPI_Send(data, 10, dt100, ...);

MPI_Type_contiguouscount参数是int类型,使用此技术可以发送多达(231-1)2 = (262 - 232 + 1)个元素。如果这还不够,您可以从dt100数据类型创建一个新的连续数据类型,例如:

// Create a contiguous datatype of 100 dt100's (effectively 100x100 elements)
MPI_Datatype dt10000;
MPI_Type_contiguous(100, dt100, &dt10000);
MPI_Type_commit(&dt10000);

如果您的原始数据大小不是新数据类型大小的倍数,您可以创建一个结构数据类型,其第一个元素是连续数据类型的int(data_size / cont_type_length)个元素的数组,第二个元素是基本数据类型的datasize % cont_type_length个元素的数组。以下是示例:
// Data to send
int data[260];

// Create a structure type
MPI_Datatype dt260;

int blklens[2];
MPI_Datatype oldtypes[2];
MPI_Aint offsets[2];

blklens[0] = 2; // That's int(260 / 100)
offsets[0] = 0;
oldtypes[0] = dt100;

blklens[1] = 60; // That's 260 % 100
offsets[1] = blklens[0] * 100L * sizeof(int); // Offsets are in BYTES!
oldtypes[1] = MPI_INT;

MPI_Type_create_struct(2, blklens, offsets, oldtypes, &dt260);
MPI_Type_commit(&dt260);

// Send the data
MPI_Send(data, 1, dt260, ...);

MPI_Aint是一个可以容纳偏移量的整数,它比int在LP64系统上能够表示更大的偏移量。请注意接收方必须构建相同的数据类型,并在MPI_Recv中类似地使用它。然而,接收任意非整数数量的连续数据类型有些困难。

这是一个简单的障碍。不那么简单的障碍出现在MPI实现内部不使用长计数的情况下。在这种情况下,MPI通常会崩溃或只发送部分数据,或者可能会发生奇怪的事情。即使没有构造特殊的数据类型,这样的MPI实现也可能会崩溃,只需将类型为MPI_INTINT_MAX个元素发送即可,因为总消息大小将是(231 - 1) * 4 = 233 - 4。如果是这种情况,你唯一的逃脱方式是手动分割消息并在循环中发送/接收。


仅就“现在是2014年”的评论而言,例如使用Intel MPI,消息大小仍然限制为2GB,即使元素数量适合4字节int(https://software.intel.com/en-us/forums/topic/361060和https://software.intel.com/en-us/forums/topic/505683)。我不知道其他实现情况。 - steabert
这只是晚上自动写作的影响。最近我们在集群上遇到了一些软件问题,当用户从Open MPI切换到Intel MPI时出现问题,而消息大小是罪魁祸首。 - Hristo Iliev

0
一个快速/粗略的解决方案是在发送器中对无符号计数器进行reinterpret_cast<int>(),并在接收器中进行反向转换。然而,我认为更好的解决方案是创建一个包含指针和计数的结构体,并使用正确的类型遵循this answer的建议创建自己的自定义数据类型来传递MPI_Type_create_struct。

我不认为你的任何一种想法都能导致传输正确数量的数据。消息大小不是一个不透明的值。 - Ben Voigt
谢谢你的回答,但我不太明白如何使用结构体来实现这个。主要问题是,结构体还需要一个“计数”变量。所以,是的,我可以将我需要的整个数组范围打包到一个结构体中,然后只发送那个“一个”结构体。但在创建结构体时,我面临着同样的问题,即MPI不接受整数参数。你能帮我理解一下你的想法吗? - Mark Anderson
@MarkAnderson 当你发送结构体时,计数是你发送的那些结构体的数量。在你的情况下,它将是一个单独的结构体,因此计数为1。 - maxywb
@BenVoigt,“count”参数并不直接指定发送的数据量,而是指缓冲区中包含的元素数。请参阅http://www.mpich.org/static/docs/v3.1/www3/MPI_Recv.html,要发送的数据类型的大小是一个单独的参数。 - maxywb
@maxywb 我知道。但是在创建结构本身时,您必须给出结构内元素的数量。因此,这只是将问题推迟了一步。问题不在于数据类型的大小,而恰恰在于缓冲区中包含的元素数量,因为我的缓冲区可能包含大量元素。 - Mark Anderson
@MarkAnderson,对分布式文件系统方面我忘了,回复楼主的评论可能是最好的选择。 - maxywb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接