关于CUDA中每个SM分配的寄存器数

关于CUDA中每个SM分配的寄存器数,cuda,Cuda,第一个问题。 CUDAC编程指南如下所示 L1和共享内存使用相同的片上内存:它可以 配置为48 KB共享内存和16 KB一级缓存或16 KB KB的共享内存和48 KB的一级缓存 但是,设备查询显示“每个块可用的寄存器总数:32768”。 我使用GTX580。(CC为2.0) 该指南称默认缓存大小为16KB,但32768表示32768*4(字节)=131072字节=128KB。事实上,我不知道哪个是正确的 第二个问题。 我设置如下 dim3 grid(32, 32);

第一个问题。 CUDAC编程指南如下所示

L1和共享内存使用相同的片上内存:它可以 配置为48 KB共享内存和16 KB一级缓存或16 KB KB的共享内存和48 KB的一级缓存

但是,设备查询显示“每个块可用的寄存器总数:32768”。 我使用GTX580。(CC为2.0) 该指南称默认缓存大小为16KB,但32768表示32768*4(字节)=131072字节=128KB。事实上,我不知道哪个是正确的

第二个问题。 我设置如下

dim3    grid(32, 32);            //blocks in a grid
dim3    block(16, 16);           //threads in a block
kernel<<<grid,block>>>(...);
dim3网格(32,32)//网格中的块
dim3块(16,16)//块中的线程
仁(…);
然后,每个块的线程数为256。=>每个块需要256*N个寄存器。 N表示每个线程所需的寄存器数。 (256*N)*blocks是每个SM的寄存器数。(非字节) 所以,如果默认大小为16KB,threads/SM为MAX(1536),那么N不能超过2。因为“每个多处理器的最大线程数:1536”。 16KB/4Bytes=4096个寄存器,4096/1536=2.66666

对于48KB的较大缓存,N不能超过8。 48KB/4字节=12288寄存器,12288/1536=8

这是真的吗?事实上我很困惑


实际上,我几乎完整的代码在这里。 我认为,当块维度为16x16时,内核得到了优化。 但是,在8x8的情况下,比16x16或类似的速度更快。 我不知道为什么

每个线程的寄存器数为16,共享内存为80+16字节

我问了同样的问题,但我不能得到确切的答案

#定义宽度512
#定义高度512
#定义瓷砖宽度8
#定义瓷砖高度8
#定义通道3
#定义DEVICENUM 1
#定义高度/设备
__全局无效打印多边形(无符号字符*IMAGEin,int*MEMin,字符a,字符b,字符c){
int Col=blockIdx.y*blockDim.y+threadIdx.y;//Col是y坐标
int Row=blockIdx.x*blockDim.x+threadIdx.x;//行是x坐标
int tid_in_block=threadIdx.x+threadIdx.y*blockDim.x;
网格中的int bid_=blockIdx.x+blockIdx.y*gridDim.x;
int threads_per_block=blockDim.x*blockDim.y;
int tid_in_grid=tid_in_block+threads_per_block*bid_in_grid;
浮动结果_a、结果_b;
__共享__;int M[15];
对于(int k=0;k<5;k++){
M[k]=MEMin[a*5+k];
M[k+5]=MEMin[b*5+k];
M[k+10]=MEMin[c*5+k];
}
int result_a_up=(M[11]-M[1])*(Row-M[0])-(M[10]-M[0])*(Col-M[1]);
int result_b_up=(M[6]-M[1])*(M[0]-Row)-(M[5]-M[0])*(M[1]-Col);
int result_down=(M[11]-M[1])*(M[5]-M[0])-(M[6]-M[1])*(M[10]-M[0]);
结果a=(浮动)结果a向上/(浮动)结果a向下;
结果b=(浮动)结果b向上/(浮动)结果向下;

如果(0块大小为8x8时速度更快,因为它是32的较小倍数,如下图所示,有32个CUDA内核绑定在一起,两个不同的warp调度程序实际调度相同的事情。因此,在每个执行周期中,在这32个内核上执行相同的指令

为了更好地阐明这一点,在第一种情况下(8x8),每个块由两个扭曲(64个线程)组成,因此仅在两个执行周期内完成,但是,当使用(16x16)作为块大小时,每个块都需要8个扭曲(256个线程),因此需要4倍多的执行周期,从而导致合成速度变慢

但是,在某些情况下,使用更多扭曲填充SM会更好,当内存访问量较高且每个扭曲可能进入内存暂停(即从内存获取其操作数)时,它将被另一个扭曲替换,直到内存操作完成。因此,会导致SM占用更多空间

当然,您应该在计算中加入每个SM的块数和SMs总数,例如,将8个以上的块分配给单个SM可能会降低其占用率,但在您的情况下,您可能不会面临这些问题,因为256通常比64更好,因为它将在短消息之间平衡块使用64个线程的REA将导致在同一SM中执行更多的块

编辑:这个答案是基于我的推测,要获得更科学的方法,请参阅格雷格·史密斯的答案。 从架构的最底层来看,注册池不同于共享内存/缓存

寄存器由组成,一级缓存可能是

为了得到一个想法,请看下面这张代表费米体系结构的图片,然后更新您的问题以进一步说明您所面临的问题


请注意,您可以看到有多少寄存器和共享内存(smem)通过将选项
--ptxas options=-v
传递给nvcc,由您的函数获取。

块大小为8x8时速度更快,因为它是32的较小倍数,如下图所示,有32个CUDA内核绑定在一起,两个不同的warp调度程序实际调度相同的事情。因此相同的指令在每个执行周期中,在这32个核上执行on

为了更好地阐明这一点,在第一种情况下(8x8),每个块由两个扭曲(64个线程)组成,因此仅在两个执行周期内完成,但是,当使用(16x16)作为块大小时,每个块都需要8个扭曲(256个线程),因此需要4倍多的执行周期,从而导致合成速度变慢

但是,在某些情况下,使用更多扭曲填充SM会更好,当内存访问量较高且每个扭曲可能进入内存暂停(即从内存获取其操作数)时,它将被另一个扭曲替换,直到内存操作完成。因此,会导致SM占用更多空间

当然,您应该在计算中加入每个SM的块数和SMs总数,例如e
#define WIDTH 512
#define HEIGHT 512
#define TILE_WIDTH 8
#define TILE_HEIGHT 8
#define CHANNELS 3
#define DEVICENUM 1 
#define HEIGHTs HEIGHT/DEVICENUM

__global__ void PRINT_POLYGON( unsigned char *IMAGEin, int *MEMin, char a, char b, char c){
        int Col = blockIdx.y*blockDim.y+ threadIdx.y;           //Col is y coordinate
        int Row = blockIdx.x*blockDim.x+ threadIdx.x;           //Row is x coordinate
        int tid_in_block = threadIdx.x + threadIdx.y*blockDim.x;
        int bid_in_grid = blockIdx.x + blockIdx.y*gridDim.x;
        int threads_per_block = blockDim.x * blockDim.y;
        int tid_in_grid = tid_in_block + threads_per_block * bid_in_grid;

        float result_a, result_b;
        __shared__ int M[15];
        for(int k = 0; k < 5; k++){
                M[k] = MEMin[a*5+k];
                M[k+5] = MEMin[b*5+k];
                M[k+10] = MEMin[c*5+k];
        }

        int result_a_up = (M[11]-M[1])*(Row-M[0]) - (M[10]-M[0])*(Col-M[1]);
        int result_b_up = (M[6] -M[1])*(M[0]-Row) - (M[5] -M[0])*(M[1]-Col);

        int result_down = (M[11]-M[1])*(M[5]-M[0]) - (M[6]-M[1])*(M[10]-M[0]);

        result_a = (float)result_a_up / (float)result_down;
        result_b = (float)result_b_up / (float)result_down;

        if((0 <= result_a && result_a <=1) && ((0 <= result_b && result_b <= 1)) && ((0 <= (result_a+result_b) && (result_a+result_b) <= 1))){
                IMAGEin[tid_in_grid*CHANNELS] += M[2] + (M[7]-M[2])*result_a + (M[12]-M[2])*result_b;      //Red Channel
                IMAGEin[tid_in_grid*CHANNELS+1] += M[3] + (M[8]-M[3])*result_a + (M[13]-M[3])*result_b;    //Green Channel
                IMAGEin[tid_in_grid*CHANNELS+2] += M[4] + (M[9]-M[4])*result_a + (M[14]-M[4])*result_b;    //Blue Channel
        }
}

struct DataStruct {
    int                 deviceID;
    unsigned char       IMAGE_SEG[WIDTH*HEIGHTs*CHANNELS];
};

void* routine( void *pvoidData ) { 
        DataStruct  *data = (DataStruct*)pvoidData;
        unsigned char *dev_IMAGE;
        int *dev_MEM;
        unsigned char *IMAGE_SEG = data->IMAGE_SEG;

        HANDLE_ERROR(cudaSetDevice(5));

        //initialize array
        memset(IMAGE_SEG, 0, WIDTH*HEIGHTs*CHANNELS);
        cudaDeviceSetCacheConfig(cudaFuncCachePreferL1);
        printf("Device %d Starting..\n", data->deviceID);

        //Evaluate Time
        cudaEvent_t start, stop;
        cudaEventCreate( &start );
        cudaEventCreate( &stop );

        cudaEventRecord(start, 0); 

        HANDLE_ERROR( cudaMalloc( (void **)&dev_MEM, sizeof(int)*35) );
        HANDLE_ERROR( cudaMalloc( (void **)&dev_IMAGE, sizeof(unsigned char)*WIDTH*HEIGHTs*CHANNELS) );

        cudaMemcpy(dev_MEM, MEM, sizeof(int)*35, cudaMemcpyHostToDevice);
        cudaMemset(dev_IMAGE, 0, sizeof(unsigned char)*WIDTH*HEIGHTs*CHANNELS);

        dim3    grid(WIDTH/TILE_WIDTH, HEIGHTs/TILE_HEIGHT);            //blocks in a grid
        dim3    block(TILE_WIDTH, TILE_HEIGHT);                         //threads in a block

        PRINT_POLYGON<<<grid,block>>>( dev_IMAGE, dev_MEM, 0, 1, 2);
        PRINT_POLYGON<<<grid,block>>>( dev_IMAGE, dev_MEM, 0, 2, 3);
        PRINT_POLYGON<<<grid,block>>>( dev_IMAGE, dev_MEM, 0, 3, 4);
        PRINT_POLYGON<<<grid,block>>>( dev_IMAGE, dev_MEM, 0, 4, 5);
        PRINT_POLYGON<<<grid,block>>>( dev_IMAGE, dev_MEM, 3, 2, 4);
        PRINT_POLYGON<<<grid,block>>>( dev_IMAGE, dev_MEM, 2, 6, 4);

        HANDLE_ERROR( cudaMemcpy( IMAGE_SEG, dev_IMAGE, sizeof(unsigned char)*WIDTH*HEIGHTs*CHANNELS, cudaMemcpyDeviceToHost ) );
        HANDLE_ERROR( cudaFree( dev_MEM ) );
        HANDLE_ERROR( cudaFree( dev_IMAGE ) );

        cudaEventRecord(stop, 0); 
        cudaEventSynchronize(stop);

        cudaEventElapsedTime( &elapsed_time_ms[data->deviceID], start, stop );
        cudaEventDestroy(start);
        cudaEventDestroy(stop);


        elapsed_time_ms[DEVICENUM] += elapsed_time_ms[data->deviceID];
        printf("Device %d Complete!\n", data->deviceID);

        return 0;
}
metric                         8x8         16x16
duration                        161µs       114µs
issued_ipc                     1.24        1.31
executed_ipc                    .88         .59
serialization                 54.61%      28.74%
achieved occupancy            88.32%      30.76%
0 warp schedulers issues       8.81%       7.98%
1 warp schedulers issues       2.36%      29.54%
2 warp schedulers issues      88.83%      52.44%
l1 global load trans          524,407     332,007
l1 global store trans         401,224     209,139
l1 global load trans/request    3.56        2.25
l1 global store trans/request  16.33        8.51