CUDA性能优化----线程配置

2017-01-12 14:19:29|  分类: HPC&CUDA优化 |  标签:cuda  gpu  hpc   |举报 |字号 订阅

下载LOFTER 我的照片书  |

前言:

CUDA线程的组织形式(block的维度配置)对程序的性能影响是至关重要的。

线程索引:
矩阵在memory中是row-major线性存储的:

在kernel里,线程的唯一索引非常有用,为了确定一个线程的索引,需要(以2D为例):

  • 线程和block索引
  • 矩阵中元素坐标
  • 线性global memory 的偏移
首先可以将thread和block索引映射到矩阵坐标:
ix = threadIdx.x + blockIdx.x * blockDim.x
iy = threadIdx.y + blockIdx.y * blockDim.y
之后可以利用上述变量计算线性地址:
idx = iy * nx + ix

上图展示了block和thread索引,矩阵坐标以及线性地址之间的关系,谨记,相邻的thread拥有连续的threadIdx.x,也就是索引为(0,0)(1,0)(2,0)(3,0)...的thread连续,而不是(0,0)(0,1)(0,2)(0,3)...连续,跟我们线性代数里玩矩阵的时候不一样。

下面我们以2D矩阵相加为例,来测试CUDA线程配置( block的大小和数量 )对程序性能的影响,,这里以2D grid和2D block为例。
测试环境:Tesla M2070一块,CUDA 6.0,
操作系统:Red Hat 4.1.2-50,gcc version 4.1.2 20080704

测试代码:
//Threads assign test
#include <cuda_runtime.h>
#include <stdio.h>
#include <math.h>
#include <time.h>#define PRECISION 1e-5
#define HANDLE_ERROR(err) (HandleError( err, __FILE__, __LINE__ ))static void HandleError( cudaError_t err,const char *file,int line )
{    if (err != cudaSuccess)
    {        printf( "%s in %s at line %d\n", cudaGetErrorString( err ),
            file, line );
        exit( EXIT_FAILURE );
    }
}__global__ void sumMatrix2DKernel(float *d_MatA,float *d_MatB,float *d_MatC,int nx,int ny)
{    int idx = threadIdx.x + blockDim.x * blockIdx.x;
    int idy = threadIdx.y + blockDim.y * blockIdx.y;
    int tid = nx*idy + idx;   if(idx < nx && idy < ny)
        d_MatC[tid] = d_MatA[tid] + d_MatB[tid];
}void sumMatrix2DOnHost (float *h_A,float *h_B,float *hostRef,int nx,int ny)
{    for(int i=0; i< nx*ny; i++)
        hostRef[i] = h_A[i] + h_B[i];
}int main(int argc, char **argv)
{    printf("%s Program Starting...\n",argv[0]);
    // set up device
    int devID = 0;
    cudaDeviceProp deviceProp;
    HANDLE_ERROR(cudaGetDeviceProperties(&deviceProp, devID));
    printf("Using Device %d: %s\n", devID, deviceProp.name);
    HANDLE_ERROR(cudaSetDevice(devID)); // set up date size of matrix
    int nx = 1<<14;
    int ny = 1<<14;
    int nxy = nx*ny;
    int nBytes = nxy * sizeof(float);
    printf("Matrix size: nx= %d, ny= %d\n",nx, ny); // malloc host memory
    float *h_A, *h_B, *hostRef, *gpuRef;
    h_A = (float *)malloc(nBytes);
    h_B = (float *)malloc(nBytes);
    hostRef = (float *)malloc(nBytes);
    gpuRef = (float *)malloc(nBytes);  // initialize data at host side
    clock_t iStart,iEnd;
    iStart = clock();
    for(int i=0;i<nxy;i++)
    {        h_A[i] = rand()/(float)RAND_MAX;
        h_B[i] = rand()/(float)RAND_MAX;
    }

    iEnd = clock();
    double iElaps = (double)(iEnd-iStart)/CLOCKS_PER_SEC;
    memset(hostRef, 0, nBytes);
    memset(gpuRef, 0, nBytes);  // add matrix at host side for result checks
    iStart = clock();
    sumMatrix2DOnHost(h_A, h_B, hostRef, nx,ny);
    iEnd = clock();
    iElaps = (double)(iEnd-iStart)/CLOCKS_PER_SEC;
    printf("--sumMatrix2DOnHost() elapsed %f sec..\n", iElaps);   // malloc device global memory
    float *d_MatA, *d_MatB, *d_MatC;
    cudaMalloc((void **)&d_MatA, nBytes);
    cudaMalloc((void **)&d_MatB, nBytes);
    cudaMalloc((void **)&d_MatC, nBytes);   // transfer data from host to device
    cudaMemcpy(d_MatA, h_A, nBytes, cudaMemcpyHostToDevice);
    cudaMemcpy(d_MatB, h_B, nBytes, cudaMemcpyHostToDevice);///
    // invoke kernel at host side
    int dimx = 32;
    int dimy = 32;
    //int dimy = 16;
    dim3 block(dimx, dimy);
    dim3 grid((nx+block.x-1)/block.x, (ny+block.y-1)/block.y);
    iStart = clock();
    sumMatrix2DKernel <<< grid, block >>>(d_MatA, d_MatB, d_MatC, nx, ny);
    cudaDeviceSynchronize();
    iEnd = clock();
    iElaps = (double)(iEnd-iStart)/CLOCKS_PER_SEC;
    printf("--sumMatrix2DOnGPU<<<(%d,%d),(%d,%d)>>> elapsed %f sec..\n", grid.x,
        grid.y, block.x, block.y, iElaps);
/// // copy kernel result back to host side
    cudaMemcpy(gpuRef, d_MatC, nBytes, cudaMemcpyDeviceToHost); // check device results
    for(int i=0; i< nxy; i++)
    {        if(fabs(gpuRef[i]-hostRef[i]) > PRECISION)
        {            fprintf(stderr,"Result verification failed at elemnt %d\n", i);
            exit(EXIT_FAILURE);
        }
    }   // free device global memory
    cudaFree(d_MatA);
    cudaFree(d_MatB);
    cudaFree(d_MatC);   // free host memory
    free(h_A);
    free(h_B);
    free(hostRef);
    free(gpuRef);   // reset device
    cudaDeviceReset();  printf("Test Passed..\n");
    return 0;
}

编译运行:

$ nvcc -arch=sm_20 sumMatrix2D.cu -o sumMatrix2D
$ ./sumMatrix2D

程序输出:
./sumMatrix2D Program Starting...
Using Device 0: Tesla M2070
Matrix size: nx= 16384, ny= 16384
--sumMatrix2DOnHost() elapsed 1.410000 sec..
--sumMatrix2DOnGPU<<<(512,1024),(32,32)>>> elapsed 0.070000 sec..
Test Passed..

现在我们将block的大小改成(32, 16),此时block数量为512*1024,再次编译运行,会发现:

./sumMatrix2D Program Starting...
Using Device 0: Tesla M2070
Matrix size: nx= 16384, ny= 16384
--sumMatrix2DOnHost() elapsed 1.410000 sec..
--sumMatrix2DOnGPU<<<(512,1024),(32,16)>>> elapsed 0.040000 sec..
Test Passed..

可以看到,程序性能提升了将近1倍,直观来看是第二次线程配置比第一次配置block的数量增加了1倍,实际上也正是由于block数量增加了的缘故。但是如果继续增加block的数量,性能反而又会下降。

现在我们将block的大小改为(16,16),此时block数量为1024*1024,再次编译运行,会发现:
./sumMatrix2D Program Starting...
Using Device 0: Tesla M2070
Matrix size: nx= 16384, ny= 16384
--sumMatrix2DOnHost() elapsed 1.400000 sec..
--sumMatrix2DOnGPU<<<(1024,1024),(16,16)>>> elapsed 0.050000 sec..
Test Passed..

关于线程块配置的性能分析参考后续章节。

CUDA性能优化----线程配置相关推荐

  1. c语言 cuda核函数,CUDA核函数与线程配置

    CUDA核函数 在GPU上调用的函数成为CUDA核函数(Kernel function),核函数会被GPU上的多个线程执行.每个线程都会执行核函数里的代码,当然由于线程编号的不同,执行的代码路径可能会 ...

  2. Ceph性能优化 之 配置参数调优

    该文同时发表在盛大游戏G云微信公众号,粘贴于此,方便各位查阅 Ceph,相信很多IT朋友都听过.因为搭上了Openstack的顺风车,Ceph火了,而且越来越火.然而要用好Ceph却也不是件易事,在Q ...

  3. CUDA性能优化系列——Kmeans算法调优(二)

    本篇介绍Kmeans算法中计算新的聚类中心部分.这部分主要逻辑:根据计算出的新的分类信息,对全部数据点依次对每个类别求出所属当前类别的数据点个数与坐标和.本质上就是进行规约运算. V1 Atomic实 ...

  4. 开源100天,OneFlow送上“百天大礼包”:深度学习框架如何进行性能优化?

    11月8日是OneFlow开源100天的纪念日,为了这个有纪念性的日子,我们为大家准备了一个"百天大礼包"--深度学习框架性能优化系列文章,希望能和大家共同探讨开源框架如何进行优化 ...

  5. nginx应用总结(2)--突破高并发的性能优化

    在日常的运维工作中,经常会用到nginx服务,也时常会碰到nginx因高并发导致的性能瓶颈问题.今天这里简单梳理下nginx性能优化的配置(仅仅依据本人的实战经验而述,如有不妥,敬请指出~) 一.这里 ...

  6. Nginx突破高并发的性能优化 - 运维笔记

    在日常的运维工作中,经常会用到nginx服务,也时常会碰到nginx因高并发导致的性能瓶颈问题.今天这里简单梳理下nginx性能优化的配置(仅仅依据本人的实战经验而述,如有不妥,敬请指出~) 一.这里 ...

  7. 2022.3.3 前端性能优化

    面试中 了解性能优化吗? 输入URL 到看到整个页面经历了什么过程? 工作中 页面加载好慢,不知道是前端问题还是后端问题. 页面交互卡顿,不知道具体哪里出了问题 什么是web性能 打开速度 动画效果 ...

  8. Linux C++性能优化秘籍:从编译器到代码,探究高性能C++程序的实现之道

    Linux C++性能优化秘籍:从编译器到代码,揭秘高性能C++程序的实现之道 引言 性能优化的重要性 Linux环境下C++程序的特点 高性能C++编程的核心要点 编译器优化 GCC与Clang编译 ...

  9. GPU性能优化之CUDA调优指南

    GPU性能优化之CUDA调优指南 GPU性能优化之CUDA调优指南 1 整体性能优化策略 2 最大化利用率 2.1 应用程序层次 2.2 设备层次 2.3 多处理器层次 2.3.1 占用率计算 3 最 ...

最新文章

  1. java 线程通讯_java多线程(五)线程通讯
  2. java高深技术总结_一名25K以上的高薪Java程序员总结出的技术以及学习技能
  3. matlab中find函数使用
  4. shell 中一个进制转换的小技巧
  5. MySQL集群节点宕机,数据库脑裂!如何排障?
  6. css细节(实习第1天)
  7. java链表实现_数据结构——基于java的链表实现(真正理解链表这种数据结构)...
  8. André Weil | 数学史:为什么,怎么看
  9. Ubuntu下 5步安装nginx记录
  10. 对openflow 1.0协议的扩展
  11. 关于运放电路放大倍数的计算
  12. 图像匹配之序贯相似性检测法匹配
  13. 计算机一级中替换,08年计算机一级辅导:实战WPS转义符在查找替换中的应用
  14. 抽样分布(卡方分布、t分布、F分布)
  15. 至少连接一个aura sync兼容设备_电磁兼容测试照片
  16. 关于WiFi密码破解的一些心得
  17. 短信通道——阿里大鱼(java)
  18. 居家学习python自制闹铃小助手
  19. 数据结构:并查集和图
  20. 《局外人》活着活着就把自己活成了冷漠无情的局外人

热门文章

  1. [转载]AxureRP 7.0部件详解(一)
  2. 微电子所在阻变存储器研究领域取得新进展
  3. voxel 与 pixel
  4. Android UI控件----ExpandableListView的基本用法
  5. Laravel3 学习笔记
  6. Sencha-概念-Events(事件)(官网文档翻译10)
  7. Effective C# 原则1:尽可能的使用属性(property),而不是数据成员(field)。
  8. NYOJ 642 牛奶
  9. 日期正则表达式yyyyMMdd
  10. AtCoder Grand Contest 030 自闭记