0_Simple__simpleMPI
MPI 的简单使用
▶ 源代码。主机根结点生成随机数组,发布副本到各结点(例子用孩子使用了一个结点),分别使用 GPU 求平方根并求和,然后根结点使用 MPI 回收各节点的计算结果,规约求和后除以数组大小(相当于球随机数组中所有元素的平方根的平均值)。
// simpleMPI.h
extern "C"
{
void initData(float *data, int dataSize);
void computeGPU(float *hostData, int blockSize, int gridSize);
float sum(float *data, int size);
void my_abort(int err);
}
// simpleMPI.cu
#include <iostream>
#include <mpi.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "simpleMPI.h" using std::cout;
using std::cerr;
using std::endl; #define CUDA_CHECK(call) \
if((call) != cudaSuccess) \
{ \
cudaError_t err = cudaGetLastError(); \
cerr << "CUDA error calling \""#call"\", code is " << err << endl; \
my_abort(err); \
} // GPU 计算平方根
__global__ void simpleMPIKernel(float *input, float *output)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
output[tid] = sqrt(input[tid]);
} // 初始化数组
void initData(float *data, int dataSize)
{
for (int i = ; i < dataSize; i++)
data[i] = (float)rand() / RAND_MAX;
} // 使用 GPU 进行计算的函数
void computeGPU(float *hostData, int blockSize, int gridSize)
{
int dataSize = blockSize * gridSize; float *deviceInputData = NULL;
CUDA_CHECK(cudaMalloc((void **)&deviceInputData, dataSize * sizeof(float))); float *deviceOutputData = NULL;
CUDA_CHECK(cudaMalloc((void **)&deviceOutputData, dataSize * sizeof(float))); CUDA_CHECK(cudaMemcpy(deviceInputData, hostData, dataSize * sizeof(float), cudaMemcpyHostToDevice)); simpleMPIKernel<<<gridSize, blockSize>>>(deviceInputData, deviceOutputData); CUDA_CHECK(cudaMemcpy(hostData, deviceOutputData, dataSize *sizeof(float), cudaMemcpyDeviceToHost)); CUDA_CHECK(cudaFree(deviceInputData));
CUDA_CHECK(cudaFree(deviceOutputData));
} // 简单的求和函数
float sum(float *data, int size)
{
float accum = .f;
for (int i = ; i < size; i++)
accum += data[i];
return accum;
} // 中止函数
void my_abort(int err)
{
cout << "Test FAILED\n";
MPI_Abort(MPI_COMM_WORLD, err);
}
// simpleMPI.cpp
#include <mpi.h>
#include <iostream>
#include "simpleMPI.h" using std::cout;
using std::cerr;
using std::endl; #define MPI_CHECK(call) if((call) != MPI_SUCCESS) { cerr << "MPI error calling \""#call"\"\n"; my_abort(-1); } int main(int argc, char *argv[])
{
int blockSize = ;
int gridSize = ;
int dataSizePerNode = gridSize * blockSize; // 初始化 MPI
MPI_CHECK(MPI_Init(&argc, &argv)); // 获取节点尺寸和编号
int commSize, commRank;
MPI_CHECK(MPI_Comm_size(MPI_COMM_WORLD, &commSize));
MPI_CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &commRank)); // 根结点生成随机数组
int dataSizeTotal = dataSizePerNode * commSize;
float *dataRoot = NULL;
if (commRank == )
{
cout << "Running on " << commSize << " nodes" << endl;
dataRoot = new float[dataSizeTotal];
initData(dataRoot, dataSizeTotal);
} // 每个结点上申请数组用于接收根结点发来的数据
float *dataNode = new float[dataSizePerNode]; MPI_CHECK(MPI_Scatter(dataRoot, dataSizePerNode, MPI_FLOAT, dataNode, dataSizePerNode, MPI_FLOAT, , MPI_COMM_WORLD)); // 清空根节点数据
if (commRank == )
delete [] dataRoot; // 每个结点调用 GPU 计算平方根,然后规约到一个值
computeGPU(dataNode, blockSize, gridSize);
float sumNode = sum(dataNode, dataSizePerNode); // 使用 MPI 接收每个结点的计算结果并进行规约
float sumRoot;
MPI_CHECK(MPI_Reduce(&sumNode, &sumRoot, , MPI_FLOAT, MPI_SUM, , MPI_COMM_WORLD)); // 回收和输出工作
delete[] dataNode;
MPI_CHECK(MPI_Finalize()); if (commRank == )
{
float average = sumRoot / dataSizeTotal;
cout << "Average of square roots is: " << average << endl;
cout << "PASSED\n";
} getchar();
return ;
}
▶ 输出结果
Running on nodes
Average of square roots is: 0.667507
PASSED
▶ 涨姿势
● 集中在 MPI 的几何函数的使用上,CUDA 部分没有新的认识。
0_Simple__simpleMPI的更多相关文章
随机推荐
- linux搜索命令之find和grep
在使用linux时,经常需要进行文件查找,其中查找的命令主要有find和grep.两个命令是有区的. 区别:(1)find命令是根据文件的属性进行查找,如文件名,文件大小,所有者,所属组,是否为空,访 ...
- makefile,让编译更简单
陈皓 (CSDN) 概述—— 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的 ...
- sprintf拼接字符串的问题
] = {}; char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', ...
- RAW+ASM 的RAC 安装文档
实验平台:Oracle 10gR2 RAC + RHEL 4.0 +VMWare GSX 3.2.0 安装步骤: 1.安装前准备及OS安装配置 2.安装Oracle 10gR2 clusterware ...
- Angular 4 路由守卫
路由守卫 只有当用户已经登录并拥有某些权限时才能进入某些路由 一个有多个表单组成的向导,如注册流程,用户只有在当前组件的组件中填写了满足要求的信息才可以导航到下一个路由 当用户未执行保存操作而试图离开 ...
- Angular 4 父组件调用子组件中的方法
1. 创建工程 ng new demo3 2. 创建子组件 ng g component child 3. 在子组件中定义方法greeting 4. 父组件html(第三行是模板中调用子组件的方法) ...
- Linux下Oracle中SqlPlus时上下左右键乱码问题的解决办法
window下的sqlplus可以通过箭头键,来回看历史命令,用起来非常的方便. 但是在Linux下,会出现各种乱码,非常不方便,如下图所示,每次打错一个字符就需要重新打一遍. 解决办法:rlwrap ...
- 在VS2008中加入ExtJS智能提示
在VS2008中加入ExtJS智能提示 在VS2008中加入ExtJS智能提示—>(方法一) 关于如何在VS2008中加入ExtJS的智能提示的方法,我这里有2种方法,相对于第二种方法,第一 ...
- 关于Jquery 插件开发,写的很清楚了。。。
转自:http://blog.jobbole.com/30550/ 本文由 伯乐在线 - 戴嘉华 翻译.未经许可,禁止转载!英文出处:Extraordinarythoughts.欢迎加入翻译小组. 如 ...
- 【EasyUI学习-2】Easyui Tree的异步加载
作者:ssslinppp 1. 摘要 2. tree的相关介绍 3. 异步加载tree数据,并实现tree的折叠展开 3.1 功能说明: 3.2 前台代码 3.3 后台代码 4. 其他 1 ...