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 部分没有新的认识。

最新文章

  1. 安装linxu6.4
  2. 【原创】JAVA并发编程——Callable和Future源码初探
  3. Python之路【第七篇】:初识Socket
  4. c# 基础部分 (基本数据类型-- 表达式)
  5. Freemarker中遍历List以及内置函数使用
  6. 《C++ Primer 4th》读书笔记 第3章-标准库类型
  7. Python3 内建模块 datetime/collections/base64/struct
  8. 多线程下的NSOperation和NSOperationQueue的使用
  9. Tuna项目总结
  10. hdu 4772
  11. 最流行的android组件大全
  12. 二、Cocos2dx中Android部分的c++和java实现相互调用(高级篇)
  13. C++ 多态性分析
  14. NOI 评价体系 arbiter 安装方法 常见的问题 移植
  15. express框架+jade+bootstrap+mysql开发用户注册登录项目
  16. 记录参加QCon2017北京站的心得
  17. vue.js 初级之一
  18. Toaster
  19. NSIS安装程序制作工具判断系统是否安装.NET
  20. Java中由Calendar类获取的月、天和小时的简单处理

热门文章

  1. Mybatis中parameterType、resultMap、statementType等等配置详解(标签中基本配置详解)
  2. ASP.NET 4.0尚未在 Web 服务器上注册
  3. 51Nod1526 分配笔名
  4. 来自官方的一些dbt 最佳实践
  5. #define WIN32_LEAN_AND_MEAN 的作用
  6. QT内使用OpenCV
  7. 详解SID之终结篇
  8. 实现多线程的方式之实现Callable接口
  9. php 使用 file_exists 还是 is_file
  10. 一个最简的Thinkphp3.2 操作Mongodb的例子