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的更多相关文章
随机推荐
- codeforces1111 简单题【DE】简要题解
D 很显然可以用一个背包算出来凑齐i个位置的方案 然后总的答案就是\(dp_{n / 2}\) 然后需要扣掉不符合条件的就是把选出来的数的贡献剪掉的贡献 然后注意因为是多重集合的排列,所以需要乘上\( ...
- 注解JAVA对象(基于Hibernate4.3)
package com.chauvet.po; import java.util.Date; import javax.persistence.Column; import javax.persist ...
- Battle City 优先队列+bfs
Many of us had played the game "Battle city" in our childhood, and some people (like me) e ...
- CTF-练习平台-Misc之 猜?
六.猜? 打开图片后发现是一个半个脸被遮住的美女,再联系到题目是“猜”,答案又是一个人的名字全拼,所以熟悉的人都知道这是刘亦菲,把拼音输进去就可以啦.
- 《DSP using MATLAB》Problem 3.21
模拟信号经过不同的采样率进行采样后,得到不同的数字角频率,如下: 三种Fs,采样后的信号的谱 重建模拟信号,这里只显示由第1种Fs=0.01采样后序列进行重建,采用zoh.foh和spline三种方法 ...
- ajax完整请求
@RequestMapping(value = "/quotaPage") // , method = RequestMethod.GET名额分配@ResponseBody //注 ...
- Boosting学习笔记(Adboost、GBDT、Xgboost)
转载请注明出处:http://www.cnblogs.com/willnote/p/6801496.html 前言 本文为学习boosting时整理的笔记,全文主要包括以下几个部分: 对集成学习进行了 ...
- day35 python学习GIL解释器锁
二 GIL介绍 GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全. 可以肯定的一点是:保护不同 ...
- TensorFlow笔记-01-开篇概述
人工智能实践:TensorFlow笔记-01-开篇概述 从今天开始,从零开始学习TensorFlow,有相同兴趣的同志,可以互相学习笔记,本篇是开篇介绍 Tensorflow,已经人工智能领域的一些名 ...
- php脚本输出js代码不执行的解决办法和原理。
<?phpecho "<script>alert('我弹出来了')</script>";?> 很简单你一句话就可以在PHP里面输出JS脚本让浏览 ...