0_Simple__MultiGPU
使用多台 GPU 进行计算
▶ 源代码。使用不同的流来控制不同 GPU 上的运算任务。
#include <stdio.h>
#include <timer.h>
#include <cuda_runtime.h>
#include "device_launch_parameters.h"
#include <helper_functions.h>
#include <helper_cuda.h>
#include "simpleMultiGPU.h" const int MAX_GPU_COUNT = ;
const int DATA_N = * ; __global__ static void reduceKernel(float *d_Result, float *d_Input, int N)
{
const int tid = blockIdx.x * blockDim.x + threadIdx.x;
const int threadN = gridDim.x * blockDim.x;
float sum = ; for (int pos = tid; pos < N; pos += threadN)
sum += d_Input[pos]; d_Result[tid] = sum;
} int main(int argc, char **argv)
{
printf("\n\tStart.\n"); const int BLOCK_N = , THREAD_N = ;
const int ACCUM_N = BLOCK_N * THREAD_N;
int i, j, GPU_N;
float sumGPU;
TGPUplan plan[MAX_GPU_COUNT]; cudaGetDeviceCount(&GPU_N);
GPU_N = MIN(GPU_N, MAX_GPU_COUNT);
printf("\n\tDevice count: %i\n", GPU_N); // 准备计算数据
for (i = ; i < GPU_N; i++)
plan[i].dataN = DATA_N / GPU_N; // 计算数据量与设备数量没有对齐的部分
for (i = ; i < DATA_N % GPU_N; i++)
plan[i].dataN++; // 申请内存,初始化 h_data
for (i = ; i < GPU_N; i++)
{
cudaSetDevice(i);
cudaStreamCreate(&plan[i].stream);
cudaMalloc((void **)&plan[i].d_data, plan[i].dataN * sizeof(float));
cudaMalloc((void **)&plan[i].d_sum, ACCUM_N * sizeof(float));
cudaMallocHost((void **)&plan[i].h_sum_from_device, ACCUM_N * sizeof(float));
cudaMallocHost((void **)&plan[i].h_data, plan[i].dataN * sizeof(float)); for (j = ; j < plan[i].dataN; j++)
plan[i].h_data[j] = (float)rand() / (float)RAND_MAX;
} StartTimer();// 计时 // 调用各 GPU 进行计算,plan[i].d_data -> plan[i].d_sum -> plan[i].h_sum_from_device
for (i = ; i < GPU_N; i++)
{
cudaSetDevice(i);
cudaMemcpyAsync(plan[i].d_data, plan[i].h_data, plan[i].dataN * sizeof(float), cudaMemcpyHostToDevice, plan[i].stream);
reduceKernel<<<BLOCK_N, THREAD_N, , plan[i].stream>>>(plan[i].d_sum, plan[i].d_data, plan[i].dataN);
cudaMemcpyAsync(plan[i].h_sum_from_device, plan[i].d_sum, ACCUM_N *sizeof(float), cudaMemcpyDeviceToHost, plan[i].stream);
} // 处理 GPU 计算结果,plan[i].h_sum_from_device -> plan[i].h_sum -> sumGPU
for (i = ; i < GPU_N; i++)
{
cudaSetDevice(i);
cudaStreamSynchronize(plan[i].stream); for (j = , plan[i].h_sum = 0.0f; j < ACCUM_N; j++)
plan[i].h_sum += plan[i].h_sum_from_device[j];
}
for (i = , sumGPU = 0.0f; i < GPU_N; i++)// CPU 最后规约
sumGPU += plan[i].h_sum;
printf("\n\tGPU Processing time: %f (ms)\n", GetTimer()); // 使用 CPU 计算,plan[i].h_data -> sumCPU
double sumCPU = ;
for (i = ; i < GPU_N; i++)
{
for (j = ; j < plan[i].dataN; j++)
sumCPU += plan[i].h_data[j];
} // 检查结果
double diff = fabs(sumCPU - sumGPU) / fabs(sumCPU);
printf("\n\tGPU sum: %f\n\tCPU sum: %f\n", sumGPU, sumCPU);
printf("\n\tRelative difference: %E, %s\n", diff, (diff < 1e-) ? "Passed" : "Failed"); //回收工作
for (i = ; i < GPU_N; i++)
{
cudaSetDevice(i);
cudaFreeHost(plan[i].h_data);
cudaFreeHost(plan[i].h_sum_from_device);
cudaFree(plan[i].d_sum);
cudaFree(plan[i].d_data);
cudaStreamDestroy(plan[i].stream);
} getchar();
return ;
}
▶ 输出结果
Start.
Device count:
GPU Processing time: 13.726471 (ms)
GPU sum: 16779778.000000
CPU sum: 16779776.312309
Relative difference: 1.005789E-07, Passed
▶ 涨姿势
● 在使用不同的设备执行相关函数(包括 cudaFree 等主机函数)时要注意,使用函数 cudaSetDevice() 来切换设备。
0_Simple__MultiGPU的更多相关文章
随机推荐
- js三级联动
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- Codeup1085: 阶乘的和
题目描述 有些数可以表示成若干个不同阶乘的和.例如,9=1!+2!+3!.小明对这些数很感兴趣,所以他给你一个正整数n,想让你告诉他这个数是否可以表示成若干个不同阶乘的和. 输入 输入包含多组测试数据 ...
- CTF之LSB信息隐藏术
LSB也就是最低有效位,原理是图片中的像素一般是由三种颜色构成,即三原色(绿红蓝),由这三种颜色可以组成其它各种颜色. 例如在PNG图片的储存中,每个颜色会有8bit,LSB隐写就是修改了像素中的最低 ...
- python open和file的区别
opne和file都是用来对文件的操作 open:内置函数,使用方式是open('file_name', mode, buffering),返回值是一个file对象,以写模式打开文件如果不存在会被创建 ...
- DOS命令下使用sqlite3 命令中文乱码的解决办法
windows cmd窗口无法显示中文,不一定数据库中存储的就是乱码——多数情况只是显示问题,可以通过以下方式解决: 1.退出dos 或者重新开启在CMD窗口,输下:chcp 65001 然后回车确定 ...
- dgraph cluster docker-compose 安装
dgraph 是一款基于golang 的图数据库,使用了graphql+ 的查询方式 集群的安装官方也提供了对应的模版,比较简单 docker-compose 文件 我做了一些简单修改(数据存储的问题 ...
- Where is Silverlight now?
Some time ago, I wrote an article about the comparison between HTML5 and Silverlight. That article w ...
- 高大上的JS工具
EtherPad (协同文件编辑): EtherCalc (协同电子表格编辑)
- python 函数参数的传递(参数带星号的说明) 元组传递 字典传递
python中函数参数的传递是通过赋值来传递的.函数参数的使用又有俩个方面值得注意:1.函数参数是如何定义的 2.在调用函数的过程中参数是如何被解析 先看第一个问题,在python中函数参数的定义主要 ...
- linux SSH各配置项解释
Linux下SSH各配置项解释 关于ssh 设置的相关总结(ssh最大连接数.ssh连接时长.安全性配置等)以redhat6.3为例 ssh配置文件在: /etc/ssh/sshd_config可以打 ...