#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。
由于
答案 0 :(得分:2)
(至少)有3或4个问题:
CUDA线程块限制为1024个线程总计。这意味着block.x * block.y * block.z的乘积必须小于或等于1024.所以你的块尺寸高于32x32根本就不能运行内核。您没有表明这一点,因为您没有proper cuda error checking。
对于32x32及更小的块大小,通常GPU都需要做很多工作。如果您希望有机会充分利用GPU,则Threadblock应至少具有大约128个线程(4个warp)。 (你应该使用很多线程块,可能至少64个。)这与延迟隐藏有关。
一个块中的32个线程(你的2个案例中),你也遇到了一个问题,就是你正在调度32个执行单元上的工作,但有些是空闲的,因为GPU只安排工作在一个单元中warp(32个主题)。
围绕内核调用的这种基于主机的时序方法:
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();
通常是首选。 (但是,你看到的数字可能是合理的。)
如果您想了解有关上述2和3相关问题的更多信息,建议您查看有关第一级GPU优化的基本演示文稿,例如this one