CUDA——简介

CUDA简介

CUDA是并行计算的平台和类C编程模型,我们能很容易的实现并行算法,就像写C代码一样。只要配备的NVIDIA GPU,就可以在许多设备上运行你的并行程序,无论是台式机、笔记本抑或平板电脑。熟悉C语言可以帮助你尽快掌握CUDA。

CUDA编程

CUDA编程允许你的程序执行在异构系统上,即CUP和GPU,二者有各自的存储空间,并由PCI-Express 总线区分开。因此,我们应该先注意二者术语上的区分:

  • Host:CPU and itsmemory (host memory)
  • Device: GPU and its memory (device memory)

代码中,一般用h_前缀表示host memory,d_表示device memory。

kernel是CUDA编程中的关键,他是跑在GPU的代码,用标示符__global__注明。

host可以独立于host进行大部分操作。当一个kernel启动后,控制权会立刻返还给CPU来执行其他额外的任务。所以,CUDA编程是异步的。一个典型的CUDA程序包含由并行代码补足的串行代码,串行代码由host执行,并行代码在device中执行。host端代码是标准C,device是CUDA C代码。我们可以把所有代码放到一个单独的源文件,也可以使用多个文件或库。NVIDIA C编译器(nvcc)可以编译host和device生成可执行程序。

这里再次说明下CUDA程序的处理流程:

  1. 从CPU拷贝数据到GPU。
  2. 调用kernel来操作存储在GPU的数据。
  3. 将操作结果从GPU拷贝至CPU。

Memory操作

cuda程序将系统区分成host和device,二者有各自的memory。kernel可以操作device memory,为了能很好的控制device端内存,CUDA提供了几个内存操作函数:

 

为了保证和易于学习,CUDA C 的风格跟C很接近,比如:

cudaError_t cudaMalloc ( void** devPtr, size_t size )

我们主要看看cudaMencpy,其函数原型为:

cudaError_t cudaMemcpy ( void* dst, const void* src, size_t count,cudaMemcpyKind kind )

其中cudaMemcpykind的可选类型有:

  1. cudaMemcpyHostToHost
  2. cudaMemcpyHossToDevice
  3. cudaMemcpyDeviceToHost
  4. cudaMemcpuDeviceToDevice

具体含义很好懂,就不多做解释了。

对于返回类型cudaError_t,如果正确调用,则返回cudaSuccess,否则返回cudaErrorMemoryAllocation。可以使用char* cudaGetErrorString(cudaError_t error)将其转化为易于理解的格式。

组织线程

掌握如何组织线程是CUDA编程的重要部分。CUDA线程分成Grid和Block两个层次。

 

由一个单独的kernel启动的所有线程组成一个grid,grid中所有线程共享global memory。一个grid由许多block组成,block由许多线程组成,grid和block都可以是一维二维或者三维,上图是一个二维grid和二维block。

这里介绍几个CUDA内置变量:

  • blockIdx:block的索引,blockIdx.x表示block的x坐标。
  • threadIdx:线程索引,同理blockIdx。
  • blockDim:block维度,上图中blockDim.x=5.
  • gridDim:grid维度,同理blockDim。

一般会把grid组织成2D,block为3D。grid和block都使用dim3作为声明,例如:

dim3 block(3);
// 后续博文会解释为何这样写grid
dim3 grid((nElem+block.x-1)/block.x);

需要注意的是,dim3仅为host端可见,其对应的device端类型为uint3。

启动CUDA kernel

CUDA kernel的调用格式为:

kernel_name<<<grid, block>>>(argument list);

其中grid和block即为上文中介绍的类型为dim3的变量。通过这两个变量可以配置一个kernel的线程总和,以及线程的组织形式。例如:

kernel_name<<<4, 8>>>(argumentt list);

该行代码表明有grid为一维,有4个block,block为一维,每个block有8个线程,故此共有4*8=32个线程。

注意,不同于c函数的调用,所有CUDA kernel的启动都是异步的,当CUDA kernel被调用时,控制权会立即返回给CPU。

函数类型标示符

__device__ 和__host__可以组合使用。

kernel的限制:

  • 仅能获取device memory 。
  • 必须返回void类型。
  • 不支持可变数目参数。
  • 不支持静态变量。
  • 不支持函数指针。
  • 异步。

代码分析

 

#include <cuda_runtime.h>
#include <stdio.h>
#define CHECK(call) \
{ \
  const cudaError_t error = call; \
  if (error != cudaSuccess) \
  { \
    printf("Error: %s:%d, ", __FILE__, __LINE__); \
    printf("code:%d, reason: %s\n", error, cudaGetErrorString(error)); \
    exit(1); \
  } \
}

void checkResult(float *hostRef, float *gpuRef, const int N) {
  double epsilon = 1.0E-8;
  bool match = 1;
  for (int i=0; i<N; i++) {
    if (abs(hostRef[i] - gpuRef[i]) > epsilon) {
      match = 0;
      printf("Arrays do not match!\n");
      printf("host %5.2f gpu %5.2f at current %d\n",hostRef[i],gpuRef[i],i);
      break;
    }
  }
  if (match) printf("Arrays match.\n\n");
}

void initialData(float *ip,int size) {
  // generate different seed for random number
  time_t t;
  srand((unsigned) time(&t));
  for (int i=0; i<size; i++) {
    ip[i] = (float)( rand() & 0xFF )/10.0f;
  }
}

void sumArraysOnHost(float *A, float *B, float *C, const int N) {
  for (int idx=0; idx<N; idx++)
  C[idx] = A[idx] + B[idx];
}

__global__ void sumArraysOnGPU(float *A, float *B, float *C) {
  int i = threadIdx.x;
  C[i] = A[i] + B[i];
}

int main(int argc, char **argv) {
  printf("%s Starting...\n", argv[0]);
  // set up device
  int dev = 0;
  cudaSetDevice(dev);

  // set up data size of vectors
  int nElem = 32;
  printf("Vector size %d\n", nElem);

  // malloc host memory
  size_t nBytes = nElem * sizeof(float);
  float *h_A, *h_B, *hostRef, *gpuRef;
  h_A = (float *)malloc(nBytes);
  h_B = (float *)malloc(nBytes);
  hostRef = (float *)malloc(nBytes);
  gpuRef = (float *)malloc(nBytes);

  // initialize data at host side
  initialData(h_A, nElem);
  initialData(h_B, nElem);
  memset(hostRef, 0, nBytes);
  memset(gpuRef, 0, nBytes);

  // malloc device global memory
  float *d_A, *d_B, *d_C;
  cudaMalloc((float**)&d_A, nBytes);
  cudaMalloc((float**)&d_B, nBytes);
  cudaMalloc((float**)&d_C, nBytes);

  // transfer data from host to device
  cudaMemcpy(d_A, h_A, nBytes, cudaMemcpyHostToDevice);
  cudaMemcpy(d_B, h_B, nBytes, cudaMemcpyHostToDevice);

  // invoke kernel at host side
  dim3 block (nElem);
  dim3 grid (nElem/block.x);
  sumArraysOnGPU<<< grid, block >>>(d_A, d_B, d_C);
  printf("Execution configuration <<<%d, %d>>>\n",grid.x,block.x);

  // copy kernel result back to host side
  cudaMemcpy(gpuRef, d_C, nBytes, cudaMemcpyDeviceToHost);

  // add vector at host side for result checks
  sumArraysOnHost(h_A, h_B, hostRef, nElem);

  // check device results
  checkResult(hostRef, gpuRef, nElem);

  // free device global memory
  cudaFree(d_A);
  cudaFree(d_B);
  cudaFree(d_C);

  // free host memory
  free(h_A);
  free(h_B);
  free(hostRef);
  free(gpuRef);
  return(0);
}

 

编译指令:$nvcc sum.cu -o sum

运行: $./sum

输出:

./sum Starting...
Vector size 32
Execution configuration <<<1, 32>>>
Arrays match.

 

<think>好的,我现在需要解决用户关于如何正确设置或查看CUDA_PATH环境变量的问题。首先,我应该回忆一下自己之前学过的关于CUDA环境变量配置的知识,并结合用户提供的引用内容来组织回答。 用户提到了几个引用,其中引用了在不同系统下配置CUDA环境变量的方法,比如LinuxWindows。我需要确保回答覆盖这两个系统。首先,设置CUDA_PATH的常用方法,比如在Linux下通过export命令,或者在Windows下通过系统属性设置。然后,如何查看已设置的环境变量,比如在Linux下使用echo或者printenv,Windows下用echo命令或者图形界面。 接下来,用户可能遇到的问题,比如环境变量设置后不生效,这时候需要检查路径是否正确,或者是否需要重启终端。同时,引用中提到虚拟环境可能检测不到CUDA_HOME,这时候可能需要使用conda命令在虚拟环境中设置变量,比如conda env config vars set,这部分也要包含进去。 还需要注意不同系统下的路径差异,比如Linux的默认路径是/usr/local/cuda,而Windows可能是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.X。此外,用户可能混淆了CUDA_PATHCUDA_HOME,是否需要说明两者的区别?根据引用内容,似乎CUDA_HOME也是一个常用的变量名,但可能根据不同的软件需求,需要设置不同的变量名,所以建议用户同时设置这两个变量,或者根据具体软件的要求来选择。 另外,用户可能没有正确配置LD_LIBRARY_PATH或PATH,导致CUDA相关的库无法找到,所以需要提到在Linux下设置LD_LIBRARY_PATH,如引用35中的例子,将/usr/local/cuda/lib64添加到其中。这部分可能属于扩展配置,但用户的问题主要是关于CUDA_PATH,所以可能需要简要提及相关环境变量。 然后,生成相关问题,根据用户的问题,可能涉及如何验证CUDA安装、其他相关的环境变量配置,以及虚拟环境中的问题。比如,如何检查CUDA是否安装成功,或者配置后仍然报错怎么办。 最后,确保回答结构清晰,分步骤说明设置查看的方法,针对不同操作系统分别列出,并且引用对应的引用来源。比如,在Linux下设置CUDA_PATH的方法可以参考引用35,Windows下参考引用4。处理虚拟环境的问题参考引用1。 需要避免使用任何Markdown格式,按照用户的要求,用中文回答,行内公式用$...$,独立公式用$$...$$,但这个问题可能不涉及数学公式,所以可能不需要。但需要正确使用引用标识,比如在引用解决方法时标注[^1]、[^3]等。 现在整理一下步骤: 1. 设置CUDA_PATH的方法: - Linux:临时永久设置 - Windows:系统环境变量设置 - 虚拟环境中的特殊处理 2. 查看CUDA_PATH的方法: - Linux:echo、printenv - Windows:echo、系统属性查看 3. 常见问题解决: - 路径是否正确 - 重启终端或使用source - 虚拟环境中的配置 4. 相关变量如PATHLD_LIBRARY_PATH的配置,引用中的例子。 然后生成相关问题,例如如何验证安装,如何配置其他变量,虚拟环境问题等。 现在需要确保所有信息准确,特别是路径命令正确无误,引用正确的引用来源。例如,在Linux下设置CUDA_PATH为/usr/local/cuda,而Windows的路径是类似C:\Program Files\NVIDIA...,根据引用4中的v10.1例子,应该是版本号,所以用户需要替换成自己的版本。 可能还需要提醒用户检查CUDA的安装路径是否正确,因为不同版本或安装方式可能导致路径不同。例如,默认路径可能不同,用户如果自定义了安装路径,需要相应调整。 总结,回答的结构应该是分步骤,不同操作系统分开说明,包含设置查看方法,常见问题,以及相关引用。然后生成相关问题。</think>### 如何正确设置或查看 CUDA_PATH 环境变量? #### **一、设置 CUDA_PATH 环境变量** 1. **Linux 系统** - **临时设置**(当前终端有效): ```bash export CUDA_PATH=/usr/local/cuda # 默认安装路径,具体根据实际安装位置调整[^5] ``` - **永久设置**(对所有用户生效): 将以下内容添加到 `~/.bashrc` 或 `~/.bash_profile` 文件中: ```bash export CUDA_PATH=/usr/local/cuda export PATH=$CUDA_PATH/bin:$PATH # 添加CUDA工具链到PATH export LD_LIBRARY_PATH=$CUDA_PATH/lib64:$LD_LIBRARY_PATH # 添加库路径[^5] ``` 执行 `source ~/.bashrc` 使配置生效。 2. **Windows 系统** - 右键点击“此电脑” → 选择“属性” → 高级系统设置 → 环境变量 → 在“系统变量”中新建: - 变量名:`CUDA_PATH` - 变量值:`C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.X`(替换为实际版本号)[^4] - 同时确保 `PATH` 变量包含 `%CUDA_PATH%\bin` `%CUDA_PATH%\libnvvp`[^4]。 3. **虚拟环境中的特殊配置** 如果在虚拟环境(如 Conda)中无法检测到 CUDA,可通过以下命令在虚拟环境中设置: ```bash conda env config vars set CUDA_PATH=/usr/local/cuda # 路径需替换为实际值 ``` 退出并重新激活环境后生效。 --- #### **二、查看 CUDA_PATH 环境变量** - **Linux/MacOS**: ```bash echo $CUDA_PATH # 查看变量值 printenv CUDA_PATH # 另一种查看方式 ``` - **Windows**: ```cmd echo %CUDA_PATH% # 命令行查看 ``` 或通过“系统属性 → 环境变量”手动检查。 --- #### **三、常见问题与解决** 1. **环境变量未生效** - 检查路径是否正确,尤其是 CUDA 安装目录是否存在。 - 在 Linux 中执行 `source ~/.bashrc` 或重启终端。 - Windows 需重启命令行工具或系统[^4]。 2. **多版本 CUDA 切换** 手动修改 `CUDA_PATH` 指向不同版本路径,并更新 `PATH` `LD_LIBRARY_PATH`。 3. **依赖库未找到** 确保 `LD_LIBRARY_PATH` 包含 CUDA 库路径(如 `/usr/local/cuda/lib64`)[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值