CUDA入门:CUDA简介习题

1. 矩阵加法接受两个矩阵 B 和 C 产生输出矩阵 A。输出矩阵 A 的每个元素是输入矩阵 B 和 C 相应元素之和,即 A[i][j] = B[i][j] + C[i][j]。方便起见只考虑方阵,元素都是单精度浮点值。写一个矩阵加法 kernel 函数和一个 stub 函数,可以用如下 4 个参数调用:指向输出矩阵的指针、指向第一个输入矩阵的指针、指向第二个输入矩阵的指针和每个维度上的元素个数。根据如下说明编写:

  • 主机存根函数为输入和输出矩阵分配内存、传输输入数据到设备上、启动 kernel 函数、将输出数据传输至主机以及回收为输入和输出矩阵分配的设备存储器。
int matrixAdd(float *A, float *B, float *C, int n){
    int size = n *n * sizeof(float);
    float *d_A, *d_B, *d_C;
    cudaMalloc((void **)&d_A, size);
    cudaMemcpy(d_A, A, size, cudaMemcpyHostToDevice);
    cudaMalloc((void **)&d_B, size);
    cudaMemcpy(d_B, B, size, cudaMemcpyHostToDevice);
    cudaMalloc((void **)&d_C, size);

    // matrixAddKernel1<<<ceil(n * n / 512.0), 512>>>(d_A, d_B, d_C, n);
    // matrixAddKernelRow<<<ceil(n / 512.0), 512>>>(d_A, d_B, d_C, n);
    // matrixAddKernelCol<<<ceil(n / 512.0), 512>>>(d_A, d_B, d_C, n);
    
    cudaMemcpy(C, d_C, size, cudaMencpyDeviceToHost);
	cudaFree(d_A);
	cudaFree(d_B);
	cudaFree(d_C);
}

  • 编写 kernel 函数, 每个线程生成一个输出矩阵元素。并为此种方案填写执行配置参数。
//compute vector sum C = A + B
//Each thread performs one one pair-wise addition
__global__ void matrixAddKernel(float *A, float *B, float *C, int n){
	int i = threadId.x + blockDim.x * blockIdx.x;
	if(i < n) C[i] = A[i] + B[i];
}

  • 编写 kernel 函数, 每个线程生成一行输出矩阵元素。并为此种方案填写执行配置参数。
//compute matrix sum C = A + B
//Each thread performs 
__global__ void matrixAddKernelRow(float *A, float *B, float *C, int n){
    int i = threadIdx.x + blockDim.x * blockIdx.x;
    if(i < n){
        for(int j = 0;j < n; ++j){
            C[i + j * n] = A[i + j * n] + B[i + j * n];
        }
    }   
}
  • - 编写 kernel 函数, 每个线程生成一列输出矩阵元素。并为此种方案填写执行配置参数。
__global__ void matrixAddKernelCol(float *A, float *B, float *C, int n){
    int i = threadIdx.x + blockDim.x * blockIdx.x;
    if(i < n){
        for(int j = 0;j < n; ++j){
            C[j * n + i] = A[j * n + i] + B[j * n + i];
        }
    }
}

  • 分析以上几种 kernel 方案的优劣
     我的理解是第一个比较快,一个线程算一个元素和,对 GPU 的利用率较高,另外两个一个线程算一行或一列,利用率较低。
main函数:
int main(int argc, char ** argv){
    int N = atoi(argv[1]);
    float *A, *B, *C;
    A = (float *)malloc(sizeof(float) * N * N);
    B = (float *)malloc(sizeof(float) * N * N);
    C = (float *)malloc(sizeof(float) * N * N);
    for(int i = 0;i < N;++i){
        for(int j = 0;j < N;++j){
            A[i * N + j] = i * N + j;
            B[i * N + j] = 1;
        }
    }
    matrixAdd(A, B, C, N);
    for(int i = 0;i < N;++i){
        for(int j = 0;j < N; ++j){
            printf("%f ",C[i * N + j]);
        }
        printf("\n");
    }
    free(A),free(B),free(C);
    return 0;
}


2. 写一个计算矩阵与向量相乘的 kernel 函数。主机存根函数可以通过指向输出矩阵上的指针、指向输入矩阵上的指针、指向输入向量的指针、以及每个维度上元素的数目。

//kernel function
//A is the input matrix, B in the input vector, C is the output vector, n is the dimension and length of matrix
//for clearity, we only consider the condition of phalanx
__global__ void MatVecMulKernel(float *A, float *B, float *C, int n){
    int i = int i = threadIdx.x + blockDim.x * blockIdx.x;
    if(i < n){
        for(int j = 0;j < n;++j){
            C[i] += A[i * n + j] * B[j];
        }
    }
}

//stub function
void MatVecMul(float *A, float *B, float *C, int n){
    int sizeM = n * n * sizeof(float),
        sizeV = n * sizeof(float);
    float *d_A, *d_B, *d_C;
    cudaMalloc((void **)&d_A, sizeM);
    cudaMemcpy(d_A, A, sizeM, cudaMemcpyHostToDevice);
    cudaMalloc((void **)&d_B, sizeV);
    cudaMemcpy(d_B, B, sizeV, cudaMemcpyHostToDevice);
    cudaMalloc((void **)&d_C, sizeV);
    
    MatVecMulKernel<<<ceil(n / 512.0), 512>>>(d_A, d_B, d_C, n);
    
    cudaMemcpy(C, d_C, sizeV, cudaMemcpyDeviceToHost);

	cudaFree(d_A);
	cudaFree(d_B);
	cudaFree(d_C);
}

3.我们希望使用每个线程来计算向量加法的两个(相邻的)输出元素。假设变量i应该是线程要处理的第一个元素的索引。将线程/块索引映射到第一个元素的数据索引的表达式是什么?

a) i = blockIdx.x * blockDim.x + threadIdx.x + 2
b) i = blockIdx.x * threadIdx.x * 2
c) i = (blockIdx.x * blockDim.x + threadIdx.x) * 2
d) i = blockIdx.x * blockDim.x * 2 + threadIdx.x

答案:一个线程两个元素,线程处理的第一个元素在向量中的索引为线程索引的二倍,选C

4.对于向量加法,假定向量长度2000, 每个线程计算一个输出元素,线程块的大小为512,。网格中将有多少线程?

a) 2000
b) 2024
c) 2048
d) 2096
答案:ceil(2000/512) = 4, 4 * 512 = 2048。选c

刚开始学,有问题欢迎一起交流。
































全部评论
感谢楼主分享,特别是还贴心的给了解析
1 回复 分享
发布于 2022-08-18 11:59 陕西

相关推荐

双飞二本嵌入式求拷打我是在&nbsp;BOSS&nbsp;上投递的简历,好多都没人回复,这是开场白和简历求大神帮忙看看。您好!我是2025届应届生,最快可在一周内上岗,能够实习六个月以上,并接受加班。以下是我的核心优势和相关经验:1.&nbsp;嵌入式开发能力:&nbsp;&nbsp;&nbsp;熟练掌握STM32系列单片机及其外设(如GPIO、定时器、ADC、DAC、I2C、SPI、UART等),能够独立完成硬件驱动开发和调试。&nbsp;&nbsp;熟悉FreeRTOS实时操作系统,具备多任务调度和资源管理经验。&nbsp;&nbsp;熟悉LVGL图形库开发,能够实现嵌入式设备的图形界面设计。2.&nbsp;硬件设计能力:&nbsp;&nbsp;&nbsp;具备PCB设计经验,曾为2023年工创赛物流搬运赛道设计小车主板,带领团队获得国家级银奖。&nbsp;&nbsp;&nbsp;熟悉硬件原理图分析,能够快速理解并调试硬件电路。3.&nbsp;机器人开发与竞赛经验:&nbsp;&nbsp;&nbsp;在全国大学生智能车竞赛、ROS机器人竞赛中多次获得国家级奖项,具备丰富的机器人开发经验。&nbsp;&nbsp;&nbsp;熟悉Linux环境,对ROS和ROS&nbsp;2有一定了解,能够进行机器人系统的开发与调试。4.&nbsp;编程能力:&nbsp;&nbsp;&nbsp;熟悉C/C++,熟悉Python,能够高效完成嵌入式开发和算法实现。&nbsp;&nbsp;&nbsp;具备良好的代码规范和文档编写能力。5.&nbsp;团队协作与领导能力:&nbsp;&nbsp;&nbsp;在多个项目中担任核心开发或团队负责人,具备良好的沟通能力和团队协作精神。&nbsp;&nbsp;&nbsp;在工创赛中带领团队完成项目规划、任务分配和技术攻关,展现了较强的领导力。我对嵌入式开发、机器人技术和智能硬件充满热情,期待加入贵公司,与团队共同成长,为公司创造价值!如果有合适的岗位,欢迎随时联系我,期待进一步沟通!
沉淀一会:嵌入式就是狗屎
点赞 评论 收藏
分享
老方子:英语等级cet写错了吧
点赞 评论 收藏
分享
评论
点赞
5
分享

创作者周榜

更多
牛客网
牛客企业服务