- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试对格子玻尔兹曼建模的 CUDA 代码进行 MPI,但在使用 MPI_Send 和 MPI_Recv 函数时遇到了令人沮丧的问题。我已经验证我有 CUDA 感知 MPI 和一些简单的设备缓冲区到设备缓冲区 MPI 发送/接收代码,所以我可以在 GPU 设备内存之间发送和接收数组,而无需通过 CPU/主机。
我的代码是针对 3D 晶格的,它在各个节点之间沿 z 方向划分,节点之间有光晕,以确保流体可以在这些划分之间流动。光环位于 GPU 上。下面的代码是一个简化和编译给出了与我的主要代码相同的错误。在这里,Rank 0 节点上的 GPU Halo 是 MPI_Send() 到 rank 1 节点,它是 MPI_Recv()。我的问题目前看起来很简单,我无法让 MPI_Send 和 MPI_Recv 调用起作用!代码不会进展到“//代码未到达此处。”行,让我得出结论,MPI_etc() 调用不起作用。
我的代码基本上如下,删除了大部分代码但仍然足以编译并出现相同的错误:
#include <mpi.h>
using namespace std;
//In declarations:
const int DIM_X = 30;
const int DIM_Y = 50;
const int Q=19;
const int NumberDevices = 1;
const int NumberNodes = 2;
__host__ int SendRecvID(int UpDown, int rank, int Cookie) {int a =(UpDown*NumberNodes*NumberDevices) + (rank*NumberDevices) + Cookie; return a;} //Use as downwards memTrnsfr==0, upwards==1
int main(int argc, char *argv[])
{
//MPI functions (copied from online tutorial somewhere)
int numprocessors, rank, namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numprocessors);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Get_processor_name(processor_name, &namelen);
/* ...code for splitting other arrays removed... */
size_t size_Halo_z = Q*DIM_X*DIM_Y*sizeof(double); //Size variable used in cudaMalloc and cudaMemcpy.
int NumDataPts_f_halo = DIM_X*DIM_Y*Q; //Number of data points used in MPI_Send/Recv calls.
MPI_Status status; //Used in MPI_Recv.
//Creating arrays for GPU data below, using arrays of pointers:
double *Device_HaloUp_Take[NumberDevices]; //Arrays on the GPU which will be the Halos.
double *Device_HaloDown_Take[NumberDevices]; //Arrays on the GPU which will be the Halos.
double *Device_HaloUp_Give[NumberDevices]; //Arrays on the GPU which will be the Halos.
double *Device_HaloDown_Give[NumberDevices]; //Arrays on the GPU which will be the Halos.
for(int dev_i=0; dev_i<NumberDevices; dev_i++) //Initialising the GPU arrays:
{
cudaSetDevice(dev_i);
cudaMalloc( (void**)&Device_HaloUp_Take[dev_i], size_Halo_z);
cudaMalloc( (void**)&Device_HaloDown_Take[dev_i], size_Halo_z);
cudaMalloc( (void**)&Device_HaloUp_Give[dev_i], size_Halo_z);
cudaMalloc( (void**)&Device_HaloDown_Give[dev_i], size_Halo_z);
}
int Cookie=0; //Counter used to count the devices below.
for(int n=1;n<=100;n++) //Each loop iteration is one timestep.
{
/* Run computation on GPUs */
cudaThreadSynchronize();
if(rank==0) //Rank 0 node makes the first MPI_Send().
{
for(Cookie=0; Cookie<NumberDevices; Cookie++)
{
if(NumberDevices==1) //For single GPU codes (which for now is what I am stuck on):
{
cout << endl << "Testing X " << rank << endl;
MPI_Send(Device_HaloUp_Take[Cookie], NumDataPts_f_halo, MPI_DOUBLE, (rank+1), SendRecvID(1,rank,Cookie), MPI_COMM_WORLD);
cout << endl << "Testing Y " << rank << endl; //CODE DOES NOT REACH HERE.
MPI_Recv(Device_HaloUp_Give[Cookie], NumDataPts_f_halo, MPI_DOUBLE, (rank+1), SendRecvID(0,rank+1,0), MPI_COMM_WORLD, &status);
/*etc */
}
}
}
else if(rank==(NumberNodes-1))
{
for(Cookie=0; Cookie<NumberDevices; Cookie++)
{
if(NumberDevices==1)
{
cout << endl << "Testing A " << rank << endl;
MPI_Recv(Device_HaloDown_Give[Cookie], NumDataPts_f_halo, MPI_DOUBLE, (rank-1), SendRecvID(1,rank-1,NumberDevices-1), MPI_COMM_WORLD, &status);
cout << endl << "Testing B " << rank << endl; //CODE DOES NOT REACH HERE.
MPI_Send(Device_HaloUp_Take[Cookie], NumDataPts_f_halo, MPI_DOUBLE, 0, SendRecvID(1,rank,Cookie), MPI_COMM_WORLD);
/*etc*/
}
}
}
}
/* Then some code to carry out rest of lattice boltzmann method. */
MPI_Finalize();
}
因为我有 2 个节点(代码中的 NumberNodes==2 变量),我有一个 rank==0,另一个 rank==1==NumberNodes-1。排名 0 的代码进入 if(rank==0) 循环,在那里它输出“Testing X 0”但永远不会输出“Testing Y 0”,因为它预先在 MPI_Send() 函数上中断。此时变量 Cookie 为 0,因为只有一个 GPU/设备,因此 SendRecvID() 函数采用“(1,0,0)”。 MPI_Send的第一个参数是一个指针,因为Device_Halo_etc是一个指针数组,而数据发送到的位置是(rank+1)=1。
同样,排名 1 的代码进入 if(rank==NumberNodes-1) 循环,输出“Testing A 1”而不是“Testing B 1”,因为代码在完成 MPI_Recv 调用之前停止。据我所知MPI_Recv的参数是正确的,因为(rank-1)=0是正确的,发送和接收的数据点数是正确的,ID是相同的。
到目前为止,我已经尝试通过手写 999 左右来确保它们每个都有完全相同的标签(尽管在每种情况下 SendRecvID() 都采用 (1,0,0) 所以是相同的),但这没有区别。我还在两个 MPI 调用中将 Device_Halo_etc 参数更改为 &Device_Halo_etc ,以防万一我弄乱了那里的指针,但也没有区别。到目前为止,我能让它工作的唯一方法是将 MPI_Send/Recv() 调用中的 Device_Halo_etc 参数更改为主机上的一些任意数组以测试它们是否传输,这样做允许它通过第一个 MPI 调用当然会卡在下一个,但即使这样也只有当我将发送/接收变量的数量更改为 1(而不是 NumDataPts_f_halo==14250)时才有效。当然,四处移动主机阵列是没有意义的。
使用带有附加链接变量的 nvcc 编译器运行代码(我不太确定这些是如何工作的,已经在某个地方在线复制了方法,但是考虑到更简单的设备到设备 MPI 调用已经起作用,我认为这没有问题), 通过:
nvcc TestingMPI.cu -o run_Test -I/usr/lib/openmpi/include -I/usr/lib/openmpi/include/openmpi -L/usr/lib/openmpi/lib -lmpi_cxx -lmpi -ldl
并编译:
mpirun -np 2 run_Test
这样做会给我一个通常看起来像这样的错误:
Testing A 1
Testing X 0
[Anastasia:16671] *** Process received signal ***
[Anastasia:16671] Signal: Segmentation fault (11)
[Anastasia:16671] Signal code: Invalid permissions (2)
[Anastasia:16671] Failing at address: 0x700140000
[Anastasia:16671] [ 0] /lib/x86_64-linux-gnu/libc.so.6(+0x364a0) [0x7f20327774a0]
[Anastasia:16671] [ 1] /lib/x86_64-linux-gnu/libc.so.6(+0x147fe5) [0x7f2032888fe5]
[Anastasia:16671] [ 2] /usr/lib/libmpi.so.1(opal_convertor_pack+0x14d) [0x7f20331303bd]
[Anastasia:16671] [ 3] /usr/lib/openmpi/lib/openmpi/mca_btl_sm.so(+0x20c8) [0x7f202cad20c8]
[Anastasia:16671] [ 4] /usr/lib/openmpi/lib/openmpi/mca_pml_ob1.so(+0x100f0) [0x7f202d9430f0]
[Anastasia:16671] [ 5] /usr/lib/openmpi/lib/openmpi/mca_pml_ob1.so(+0x772b) [0x7f202d93a72b]
[Anastasia:16671] [ 6] /usr/lib/libmpi.so.1(MPI_Send+0x17b) [0x7f20330bc57b]
[Anastasia:16671] [ 7] run_Test() [0x400ff7]
[Anastasia:16671] [ 8] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f203276276d]
[Anastasia:16671] [ 9] run_Test() [0x400ce9]
[Anastasia:16671] *** End of error message ***
--------------------------------------------------------------------------
mpirun noticed that process rank 0 with PID 16671 on node Anastasia exited on signal 11 (Segmentation fault).
--------------------------------------------------------------------------
我在我的笔记本电脑 (Anastasia) 上运行代码,这是一台联想 Y500,配备双 GT650m NVIDIA 显卡,在 Linux Ubuntu 12.04LTS 上运行,如果这有所不同的话。 nvcc --version
给出“release 5.0, V0.2.1221”,mpirun --version
给出“mpirun (Open MPI) 1.5.4”。
最佳答案
感谢 Anycorn 对代码的帮助!
如果任何有类似问题的人感兴趣,我的错误结果是确定我是否能够使用 MPI 调用访问 CUDA 内存。我无法使用 MPI_Send/Recv() GPU 内存,因此出现“无效权限”错误。如果有人有类似的问题,我建议您测试一个简单的代码,使用 MPI_Send/Recv() 函数发送设备内存,正如 Anycorn 在上述问题的评论部分所建议的那样。
请注意意外发送指向设备内存指针而不是设备内存指针的指针(MPI_Send/Recv() 函数中需要一个指针,它采用的第一个参数).我已经在不同节点之间发送了那个指针,因为指针在主机/CPU 内存上,所以调用工作正常。结果是节点 1 会给节点 0 一个指向指针的指针——当我输出我认为从节点 1 收集的数据时,我得到了新接收到的指针指向节点 0 的数据……这是指向我通过草率编码在两个节点上初始化的同一个数组(“if(node==1)初始化数组”行会把我救在那里)。因此,我收到了正确的输出,并认为一切都很好。
再次感谢 Anycorn!
关于c++ - 简单的 MPI_Send 和 Recv 使用 CUDA 给出段错误(11)和无效权限(2),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18070428/
我有一个使用 openmpi 编译和运行的代码。最近,我想使用 Intel MPI 运行同样的代码。但是我的代码没有按预期工作。我深入研究了代码,发现 MPI_Send 在两个实现中的行为不同。 我从
我想将 MPI_Send 消息发送到单个但可变的主机。我的意思是,我在编译时不知道要发送消息的主机的级别。 很自然地,我写的内容如下: MPI_Send(&myIntData, 1, MPI_INT,
我可以在单个 MPI_SEND 中发送一个矩阵的行和另一个矩阵的列,我该如何执行此过程? MPI_SEND (row and column of the matrix ...) 最佳答案 由于 C/C
我有以下代码: double * myX; double * myY; double * myZ; int amount; int count; // number of process v
我正在编写 mpi 的 C++ 包装器。 我在 mpi 遇到了一个奇怪的错误:在我的例子中,错误只在消息足够大时出现,运行时错误如下: Fatal error in MPI_Send: Other M
如果我想定义自己的类型,并将其用作 MPI_Send 的数据类型以仅从矩阵中获取偶数行,是否必须静态分配该矩阵(发送缓冲区)? 我动态分配的时候好像有问题。这是因为地址需要连续才能发送数据吗? 最佳答
我正在使用 MPI 编写 Mergesort 来对整数数组进行排序。这个想法是在同一等级上对数组的左半部分进行归并排序,同时将数组的右半部分发送到子等级。所以如果有四个过程,它看起来像这样:
我必须在我的程序中使用 MPI API 发送/接收矩阵。为了发送矩阵,我使用了以下语法: MPI_Send(matrix, ...) <- USE THIS MPI_Send(&matrix, ..
在大量内核上调试我的程序时,我遇到了非常奇怪的虚拟内存不足错误。我的调查导致代码和平,主人向每个奴隶发送小消息。然后我写了一个小程序,其中 1 个主机使用 MPI_SEND 发送 10 个整数,所有从
这是我在 stackoverflow 中的第一个问题。我有两个进程,一个根 0 和一个从属 1。从属分配一个二维数组 (CHUNK_ROWS+2,CHUNK_COLUMNS+2) 并想发送一个 [CH
我正在尝试使用 MPI 形成环形通信,其中我的每个进程都将其结果发送到下一个进程,最后一个进程将结果发送到第 0 个进程。假设我有 4 个进程,那么我的第 0 个进程会将结果发送到第 1 个、第 1
我得到了一个小练习,我必须通过使用 MPI 来估计 n 个球体的总体积来实现蒙特卡罗算法,这些球体的中心坐标和半径在 3 维中。即使我们必须使用 MPI,我们也可以在本地机器上启动所有进程,因此没有网
当我使用超过 1 个处理器执行程序时,程序将停止工作。它在第一个 MPI_Send 处停止我做错了什么? #include "mpi.h" #include #include #include
我有一个主进程和更多从进程。我希望每个从进程向主进程发送一个整数,所以我想我应该使用 MPI_Gather 收集它们。但不知怎的,它不起作用,我开始认为 MPI_Gather 与 MPI_Send 不
我正在尝试将多列“B”矩阵从处理器 0 发送到不同的处理器。我正在尝试使用 MPI_Send 进行发送,但它不起作用。有人可以帮助我吗? 例如:方阵 B 的大小为 7。这样就应该被分发了。 处理器 0
最近才知道MPI_Send不能一次发送太长的数据,所以决定把数据分成几 block ,用for循环发送。下面是一个测试用例。这里的问题是,如果我使用少量数据并将其分成几 block ,程序将运行;但是
我正在尝试使用 MPI 在 C++ 中处理一些动态分配的多维数组。为了避免担心不连续的内存,我编写了一个类包装器,它允许我像访问二维数组一样访问一维数组。我正在尝试创建一个 MPI 数据类型以通过 M
这可能是一件微不足道的事情,但是: 底层数组的大小是否可以长于在 MPI_Send( ... ) 调用中与缓冲区指针一起发送的计数参数? 至于 MPI_Recv( ... ),我发现消息来源清楚地表明
我正在尝试运行下面使用并行编程的程序。如果我们使用 4 个处理器,我希望它们包含总和 1+2=3、3+4=7、11 和 15。所以我希望求和 vector 按顺序包含 3、7、11 和 15。但是,由
我正在学习 MPI_Send,但我对这种方法感到困惑。我写了一个简单的乒乓程序,rank-0 节点发送消息给 rank-1 节点,然后后者返回消息给前一个。 if (rank == 0) { /*
我是一名优秀的程序员,十分优秀!