MPI的数据类型适用于花车,而不是双打。它是一个对齐问题? [英] MPI derived datatype works for floats, but not for doubles. Is it an alignment issue?
问题描述
我必须与正在沟通与MPI的数据类型的帮助下,C-结构,一个奇怪的问题。以下作品中的例子。它简单的发送由一个整数
加4 浮动
值的消息。
I have a weird issue related to a C-structure that is communicated with the help of an MPI derived datatype. The example below works; it simply sends a message consisting of one integer
plus 4 float
values.
Minmum的例子:
#include <mpi.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int i, rank, tag = 1;
MPI_Status status;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// Array of doubles plus element count
typedef struct {
int row;
float elements[4];
} My_array;
// Derived datatype for an array of doubles plus element count
MPI_Datatype MY_ARRAY_TYPE;
const int nr_blocks = 2;
int blocklengths[2] = {1, 4};
MPI_Datatype oldtypes[2] = {MPI_INT, MPI_FLOAT};
MPI_Aint extent, lb;
MPI_Type_get_extent(MPI_INT, &lb, &extent);
MPI_Aint displacements[2] = {0, extent};
MPI_Type_create_struct(nr_blocks, blocklengths, displacements,
oldtypes, &MY_ARRAY_TYPE);
MPI_Type_commit(&MY_ARRAY_TYPE);
if(rank == 0) {
My_array array1 = {3, 3.1, 3.2, 3.3, 3.4};
MPI_Send(&array1, 1, MY_ARRAY_TYPE, 1, tag, MPI_COMM_WORLD);
}
if(rank == 1) {
My_array array2;
MPI_Recv(&array2, 1, MY_ARRAY_TYPE, 0, tag, MPI_COMM_WORLD, &status);
printf("Rank %d received elements of row %d:\n", rank, array2.row);
for(i = 0; i < 4; i++)
printf("\t%.1f\n", array2.elements[i]);
}
MPI_Type_free(&MY_ARRAY_TYPE);
MPI_Finalize();
}
如果你有机会到MPI安装,例如可以通过 mpicc -o例如example.c
编译和的mpirun -np运行例如2
。
输出应该是
If you have access to an MPI installation, the example can be compiled by mpicc -o example example.c
and run by mpirun -np 2 example
.
The output should be
Rank 1 received elements of row 3:
3.1
3.2
3.3
3.4
问题:
现在,当浮动
的阵s被改为数组双击
S,并据此 MPI_FLOAT
到 MPI_DOUBLE
,我得到一个错误的结果。
The problem:
Now when the array of float
s is changed to an array of double
s, and accordingly MPI_FLOAT
to MPI_DOUBLE
, I get a wrong result.
这code:
#include <mpi.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int i, rank, tag = 1;
MPI_Status status;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// Array of doubles plus element count
typedef struct {
int row;
double elements[4];
} My_array;
// Derived datatype for an array of doubles plus element count
MPI_Datatype MY_ARRAY_TYPE;
const int nr_blocks = 2;
int blocklengths[2] = {1, 4};
MPI_Datatype oldtypes[2] = {MPI_INT, MPI_DOUBLE};
MPI_Aint extent, lb;
MPI_Type_get_extent(MPI_INT, &lb, &extent);
MPI_Aint displacements[2] = {0, extent};
MPI_Type_create_struct(nr_blocks, blocklengths, displacements,
oldtypes, &MY_ARRAY_TYPE);
MPI_Type_commit(&MY_ARRAY_TYPE);
if(rank == 0) {
My_array array1 = {3, 3.1, 3.2, 3.3, 3.4};
MPI_Send(&array1, 1, MY_ARRAY_TYPE, 1, tag, MPI_COMM_WORLD);
}
if(rank == 1) {
My_array array2;
MPI_Recv(&array2, 1, MY_ARRAY_TYPE, 0, tag, MPI_COMM_WORLD, &status);
printf("Rank %d received elements of row %d:\n", rank, array2.row);
for(i = 0; i < 4; i++)
printf("\t%.1f\n", array2.elements[i]);
}
MPI_Type_free(&MY_ARRAY_TYPE);
MPI_Finalize();
}
生产:
Rank 1 received elements of row 3:
3.1
3.2
3.3
0.0
我尝试了一下周围,在结构和派生数据类型使用其它数据(例如,整数而不是一个数组, INT
/ MPI_INT
而不是浮动
/ MPI_FLOAT
等),并看到问题使用时,双打只出现。这让我怀疑这可能是各种各样的对齐问题 - 但我卡在那里。 MPI应自动照顾比对。
I tried around a bit, using other data in the struct and the derived datatype (e.g., an array of integers instead of just one, int
/MPI_INT
instead of float
/MPI_FLOAT
, etc.) and saw that the problem arises only when doubles are used. Which makes me suspect that this might be an alignment issue of sorts - but I am stuck there. MPI should take care of alignments automatically.
问:为什么用浮动
/ MPI_FLOAT
上面的例子中的工作,但与双击
/ MPI_DOUBLE
,我该如何解决这个问题?
Question: Why does the above example work with float
/MPI_FLOAT
, but not with double
/MPI_DOUBLE
and how can I fix it?
有些机细节,可能是相关的:
Some machine specifics that might be relevant:
- CPU:AMD皓龙6134
- 地址尺寸:48位
- 对齐:64
- 编译器:GCC 4.4.7
- MPI库:(可惜)厂商特定
编辑:在弗拉基米尔·F中的意见建议,我增加了code不起作用
as suggested in the comments by Vladimir F, I added the code that does not work.
推荐答案
我只是发现了问题所在:它确实是对齐。第二code上市产生正确的第3双打也不过是一个奇怪的巧合...通过使用 MPI_INT
为以下值的偏移量的扩大,我认为不会有什么填充。这是更好地计算这样的偏移量:
I just found out what the problem is: it is indeed alignment. That the second code listing produces the first 3 doubles correctly is nothing but a weird coincidence...By using the extend of MPI_INT
as the offset of the following value, I assumed that there would be no padding. It is better to compute the offsets like this:
#include <stddef.c>
...
MPI_Datatype MY_ARRAY_TYPE;
const int nr_blocks = 2;
int blocklengths[2] = {1, 4};
MPI_Datatype oldtypes[2] = {MPI_INT, MPI_DOUBLE};
MPI_Aint displacements[2];
displacements[0] = offsetof(My_array, row);
displacements[1] = offsetof(My_array, elements);
MPI_Type_create_struct(nr_blocks, blocklengths, displacements,
oldtypes, &MY_ARRAY_TYPE);
MPI_Type_commit(&MY_ARRAY_TYPE);
...
我真的有兴趣看看它是如何制定出这样......为什么我们拿到3正确的价值观和一个0.0?由于取向是关闭的4个字节和双打重新由8个字节我的平台,为什么我没有得到一些随机数上psented $ P $?如何前3已经去codeD正确,如果他们每人拿了一张双人床再加上接下来的双重的上4下4个字节?
I'd really be interested to see how it can work out this way...why do we get 3 correct values and one 0.0? Since the alignment was off by 4 bytes and doubles are represented by 8 bytes on my platform, why didn't I get some random numbers? How can the first 3 have been decoded correctly if they each took the lower 4 bytes of one double plus the upper 4 of the next double?
这篇关于MPI的数据类型适用于花车,而不是双打。它是一个对齐问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!