CUDA 初体验

2023-10-29

CUDA Visual Profiler

在上180645课程的时候,里面谈到使用CUDA来做矩阵乘法和k均值聚类的加速。在使用n卡的时候,有一个Visual Profiler的东西可以看到GPU的使用信息。

在安装好了CUDA以后,在Ubuntu上登录以后,使用X server。在Ubuntu命令行输入:

ssh -X < your_andrew_id>@ghcXX.ghc.andrew.cmu.edu

然后就登陆了远程服务器,接着呢使用:

computeprof &

如果遇到错误,退出登录再连接就好了。

这样就可以看到了GPU的使用信息了。然后如果是Windows的话,使用Xming或Cygwin。如果是OS X的话,使用XQuartz就可以了。

CUDA编程指导

使用CUDA编程,可以学习CUDA编程指南【1】。接下来我就大概过一遍编程指南。

threadIdx是三维的向量,可以表示为一维、二维、三维的线程索引。如果是二维的话,若尺寸是 (Dx,Dy) ,那么索引的就是 (x+yDx) 。如果是三维的,索引的就是(x,y,z),那么就是( x+yDx+zDxDy )

现在线程块一般是1024个,但是因为有多个线程块。所以总的线程数是每块线程数x线程块数。

这里写图片描述

通过调用__syncthreads()函数进行数据同步。

CUDA的每个线程、线程块等等的内存层次:
这里写图片描述

除了全局存储之外,还有两种额外的存储:常量和texture memory(这个玩样儿是啥?)。

CUDADeviceReset()的调用使得所有的配置初始化。

CUDA上的存储操作有cudaMalloc(), cudaFree(). cudaMemcpy()。

举一个例子:

// Device code
__global__ void VecAdd(float* A, float* B, float* C, int N)
{
int i = blockDim.x * blockIdx.x + threadIdx.x;
if (i < N)
C[i] = A[i] + B[i];
}
// Host code
int main()
{
int N = ...;
size_t size = N * sizeof(float);
// Allocate input vectors h_A and h_B in host memory
float* h_A = (float*)malloc(size);
float* h_B = (float*)malloc(size);
// Initialize input vectors
...
// Allocate vectors in device memory
float* d_A;
cudaMalloc(&d_A, size);
float* d_B;
cudaMalloc(&d_B, size);
float* d_C;
cudaMalloc(&d_C, size);
// Copy vectors from host memory to device memory
cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);
cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice);
// Invoke kernel
int threadsPerBlock = 256;
int blocksPerGrid =
(N + threadsPerBlock - 1) / threadsPerBlock;
VecAdd<<<blocksPerGrid, threadsPerBlock>>>(d_A, d_B, d_C, N);
// Copy result from device memory to host memory
// h_C contains the result in host memory
cudaMemcpy(h_C, d_C, size, cudaMemcpyDeviceToHost);
// Free device memory
cudaFree(d_A);
cudaFree(d_B);
cudaFree(d_C);
// Free host memory
...
}

cudaMallocPitch(), cudaMalloc3D()可以用来分配内存。另外还有cudaMemcpy2D和cudaMemcpy3D来分配2D和3D的内存。P34行有例子。

shared memory

shared 标识,共享的内存比全局的内存更快。这里举了一个矩阵乘法的例子: P35

P41页有memory blocking存在,更加快。

Page locked out memory

和传统的malloc分配的内存相反的,这种比较固定。

cudaHostAlloc() 和 cudaFreeHost()。

在CUDA里面涉及数据同步和流的东西,这里有显示同步和隐式同步。还有更多数据流的东西,比如数据传过去kernel的时候有的已经在执行啦什么的。还有callback函数。

P57里面有各种API。

CUDA里面的硬件架构上,有SIMD和多线程。

C

一些CUDA的语法,涉及和C有关的东西。类似于API。

在这里,贴上矩阵的CUDA算法,最基本的,然后需要在上面进行加速:

#include <cuda.h>
#include <cuda_runtime.h>
#include "matrix_mul.h"
#define TILE_WIDTH 2

namespace cuda
{
  __global__
  void
  matrix_mul_kernel(float *sq_matrix_1, float *sq_matrix_2, float *sq_matrix_result, int sq_dimension)
  {

    int tx = threadIdx.x;
    int ty = threadIdx.y;

    float sum = 0.0f;

    for(int k = 0; k < sq_dimension; k++)
      {
        sum += sq_matrix_1[ty*sq_dimension + k] * sq_matrix_2[k*sq_dimension + tx];
      }
    sq_matrix_result[ty*sq_dimension + tx] = sum;

 }

  void
  matrix_multiplication(float *sq_matrix_1, float *sq_matrix_2, float *sq_matrix_result, unsigned int sq_dimension)
  {
    int size = sq_dimension * sq_dimension * sizeof(float);
    float *sq_matrix_1_d, *sq_matrix_2_d, *sq_matrix_result_d;

    /***************************************************
  1st Part: Allocation of memory on device memory  
    ****************************************************/

    /* copy sq_matrix_1 and sq_matrix_2 to device memory */
    cudaMalloc((void**) &sq_matrix_1_d, size);
    cudaMemcpy(sq_matrix_1_d, sq_matrix_1, size, cudaMemcpyHostToDevice);
    cudaMalloc((void**) &sq_matrix_2_d, size);
    cudaMemcpy(sq_matrix_2_d, sq_matrix_2, size, cudaMemcpyHostToDevice);

    /*allocate sq_matrix_result on host */
    cudaMalloc((void**) &sq_matrix_result_d, size);

    /***************************************************
   2nd Part: Inovke kernel 
    ****************************************************/
    dim3 dimBlock(sq_dimension, sq_dimension);
    dim3 dimGrid(1,1);
    matrix_mul_kernel<<<dimGrid, dimBlock, dimBlock.x * dimBlock.x * sizeof(float)>>>(sq_matrix_1_d, sq_matrix_2_d, sq_matrix_result_d, sq_dimension);

    /***************************************************
   3rd Part: Transfer result from device to host 
    ****************************************************/
    cudaMemcpy(sq_matrix_result, sq_matrix_result_d, size, cudaMemcpyDeviceToHost);
    cudaFree(sq_matrix_1_d);
    cudaFree(sq_matrix_2_d);
    cudaFree(sq_matrix_result_d);
  }
} // namespace cuda

CUDA 调用

核函数是GPU每个thread上运行的程序。必须通过gloabl函数类型限定符定义。形式如下:

            __global__ void kernel(param list){  }

核函数只能在主机端调用,调用时必须申明执行参数。调用形式如下:

            Kernel<<<Dg,Db, Ns, S>>>(param list);

<<<>>>运算符内是核函数的执行参数,告诉编译器运行时如何启动核函数,用于说明内核函数中的线程数量,以及线程是如何组织的。

<<<>>>运算符对kernel函数完整的执行配置参数形式是<< < Dg, Db, Ns, S>>> 【2】

  • 参数Dg用于定义整个grid的维度和尺寸,即一个grid有多少个block。为dim3类型。Dim3 Dg(Dg.x, Dg.y, 1)表示grid中每行有Dg.x个block,每列有Dg.y个block,第三维恒为1(目前一个核函数只有一个grid)。整个grid中共有Dg.x*Dg.y个block,其中Dg.x和Dg.y最大值为65535。
  • 参数Db用于定义一个block的维度和尺寸,即一个block有多少个thread。为dim3类型。Dim3 Db(Db.x, Db.y, Db.z)表示整个block中每行有Db.x个thread,每列有Db.y个thread,高度为Db.z。Db.x和Db.y最大值为512,Db.z最大值为62。 一个block中共有Db.x*Db.y*Db.z个thread。计算能力为1.0,1.1的硬件该乘积的最大值为768,计算能力为1.2,1.3的硬件支持的最大值为1024。
  • 参数Ns是一个可选参数,用于设置每个block除了静态分配的shared Memory以外,最多能动态分配的shared memory大小,单位为byte。不需要动态分配时该值为0或省略不写。
  • 参数S是一个cudaStream_t类型的可选参数,初始值为零,表示该核函数处在哪个流之中。

CUDA 编程介绍

比如举个计算一个数字每个数字平方和的CUDA实现。

#include <stdio.h>   

__global__ void square(float * d_out, float * d_in)
{  
    int idx = threadIdx.x;  
    float f = d_in[idx];  
    d_out[idx] = f * f;  
}  

int main(int argc, char ** argv) 
{  
    const int ARRAY_SIZE = 64;  
    const int ARRAY_BYTES = ARRAY_SIZE * sizeof(float);  

    // generate the input array on the host   
    float h_in[ARRAY_SIZE];  
    for (int i = 0; i < ARRAY_SIZE; i++)
    {  
        h_in[i] = float(i);  
    }  
    float h_out[ARRAY_SIZE];  

    // declare GPU memory pointers   
    float *d_in;  
    float *d_out;  

    // allocate GPU memory   
    cudaMalloc((void**) &d_in, ARRAY_BYTES);  
    cudaMalloc((void**) &d_out, ARRAY_BYTES);  

    // transfer the array to the GPU   
    cudaMemcpy(d_in, h_in, ARRAY_BYTES, cudaMemcpyHostToDevice);  

    // launch the kernel   
    square<<<1, ARRAY_SIZE>>>(d_out, d_in);  

    // copy back the result array to the CPU   
    cudaMemcpy(h_out, d_out, ARRAY_BYTES, cudaMemcpyDeviceToHost);  

    // print out the resulting array   
    for (int i =0; i < ARRAY_SIZE; i++) {  
        printf("%f", h_out[i]);  
        printf(((i % 4) != 3) ? "\t" : "\n");  
    }  
    cudaFree(d_in);  
    cudaFree(d_out);  

    return 0;  
}  

CUDA 数据同步

原本有问题的代码:

__global__ void shift(){  
    int idx = threadIdx.x;  
    __shared__ int array[128];  
    array[idx] = threadIdx.x;  
    if (idx < 127) {  
        array[idx] = array[idx + 1];  
    }  
}  

设置barrier:

__global__ void shift(){
    int idx = threadIdx.x;
    __shared__ int array[128];
    array[idx] = threadIdx.x;
    __syncthreads();//执行至此,数组中的每一个元素都被正确的赋值
    if (idx < 127) {
        int temp = array[idx + 1];
        __syncthreads();//将一行代码拆分成两行来设置一个barrier,这种技巧非常实用,执行至此,每一个线程都正确的取值
        array[idx] = temp;
        __syncthreads();//确保后续使用array的正确性
    }

}

参考资料:
【1】CUDA 编程指南:http://docs.nvidia.com/cuda/pdf/CUDA_C_Programming_Guide.pdf
【2】CUDA 调用说明:http://blog.csdn.net/augusdi/article/details/12204121
【3】CUDA 核函数的参数解析:http://blog.csdn.net/a925907195/article/details/39500915

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CUDA 初体验 的相关文章

随机推荐

  • ChatGPT在编程方面的用例:节省时间并提高工作效率

    除非您一直住在树林里的小屋里 远离电网 否则您可能听说过ChatGPT AI 聊天机器人于 2022 年 11 月发布并引起了不小的轰动 这引出了一个问题 这项激动人心的新技术究竟能为您 您的企业和您的行业做什么 ChatGPT 在各个领域
  • 山洪灾害监测预警系统解决方案

    一 方案背景 山洪灾害是指山丘地区由降雨引起的洪水 泥石流和滑坡灾害 近年来 我国突发性 局部性极端强降雨引发的山洪灾害导致大量人员伤亡 占洪涝灾害死亡总人数的比例趋上升趋势 群死群伤事件时有发生 山洪灾害严重制约山区和丘陵地区经济发展 人
  • webpack

    一 背景 随着前端的项目逐渐扩大 必然会带来的一个问题就是性能 尤其在大型复杂的项目中 前端业务可能因为一个小小的数据依赖 导致整个页面卡顿甚至奔溃 一般项目在完成后 会通过webpack进行打包 利用webpack对前端项目性能优化是一个
  • Spring源码深度解析:三、容器的刷新 - refresh()

    一 前言 文章目录 Spring源码深度解析 文章目录 我们先通过Spring源码的整体流程 来了解Spring的工作流程是什么 接着根据这个工作流程一步一步的阅读源码 二 Spring容器的启动 public class Test pub
  • QT页面旋转涉及源码修改

    QT页面旋转涉及源码修改 qlinuxfbscreen cpp qlinuxfbscreen h qt页面旋转 在源码中直接搜索这两个文件名称 直接替换内容即可 qlinuxfbscreen cpp Copyright C 2016 The
  • Mongo进阶--存储原理

    存储引擎 Storage wiredTiger引擎 3 0新增引擎 官方宣称在read insert和复杂的update下具有更高的性能 所以后续版本 我们建议使用wiredTiger 所有的write请求都基于 文档级别 的lock 因此
  • GitHub 供应链安全已支持 Dart 开发者生态

    通过 Dart 和 GitHub 团队的共同努力 自 10 月 7 日起 GitHub 的 Advisory Database 安全咨询数据库 Dependency Graph 依赖项关系图 和 Dependabot 依赖更新机器人 开始支
  • MySQL 时间减法

    select date sub curdate interval 1 SECOND 减一秒 select date sub curdate interval 1 MINUTE 减一分钟 select date sub curdate int
  • linux远程telnet和ss都连不上,CentOS7 可以ping通 但是telnet无法连接上端口的问题

    在一台全新的Linux上部署项目 遇到了一些问题 1 安装zookeeper 启动成功 正常运行 本地通过telnet无法连接到zookeeper 可能原因 1 可能是端口没有起来 通过ss ntl可以清楚看到 2181端口已经启动 起来了
  • P1005 最大公约数

    算法 欧几里得辗转相除法 include
  • 文件包含 78-79

    web78 没有什么绕过 file php filter convert base64 encode resource flag php构建这个伪协议之后可以得到flag 首先这是一个file关键字的get参数传递 php 是一种协议名称
  • 2020年中国研究生数学建模竞赛B题

    降低汽油精制过程中的辛烷值损失模型 一 背景 汽油是小型车辆的主要燃料 汽油燃烧产生的尾气排放对大气环境有重要影响 为此 世界各国都制定了日益严格的汽油质量标准 见下表 汽油清洁化重点是降低汽油中的硫 烯烃含量 同时尽量保持其辛烷值 欧盟和
  • JavaScript的一些设计原则

    1 单一职责原则 SRP 单一职责原则通常指 一个类只有一种功能 但是JavaScript是一门面向对象的语言 没有类的概念 所以单一职责在JavaScript中的含义是 一个对象 方法 只有一种功能 那么为什么需要单一职责原则呢 是因为不
  • 「Web3大厂」价值70亿美元的核心竞争力

    经过近 5 年的研发和酝酿 Linea 团队在 7 月的巴黎 ETHCC 大会期间宣布了主网 Alpha 的上线 引起了社区的广泛关注 截止 8 月 4 日 据 Dune 数据信息显示 其主网在一周内就涌入了 100 多个生态项目 跨入了超
  • 远程桌面链接怎么用(win10电脑远程桌面连接工具怎么使用)

    相信很多人都已经使用过QQ的远程协助 远程协助功能可以实现好友间桌面共享 还可以让好友操作自己的电脑 帮助解决一些电脑问题 然而 很多人却忽略了Windows本身就附带的一个功能 远程桌面连接 其实它的功能 性能等一点都不弱 而且它比很多第
  • 融云荣获「2023 中国数字生态通信领军企业」奖

    融云北极星如何协助开发者排查问题和预警风险 8月17日直播课 点击上方报名 由 B P 商业伙伴主办的 2023 数字生态大会 于 8 月 4 日在京举行 融云携数智办公解决方案受邀参展 并获 2023 中国数字生态通信领军企业 奖 关注
  • 微信H5页面背景音乐自动播放

    移动端默认是禁止背景音乐自动播放的 很多需求都需要在页面加载完成的情况下同时出现背景音乐 基于微信的H5页面的音频自动播放的方法网上有很多教程 本次分享的只是一种思路
  • angular 单元测试jest

    前言 最近公司要求笔者开发编写项目单元测试 之前使用过angular框架 但是不知道原来在生成组件的时候多的内个文件 name spec ts 是用来编写angular的单元测试的 下面简单介绍一下关于单元测试的一些问题 单元测试代码和业务
  • java基础:初始化块

    初始化块 1 什么是初始化块 初始化块是java类中可出现的第四种成员 成员变量 方法 构造器 一个类中可以有多个初始化块 2 初始化块的作用 从某种程度来看 初始化块是构造器的补充 初始化块总是在构造器执行之前执行 系统通压根可以使用初始
  • CUDA 初体验

    CUDA Visual Profiler CUDA编程指导 shared memory Page locked out memory C CUDA 调用 CUDA 编程介绍 CUDA 数据同步 CUDA Visual Profiler 在上