CUDA矩阵增加执行时间与块和网格尺寸的变化

时间:2015-05-07 01:04:13

标签: cuda

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <stdlib.h> 
#include <malloc.h>
#include <time.h>
#include <intrin.h>
#include <stdint.h>

uint64_t rdtsc()
{
    return __rdtsc();
}


void init_matrix(int *a,int size)
{
    for(int i=0;i<size;i++)
        a[i]=i;
}

void print_matrix(int *a,int rows,int columns)
{

    for(int i=0;i<rows;i++){
        for(int j=0;j<columns;j++){
            printf("%d  ",a[j+i*columns]);
        }
        printf("\n");
    }


}
__global__ void add_matrix(int *c,int *a,int *b,int rows,int columns)
{
    //printf("Thread Launched %d\n",threadIdx.x);
    int x = threadIdx.x+blockIdx.x*blockDim.x;
    int y= threadIdx.y+blockIdx.y*blockDim.y;
    int i=x+y*columns;

    c[i]=a[i]+b[i];
}

int main()
{

    int rows=1<<10,columns=1<<10;
    int *h_a,*h_b,*h_c;
    int blockx=512,blocky=512;
    int num_bytes=rows*columns*sizeof(int);
    h_a=(int *)malloc(num_bytes);
    h_b=(int *)malloc(num_bytes);

    h_c=(int *)malloc(num_bytes);


    init_matrix(h_a,rows*columns);
    init_matrix(h_b,rows*columns);


    int *d_a,*d_b,*d_c;

    dim3 block(blockx,blocky);
    dim3 grid(rows/block.x,columns/block.x);

    cudaMalloc((void**)&d_a, num_bytes);
    cudaMalloc((void**)&d_b, num_bytes);
    cudaMalloc((void**)&d_c, num_bytes);

cudaMemcpy(d_a,h_a,num_bytes, cudaMemcpyHostToDevice);
cudaMemcpy(d_b,h_b,num_bytes, cudaMemcpyHostToDevice);

unsigned __int64 a,b;

a=rdtsc();
add_matrix<<<grid,block>>>(d_c,d_a,d_b,rows,columns);
b=rdtsc();





printf("Cycles Taken=%d\n",b-a);

cudaDeviceSynchronize();
cudaMemcpy(h_c,d_c,num_bytes,cudaMemcpyDeviceToHost);








   system("pause");
cudaFree(d_a);
cudaFree(d_b);
cudaFree(d_c);
free(h_a);
free(h_b);
free(h_c);
cudaDeviceReset();
    return 0;
}

上面是一个矩阵加法内核,我用它来确定Cycles中GPU在GPU上的执行时间。

blockx = 1,blocky = 1 Cycles = 436343455

blockx = 4,blocky = 4 Cycles = 32447213

blockx = 32,blocky = 32 Cycles = 8421874

blockx = 128,blocky = 128 Cycles = 71655

blockx = 256,blocky = 256 Cycles = 73000

blockx = 512,blocky = 512 Cycles 70002

上面显示了内核更改block.x和block.y维度所需的周期数。在相对较大的块尺寸的情况下,执行时间要少得多。任何人都可以解释我为什么会如此。是因为经线没有得到正确使用的原因吗?

P.S-这些结果来自华硕ROG笔记本电脑,配备i7-4710HQ和GTX 860M。

由于

1 个答案:

答案 0 :(得分:2)

(至少)有3或4个问题:

  1. CUDA线程块限制为1024个线程总计。这意味着block.x * block.y * block.z的乘积必须小于或等于1024.所以你的块尺寸高于32x32根本就不能运行内核。您没有表明这一点,因为您没有proper cuda error checking

  2. 对于32x32及更小的块大小,通常GPU都需要做很多工作。如果您希望有机会充分利用GPU,则Threadblock应至少具有大约128个线程(4个warp)。 (你应该使用很多线程块,可能至少64个。)这与延迟隐藏有关。

  3. 一个块中的32个线程(你的2个案例中),你也遇到了一个问题,就是你正在调度32个执行单元上的工作,但有些是空闲的,因为GPU只安排工作在一个单元中warp(32个主题)。

  4. 围绕内核调用的这种基于主机的时序方法:

    a=rdtsc();
    add_matrix<<<grid,block>>>(d_c,d_a,d_b,rows,columns);
    b=rdtsc();
    

    通常很麻烦,因为内核调用是异步意味着在内核完成执行之前,控制会立即返回到CPU线程。在定时区域内移动设备同步:

    a=rdtsc();
    add_matrix<<<grid,block>>>(d_c,d_a,d_b,rows,columns);
    cudaDeviceSynchronize();
    b=rdtsc();
    

    通常是首选。 (但是,你看到的数字可能是合理的。)

  5. 如果您想了解有关上述2和3相关问题的更多信息,建议您查看有关第一级GPU优化的基本演示文稿,例如this one