gpt4 book ai didi

c++ - 具有用户定义函数和 MPI_BOTTOM 的 Allreduce

转载 作者:行者123 更新时间:2023-11-30 03:40:56 28 4
gpt4 key购买 nike

考虑下面的程序,它应该对 double 进行一些愚蠢的添加:

#include <iostream>
#include <vector>

#include <mpi.h>

void add(void* invec, void* inoutvec, int* len, MPI_Datatype*)
{
double* a = reinterpret_cast <double*> (inoutvec);
double* b = reinterpret_cast <double*> (invec);

for (int i = 0; i != *len; ++i)
{
a[i] += b[i];
}
}

int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);

std::vector<double> buffer = { 2.0, 3.0 };

MPI_Op operation;
MPI_Op_create(add, 1, &operation);

MPI_Datatype types[1];
MPI_Aint addresses[1];
int lengths[1];
int count = 1;

MPI_Get_address(buffer.data(), &addresses[0]);
lengths[0] = buffer.size();
types[0] = MPI_DOUBLE;

MPI_Datatype type;
MPI_Type_create_struct(count, lengths, addresses, types, &type);
MPI_Type_commit(&type);

MPI_Allreduce(MPI_IN_PLACE, MPI_BOTTOM, 1, type, operation, MPI_COMM_WORLD);

MPI_Type_free(&type);
MPI_Op_free(&operation);
MPI_Finalize();

std::cout << buffer[0] << " " << buffer[1] << "\n";
}

因为这是更大程序的一部分,我想发送的数据 1) 在堆上,2) 由不同的类型组成,所以我认为我必须使用用户定义的类型。

现在这里一定有问题,因为程序在使用 mpirun -n 2 ./a.out 运行时崩溃了。来自 gdb 的回溯是:

#0  __memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:158
#1 0x00007ffff65de460 in non_overlap_copy_content_same_ddt () from /usr/local/lib/libopen-pal.so.6
#2 0x00007ffff180a69b in ompi_coll_tuned_allreduce_intra_recursivedoubling () from /usr/local/lib/openmpi/mca_coll_tuned.so
#3 0x00007ffff793bb8b in PMPI_Allreduce () from /usr/local/lib/libmpi.so.1
#4 0x00000000004088b6 in main (argc=1, argv=0x7fffffffd708) at mpi_test.cpp:39

第 39 行是 MPI_Allreduce 调用。这可能是一个愚蠢的错误,但在盯着它看了几个小时之后,我仍然没有看到它。有人发现错误吗?谢谢!

最佳答案

编辑:Open MPI 在执行就地缩减为时如何处理具有非零下限的类型(例如您在使用绝对地址时创建的类型)存在一个错误全部。它似乎存在于所有版本中,包括开发分支。可以通过关注 issue on GitHub 来跟踪状态.


您的 add 运算符是错误的,因为您没有考虑数据类型的下限。一个合适的解决方案是这样的:

void add(void* invec, void* inoutvec, int* len, MPI_Datatype* datatype)
{
MPI_Aint lb, extent;
MPI_Type_get_true_extent(*datatype, &lb, &extent);

double* a = reinterpret_cast <double*> (reinterpret_cast <char*>(inoutvec) + lb);
double* b = reinterpret_cast <double*> (reinterpret_cast <char*>(invec) + lb);

for (int i = 0; i != *len; ++i)
{
a[i] += b[i];
}
}

这将正确访问数据,但仍然是错误的。 *len 将是 1,因为这是您传递给 MPI_Allreduce 的值,但每个元素后面有两个 double 。正确编写的运算符将使用类型自省(introspection)机制来获取 double block 的长度并将 *len 乘以它,或者简单地将 vector 长度硬编码为二:

for (int i = 0; i < 2*(*len); i++)
{
a[i] += b[i];
}

关于c++ - 具有用户定义函数和 MPI_BOTTOM 的 Allreduce,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37664742/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com