3.8 CUDA编程者使用OpenCL的注意事项

英伟达的CUDA C提供的API与OpenCL类似。代码清单3.6用使用CUDA实现了向量相加,OpenCL和CUDA中的很多命令都可以相互对应。OpenCL API中有更多的参数,这是因为OpenCL需要在运行时去查找平台,并对程序进行编译。CUDA C只针对英伟达的GPU,其只有一个平台可以使用,所以平台的查找自动完成;将程序编译成PTX的过程可以在编译主机端二进制文件的时候进行(CUDA没有运行时编译)。

OpenCL中平台在运行时进行查找,程序需要选择一个目标设备,并在运行时进行编译。程序的编译不能在运行时之外完成,因为不知道哪个具体设备要去执行内核,无法在这种情况下生成中间码(IL/ISA)。比如,一个OpenCL内核在AMD GPU上测试有没有问题,但当其需要运行在Intel的设备上时,编译器生成的中间码就和AMD平台上的不太一样。从而,对与平台的查找,以及在运行时进行编译程序就能避免这样的问题。

OpenCL和CUDA C最大的区别是,CUDA C提供一些特殊的操作完成内核启动,其编译需要使用一套工具链,这套工具链中需要包含英伟达支持的预处理器。预处理器生成的代码,和OpenCL的内核代码十分相近。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. // CUDA kernel. Eache thread computes one element of C
  5. __global__ void vecAdd(int *A, int *B, int *C, int elements){
  6. // Compute the global thread ID using CUDA intrinsics
  7. int id = blocakIdx.x * blocakDim.x + threadIdx.x;
  8. // Must check that the thread is not out of bounds
  9. if (id < elements)
  10. C[id] = A[id] + B[id];
  11. }
  12. int main(int argc, char *argv[]){
  13. // Elements in each array
  14. const int elements = 2048;
  15. // Compute the size of the data
  16. size_t datasize = sizeof(int) * elements;
  17. // Allocate space for input/output host data
  18. int *A = (int *)malloc(datasize); // Input array
  19. int *B = (int *)malloc(datasize); // Input array
  20. int *C = (int *)malloc(datasize); // Output array
  21. // Device input vectors
  22. int *bufA;
  23. int *bufB;
  24. // Device output vectors
  25. int *bufC;
  26. // Allocate memeory for each vector on GPU
  27. cudaMalloc(&bufA, datasize);
  28. cudaMalloc(&bufB, datasize);
  29. cudaMalloc(&bufC, datasize);
  30. int i;
  31. // Initialize vectors on host
  32. for (i = 0; i < elements; i++){
  33. A[i] = i;
  34. B[i] = i;
  35. }
  36. // Copy host vectors to device
  37. cudaMemcpy(bufA, A, datasize, cudaMemcpyHostToDevice);
  38. cudaMemcpy(bufB, B, datasize, cudaMemcpyHostToDevice);
  39. int blockSize, gridSize;
  40. // Number of threads in each thread block
  41. blockSize = 256;
  42. // Number of thread blocks in grid
  43. gridSize = elements / blockSize;
  44. // Execute the kernel
  45. vecAdd<<<gridSize, blockSize>>>(bufA, bufB, bufC, elements);
  46. // Copy array back to host
  47. cudaMemcpy(C, bufC, datasize, cudaMemcpyDeviceToHost);
  48. // Release device memeory
  49. cudaFree(bufA);
  50. cudaFree(bufB);
  51. cudaFree(bufC);
  52. // Release host memeoy
  53. free(A);
  54. free(B);
  55. free(C);
  56. }

代码清单3.6 CUDA C版本的向量相加