[英]How to send GMP or MPFR types with MPI
我嘗試使用MPI_Scatter
發送mpfr_t
類型的變量。 例如:
mpfr_t *v1 = new mpfr_t[10];
mpfr_t *v2 = new mpfr_t[10];
MPI_Scatter(v1, 5, MPI_BYTE, v2, 5, MPI_BYTE, 0, MPI_COMM_WORLD );
for (int i = 0; i < 5; i++)
mpfr_printf("value rank %d - %RNf \n", ProcRank, v2[i]);
它打印:
value rank 0 - nan
value rank 0 - nan
value rank 0 - nan
.....
value rank 1 - nan
value rank 0 - nan
但這是 MPI_Bcast 的工作。 我做錯了什么。 代碼 C/C++,MPI 庫是 OpenMPI-1.6。
您將發送計數指定為5,將數據類型指定為MPI_BYTE。 這似乎很奇怪。 如果要使用MPI_BYTE,並且要發送5個mpfr_t值,則將發送計數指定為5 * sizeof(mpfr_t)。 另一個選擇是創建自己的MPI派生數據類型(如果要擺脫sizeof())。
正如@LaryxDecidua 已經指出的那樣,MPFR 數字在堆上使用動態 memory,因此不能直接用於 MPI 操作。 但是,如果您可以使用 MPFR 4.0.0 或更高版本,則可以使用 MPFR function mpfr_fpif_export
將數字序列化為線性 memory 緩沖區,然后使用 MPI 發送此緩沖區。 接收端可以通過調用mpfr_fpif_import
恢復原來的號碼。 這兩個函數都對FILE *
句柄進行操作,因此您還需要使用open_memstream
和/或fmemopen
將文件句柄 map 到 memory 緩沖區。 不幸的是,序列化數字的長度不僅取決於精度,還取決於值(例如,值 0 比其他數字占用更少的字節),因此像MPI_Scatter
或MPI_Gather
這樣的組通信需要為每個等級固定緩沖區大小將不會'不工作。 請改用MPI_Send
和MPI_recv
對。
這是一個完整的 C++17 示例,它為mpreal
代碼庫提供了一個很好的 MPFR 數字接口:
#include <cstdio>
#include <iostream>
#include <mpi.h>
#include <mpreal.h>
#include <numeric>
#include <optional>
int main(int argc, char **argv) {
MPI_Init(&argc, &argv);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
std::vector<mpfr::mpreal> real_vec{world_rank, M_PI};
// Serialize the mpreal vector to memory (send_buf)
char *send_buf;
size_t send_buf_size;
FILE *real_stream = open_memstream(&send_buf, &send_buf_size);
for (auto &real : real_vec) {
mpfr_fpif_export(real_stream, real.mpfr_ptr());
}
fclose(real_stream);
// Gather the buffer length of all processes
std::optional<std::vector<size_t>> send_buf_size_vec;
if (world_rank == 0) {
send_buf_size_vec = std::vector<size_t>(world_size);
}
MPI_Gather(&send_buf_size, 1, MPI_UNSIGNED_LONG, (send_buf_size_vec ? send_buf_size_vec->data() : nullptr), 1,
MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
if (world_rank != 0) {
// Send the serialized mpreal vector to rank 0
MPI_Send(send_buf, send_buf_size, MPI_BYTE, 0, 0, MPI_COMM_WORLD);
} else {
// Create a recv buffer which can hold the data from all processes
size_t recv_buf_size = std::accumulate(send_buf_size_vec->begin(), send_buf_size_vec->end(), 0UL);
std::vector<char> recv_buf(recv_buf_size);
auto all_buf_it = recv_buf.begin();
// Directly copy the send buffer of process 0
std::memcpy(&*all_buf_it, send_buf, send_buf_size);
all_buf_it += (*send_buf_size_vec)[0];
// Receive serialized numbers from all other ranks
MPI_Status status;
for (int i = 1; i < world_size; ++i) {
MPI_Recv(&*all_buf_it, (*send_buf_size_vec)[i], MPI_BYTE, i, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
all_buf_it += (*send_buf_size_vec)[i];
}
// Import all mpreals from the receive buffer
real_stream = fmemopen(recv_buf.data(), recv_buf.size(), "rb");
std::vector<mpfr::mpreal> all_real_vec(world_size * real_vec.size());
for (auto &real : all_real_vec) {
mpfr_fpif_import(real.mpfr_ptr(), real_stream);
}
fclose(real_stream);
// Print all received values
std::cout << "Read values:" << std::endl;
for (auto &real : all_real_vec) {
std::cout << real << std::endl;
}
}
MPI_Finalize();
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.