为了更好的在kernel函数中提高数据访问效率,我们需要理解CUDA各个存储器模型的特点,合理的分配存储空间。
-------------------华丽的分割线-------------------
一、存储器比较
每个线程拥有自己的register and loacal memory;(可读可写)
每个线程块拥有一块shared memory;(可读可写)
所有线程都可以访问global memory;(可读可写)
还有,可以被所有线程访问的只读存储器:constant memory and texture memory (只读)
通过上述图,我们理解为什么shared和register拥有同样的访问速度,shared memory 和 register 位于 GPU 片内。全局存储三个:global memory,constant memory,texture memory.
存储器关系图,如图所示:
二、各类存储器细讲
1、 寄存器Register
寄存器是GPU上的高速缓存器,其基本单元是寄存器文件,每个寄存器文件大小为32bit. Kernel中的局部(简单类型)变量第一选择是被分配到Register中。
特点:每个线程私有,速度快。
2、 局部存储器 local memory
当register耗尽时,数据将被存储到local memory。如果每个线程中使用了过多的寄存器,或声明了大型结构体或数组,或编译器无法确定数组大小,线程的私有数据就会被分配到local memory中。但是local memory 的数据是被保存在显存中的,速度很慢。
特点:每个线程私有;没有缓存,慢。
注:在声明局部变量时,尽量使变量可以分配到register。如:
unsigned int mt[3]; 改为: unsigned int mt0, mt1, mt2;
使用常量内存性能提升的原因:
I:对常量内存的单次读操作可以广播到其他的“邻近”线程。这将节约15次读取操作。(为什么是15,因为“邻近”指半个线程束,一个线程束包含32个线程的集合。)
II: 常量内存的数据将缓存起来,因此对相同地址的连续读操作将不会产生额外的内存通信量。
注:定义常数存储器时,需要将其定义在所有函数之外,作用于整个文件
1 __constant__ int devVar; 2 cudaMemcpyToSymbol(devVar, hostVar, sizeof(int), 0, cudaMemcpyHostToDevice) 3 cudaMemcpyFromSymbol(hostVar, devVar, sizeof(int), 0, cudaMemcpyDeviceToHost)
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#define SIZE 124
//***declare the constant value***
//两种方法赋值:1-定义直接初始化 2-定义后调用函数初始化cudaMemcpyToSymbol
__constant__ int constArray[SIZE];
__constant__ int cosntArray_Result[SIZE];
__constant__ int constNumber = 10;
//********************************
__global__ void addKernel()
{
int idx = threadIdx.x + blockDim.x * blockIdx.x;
cosntArray_Result[idx] = constNumber + constArray[idx];
}
int main()
{
int inArray[SIZE] = {0};
size_t size = SIZE * sizeof(int);
int *result = NULL;
result = (int*)malloc(size);
//初始化数据
for (int i = 0; i < SIZE; i++) {
inArray[i] = i+1;
}
//copy host data to constant memory 如果不初始化常量内存,将默认数组各元素为0
cudaMemcpyToSymbol(constArray, inArray, size);
//call kernel fun
dim3 threadPerBlock(16);
dim3 blockNum((SIZE + threadPerBlock.x - 1) / threadPerBlock.x);
//计算输入数据和输出数据均采用常量内存
addKernel << <blockNum , threadPerBlock >> > ();
//copy constant data to host data
cudaMemcpyFromSymbol(result, cosntArray_Result, size);
//show data
for (int i = 0; i < SIZE; i++) {
printf("%5d", result[i]);
}
return 0;
}
结果:形式:分为一维纹理内存:texture<float> texconst 和 二维纹理内存 texture<float> texconst 。