CUDA当在主机代码中声明常量内存时,如何访问设备内核中的常量内存?
作为记录,这是家庭作业所以尽量少或多少考虑到这一点。 我们使用常量存储器来存储“掩模矩阵”,该掩模矩阵将用于在更大的矩阵上执行卷积。 当我在主机代码中时,我使用cudaMemcpyToSymbol()将掩码复制到常量内存。
我的问题是,一旦将其复制并启动我的设备内核代码,设备如何知道访问常量内存掩码矩阵的位置。 在内核启动时是否需要传入指针。 教授给我们的大部分代码都不应该被改变(没有指向传入掩码的指针)但总有可能他犯了一个错误(虽然这很可能是我对某些东西的理解)
是不是常量的memeory declaratoin应该包含在单独的kernel.cu文件中?
我正在最小化代码,只显示与常量内存有关的事情。 因此,请不要指出是否有什么东西没有初始化等。 有代码,但目前没有关注。
main.cu:
#include #include "kernel.cu" __constant__ float M_d[FILTER_SIZE * FILTER_SIZE]; int main(int argc, char* argv[]) { Matrix M_h, N_h, P_h; // M: filter, N: input image, P: output image /* Allocate host memory */ M_h = allocateMatrix(FILTER_SIZE, FILTER_SIZE); N_h = allocateMatrix(imageHeight, imageWidth); P_h = allocateMatrix(imageHeight, imageWidth); /* Initialize filter and images */ initMatrix(M_h); initMatrix(N_h); cudaError_t cudda_ret = cudaMemcpyToSymbol(M_d, M_h.elements, M_h.height * M_h.width * sizeof(float), 0, cudaMemcpyHostToDevice); //char* cudda_ret_pointer = cudaGetErrorString(cudda_ret); if( cudda_ret != cudaSuccess){ printf("\n\ncudaMemcpyToSymbol failed\n\n"); printf("%s, \n\n", cudaGetErrorString(cudda_ret)); } // Launch kernel ---------------------------------------------------------- printf("Launching kernel..."); fflush(stdout); //INSERT CODE HERE //block size is 16x16 // \\\\\\\\\\\\\**DONE** dim_grid = dim3(ceil(N_h.width / (float) BLOCK_SIZE), ceil(N_h.height / (float) BLOCK_SIZE)); dim_block = dim3(BLOCK_SIZE, BLOCK_SIZE); //KERNEL Launch convolution<<>>(N_d, P_d); return 0; }
kernel.cu: 这就是我不知道如何访问常数内存的地方。
//__constant__ float M_c[FILTER_SIZE][FILTER_SIZE]; __global__ void convolution(Matrix N, Matrix P) { /******************************************************************** Determine input and output indexes of each thread Load a tile of the input image to shared memory Apply the filter on the input image tile Write the compute values to the output image at the correct indexes ********************************************************************/ //INSERT KERNEL CODE HERE //__shared__ float N_shared[BLOCK_SIZE][BLOCK_SIZE]; //int row = (blockIdx.y * blockDim.y) + threadIdx.y; //int col = (blockIdx.x * blockDim.x) + threadIdx.x; }
在“经典”CUDA编译中,您必须定义所有代码和符号(纹理,常量内存,设备函数)以及在同一转换单元中访问它们的任何主机API调用(包括内核启动,绑定到纹理,复制到符号)。 这实际上意味着在同一个文件中(或通过同一文件中的多个include语句)。 这是因为“经典”CUDA编译不包括设备代码链接器。
自从CUDA 5发布以来,有可能使用单独的编译模式并将不同的设备代码对象链接到支持它的体系结构上的单个fatbinary有效负载。 在这种情况下,您需要使用extern关键字声明任何__constant__变量,并将该符号恰好定义一次。
如果你不能使用单独的编译,那么通常的解决方法是在与你的内核相同的.cu文件中定义__constant__符号,并包含一个小的主机包装器函数,它只调用cudaMemcpyToSymbol
来设置有问题的__constant__符号。 您可能会对内核调用和纹理操作执行相同的操作。
下面是一个“最小尺寸”示例,显示了__constant__
符号的使用。 您不需要传递任何指向__global__
函数的指针。
#include #include #include __constant__ float test_const; __global__ void test_kernel(float* d_test_array) { d_test_array[threadIdx.x] = test_const; } #include int main(int argc, char **argv) { float test = 3.f; int N = 16; float* test_array = (float*)malloc(N*sizeof(float)); float* d_test_array; cudaMalloc((void**)&d_test_array,N*sizeof(float)); cudaMemcpyToSymbol(test_const, &test, sizeof(float)); test_kernel<<<1,N>>>(d_test_array); cudaMemcpy(test_array,d_test_array,N*sizeof(float),cudaMemcpyDeviceToHost); for (int i=0; i