使用多台 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. 如何在Struts2的拦截器中调用Spring容器

    第一种: 通常用ApplicationContext来调用Spring配置文件中的一些Bean,所以首先创建Spring上下文容器. ApplicationContext ac = (Applicat ...

  2. FabricExpress.net supply high quality quilting fabric

    FabricExpress is a company specializing in high quality custom t-shirts,custom fabric,senior handmad ...

  3. LG1955 [NOI2015]程序自动分析

    题意 题目描述 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3...代表程序中出现的变量,给定n个形如xi=xj或xi≠x ...

  4. php过滤html标签截取部分内容

    <?php $str = '<span>fdsfsdf</span><a href="#">href</a>'; echo h ...

  5. Linux高级文本处理命令

    cut 一.cut命令 功能:cut命令可以从一个文本文件/文本流中提取文本列 语法: cut -d '分割字符' -f fields ##用于有特定分割字符 cut -c 字符区间 ##用于排列整齐 ...

  6. js object对象赋值bug和对象复制clone方法

    最近在写程序的时候发现,如果新建一个object对象objb,初始化值为obja,如果改变了objb对象的字段值,那么obja也会随之改变,看来对象赋值传递的是一个引用. 代码重现: <scri ...

  7. Selenium2+python自动化40-cookie相关操作

    前言 虽然cookie相关操作在平常ui自动化中用得少,偶尔也会用到,比如登录有图形验证码,可以通过绕过验证码方式,添加cookie方法登录. 登录后换账号登录时候,也可作为后置条件去删除cookie ...

  8. Spring Boot 整合 FastDFS 客户端

    原文地址:Spring Boot 整合 FastDFS 客户端 博客地址:http://www.extlight.com 一.前言 前两篇介绍整体上介绍了通过 Nginx 和 FastDFS 的整合来 ...

  9. win xp 关闭动画屏幕角色,那只小狗

    这个动画屏幕角色每次会占用两秒左右的时间. 在搜索选项中打开"改变首选项(G)" -选择 “不使用动画屏幕角色(S)”. - -

  10. css 填坑常用代码分享[居家实用型]

    原文地址 http://www.cnblogs.com/jikey/p/4233003.html 以下是常用的代码收集,没有任何技术含量,只是填坑的积累.转载请注明出处,谢谢. 一. css 2.x ...