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的更多相关文章
随机推荐
- 转:三种状态对象的使用及区别(Application,Session,Cookie)
Application状态对象 Application 对象是HttpApplication 类的实例,将在客户端第一期从某个特定的ASP.NET应用程序虚拟目录中请求任何URL 资源时创建.对于We ...
- 【java编程】正确重写hashCode和equesl方案
一. 正确书写hashCode的办法: [原则]按照equals( )中比较两个对象是否一致的条件用到的属性来重写hashCode(). {1}. 常用的办法就是利用涉及到的的属性进行线性组合. {2 ...
- 【spring源码分析】spring AspectJ的Execution表达式
在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点" 例如定义切入点表达式 execution (* com.sam ...
- 获取的时候报cannot find package "golang.org /x/net/context",编译也报错误
gitclone 这个https://github.com/golang/net.git ,编译通过了. 创建了相应的golang.org/x/ 路径, 然后将克隆的目录 放回golang.org/ ...
- leetcode:Reverse Words in a String【Python版】
class Solution: # @param s, a string # @return a string def reverseWords(self, s): ss = s.split(&quo ...
- citus real-time 分析demo( 来自官方文档)
citus 对于多租户以及实时应用的开发都是比较好的,官方也提供了demo 参考项目 https://github.com/rongfengliang/citus-hasuar-graphql 环 ...
- smarty学习——编写扩展
在进行了以上的开发环境的配置之后就是,进行进一步的学习,为了开发的方便我们一般会使用oop的编程思想,进行方便的处理 如下: 1.smartyUser 的创建 <?php require_onc ...
- java打jar包的几种方式详解
经常会头疼于一个jar包是如何制作的,包括maven的打包方式,springboot的打jar包的原理,jar包稍稍有错误就会完全无法运行.在网上折腾了很久终于有些思路和步骤,在这里做个笔记 本文目录 ...
- centos7 添加用户并授权root权限
centos7.2 版本,我们不可能每次都用root账号登陆,root账号公认的不安全,所以,首先,禁止掉root账号的登陆.1.静止root账号登陆. $ vi /etc/ssh/sshd.conf ...
- 嵌入式Linux软件工程师面试题一
题一,同步和异步有啥区别? 题二,TCP与UDP有啥区别? 题三,进程和线程有啥区别? 题一答案: 同步(Sync):所有的操作都做完,才返回给用户.这样用户在线等待的时间太长,给用户一种卡死了的感觉 ...