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的更多相关文章
随机推荐
- Visual Studio Code 使用指南
安装 VSCode是微软推出的一款轻量编辑器,采取了和VS相同的UI界面,搭配合适的插件可以优化前端开发的体验. HTML Snippets:增强了zen-coding,增加了H5的自动补全,安 ...
- HDU 3068 最长回文 manacher 算法,基本上是O(n)复杂度
下面有别人的比较详细的解题报告: http://wenku.baidu.com/view/3031d2d3360cba1aa811da42.html 下面贴我的代码,注释在代码中: #include ...
- 实验吧—密码学——WP之 传统知识+古典密码
仔细读题,发现有价值的信息: 几个不同的年份:“+甲子”:key值结构 首先我们并不知道这些年份在这里代表着什么,那么我们就去百度一下发现了如下所示的六十甲子顺序表 而在表中每个年份前都有数字,将他们 ...
- (dfs痕迹清理兄弟篇)bfs作用效果的后效性
dfs通过递归将每种情景分割在不同的时空,但需要对每种情况对后续时空造成的痕迹进行清理(这是对全局变量而言的,对形式变量不需要清理(因为已经被分割在不同时空)) bfs由于不是利用递归则不能分割不同的 ...
- JNI学习笔记_C调用Java
一.笔记 1.C调用Java中的方法,参考jni.pdf pg97可以参考博文:http://blog.csdn.net/lhzjj/article/details/26470999步骤: a. 创建 ...
- 详解SID之终结篇
今天测试某款监控软件时遇到一个比较棘手的问题,这款软件需要在被监控端安装客户端程序.成功在第一个节点安装好客户端后问题出现了,在其他节点安装时报错无法安装.软件报的错误信息无从下手且系统日志也看不出什 ...
- 先进驾驶员辅助系统ADSA
ADSA(Advanced Driver-Assistance Systems)字面翻译过来是“先进驾驶员辅助系统”,实际上它是一种“辅助驾驶员更便捷更安全使用汽车”的系统. ADAS的研发历史可以追 ...
- 织梦ask标签的调用
EDE 问答首页调用标签 标签名称: ask 功能说明:问答调用标签 适用范围:全局使用 基本语法: {dede:ask row='6' qtype='new' tid='0' titlelen='2 ...
- 关于 ake sure class name exists, is public, and has an empty constructor that is public
解决方法:自定义的fragment最好有一个Public的参数为空的构造函数,若需要传入一个参数,可以使用下面的方法 public FileViewFragment(){ } public stati ...
- PREV-1_蓝桥杯_核桃的数量
问题描述 小张是软件项目经理,他带领3个开发组.工期紧,今天都在加班呢.为鼓舞士气,小张打算给每个组发一袋核桃(据传言能补脑).他的要求是: 1. 各组的核桃数量必须相同 2. 各组内必须能平分核桃( ...