使用多台 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的更多相关文章

随机推荐

  1. HDU 4548:美素数

    Problem Description 小明对数的研究比较热爱,一谈到数,脑子里就涌现出好多数的问题,今天,小明想考考你对素数的认识. 问题是这样的:一个十进制数,如果是素数,而且它的各位数字和也是素 ...

  2. PAT天梯:L1-019. 谁先倒

    L1-019. 谁先倒 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 划拳是古老中国酒文化的一个有趣的组成部分.酒桌上两人划拳 ...

  3. HDU 2009

    求数列的和 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submiss ...

  4. js操作cookie总结 及乱码

    涉及到cookie的 setPath问题: https://blog.csdn.net/damys/article/details/49737905 cookie注解:public voic getx ...

  5. 虚拟机CentOS的NAT模式联网和SecureCRT远程登录管理工具

    Cenos7 发生了很大的变化,不过也是直接配置网络,从启网卡,从启机器,crt链接 https://blog.csdn.net/gebitan505/article/details/54584213 ...

  6. DataFrame 列运算

    import pandas as pd import StringIO table_buffer = StringIO.StringIO('''a b 2007-01-08 0.786667 270 ...

  7. Vue2.x directive自定义指令

    directive自定义指令 除了默认设置的核心指令( v-model 和 v-show ),Vue 也允许注册自定义指令. 注意,在 Vue2.0 里面,代码复用的主要形式和抽象是组件——然而,有的 ...

  8. sql 变量赋值

    mysql 的变量赋值如下: set @name='app' ; or set @name:='appfirst'; or with select select @appname:='you name ...

  9. 【VB.NET】——若水归海

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/successA/article/details/34496209 看完台湾微软特约资深讲师的VB.N ...

  10. VPC/VM/VBOX安装GHOST版的无法启动系统

    本人最近在安装一些公司的虚拟机,方便开发使用,不用每次都安装几个小时的装机和安装软件,但是本次却遇到了一点问题,虚拟机安装完成后一直无法进入系统,只有一个光标在黑色的屏幕上一闪一闪的,也没有任何错误提 ...