并行计算之路<1>——Hello, CUDA.
2016-02-14 17:28
357 查看
you will say goodbye to girls if you are saying “hello world”. 码猿有风险,入行需谨慎
2) malloc() 分配内存空间
3) cudaMalloc() 分配显存空间
4) memset() 初始化内存空间
5) cudaMemset() 初始化显存空间
6) 限定符 __global__ 表示全局函数,从主机调用,在设备里执行。
7) cudaMemcpy() 将处理结果复制到目的内存。
8) free() 以及 cudaFree() 分别释放内存和显存的空间。
1) 选择计算的GPU
2) 分配显存(或内存)空间
3) 初始化数据
4) 调用核函数
5) 处理结果数据
6) 释放显存(或内存)空间
站在巨人的肩膀上,会让事情事半功倍。让更多的时间放在算法上,以及生活上。
参考:
《GPGPU编程技术——从GLSL、CUDA到OpenCL》♥♥♥♥♥
《数字图像处理高级应用——基于MATLAB与CUDA的实现》♥♥♥
《基于CUDA的并行程序设计》♥♥♥
《CUDA专家手册》♥♥♥♥♥
《高性能CUDA应用设计与开发》♥♥♥♥
第一个CUDA程序
参考《GPGPU编程技术——从GLSL、CUDA到OpenCL》的4.3节第一个CUDA程序,因为版本的不同所以对原书的代码进行修改。修改后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "cuda_runtime.h" #include "device_launch_parameters.h" __global__ void my_first_kernel(float *x) { int i = threadIdx.x + blockDim.x * blockIdx.x; *(x + i) = (float) threadIdx.x; } int main(int argc, char **argv) { float *pfCPU = NULL; float *pfGPU = NULL; int nBlocks, nThreads, nSize, n; // 设置block数、每个block的线程数 nBlocks = 2; nThreads = 8; nSize = nBlocks * nThreads; // 分配CPU和GPU存储空间 pfCPU = (float *)malloc(nSize * sizeof(float)); cudaMalloc((void **)&pfGPU, nSize * sizeof(float)); // 数据初始化 memset(pfCPU, 0, nSize * sizeof(float)); cudaMemset(pfGPU, 0, nSize * sizeof(float)); // 执行全局函数 my_first_kernel<<< nBlocks, nThreads >>>(pfGPU); // 取回计算结果,并打印输出 cudaMemcpy(pfCPU, pfGPU, nSize * sizeof(float), cudaMemcpyDeviceToHost); for (n = 0; n < nSize; n++) { printf("%d %f \n", n, *(pfCPU + n)); } // 回收存储空间 cudaFree(pfGPU); free(pfCPU); return 0; }
代码分析
1) CUDA 初始化设备时默认使用0号设备,也可以通过 cudaSetDevice() 函数来启动其它GPU设备。2) malloc() 分配内存空间
3) cudaMalloc() 分配显存空间
4) memset() 初始化内存空间
5) cudaMemset() 初始化显存空间
6) 限定符 __global__ 表示全局函数,从主机调用,在设备里执行。
7) cudaMemcpy() 将处理结果复制到目的内存。
8) free() 以及 cudaFree() 分别释放内存和显存的空间。
CUDA提供的demo
新建 CUDA Runtime的时候,会提供一个demo。当然比第一个严谨规范。代码
#include "cuda_runtime.h" #include "device_launch_parameters.h" #include <stdio.h> cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size); __global__ void addKernel(int *c, const int *a, const int *b) { int i = threadIdx.x; c[i] = a[i] + b[i]; } int main() { const int arraySize = 5; const int a[arraySize] = { 1, 2, 3, 4, 5 }; const int b[arraySize] = { 10, 20, 30, 40, 50 }; int c[arraySize] = { 0 }; // Add vectors in parallel. cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize); if (cudaStatus != cudaSuccess) { fprintf(stderr, "addWithCuda failed!"); return 1; } printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n", c[0], c[1], c[2], c[3], c[4]); // cudaDeviceReset must be called before exiting in order for profiling and // tracing tools such as Nsight and Visual Profiler to show complete traces. cudaStatus = cudaDeviceReset(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaDeviceReset failed!"); return 1; } return 0; } // Helper function for using CUDA to add vectors in parallel. cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size) { int *dev_a = 0; int *dev_b = 0; int *dev_c = 0; cudaError_t cudaStatus; // Choose which GPU to run on, change this on a multi-GPU system. cudaStatus = cudaSetDevice(0); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?"); goto Error; } // Allocate GPU buffers for three vectors (two input, one output) . cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } // Copy input vectors from host memory to GPU buffers. cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } // Launch a kernel on the GPU with one thread for each element. addKernel<<<1, size>>>(dev_c, dev_a, dev_b); // Check for any errors launching the kernel cudaStatus = cudaGetLastError(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus)); goto Error; } // cudaDeviceSynchronize waits for the kernel to finish, and returns // any errors encountered during the launch. cudaStatus = cudaDeviceSynchronize(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus); goto Error; } // Copy output vector from GPU buffer to host memory. cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } Error: cudaFree(dev_c); cudaFree(dev_a); cudaFree(dev_b); return cudaStatus; }
代码分析
其实不难发现,CUDA处理的流程如下。1) 选择计算的GPU
2) 分配显存(或内存)空间
3) 初始化数据
4) 调用核函数
5) 处理结果数据
6) 释放显存(或内存)空间
SDK 和函数库
库名 | 说明 |
---|---|
Thrust | 一个类似于STL针对CUDA的C++模板库 |
NVPP | 英伟达基本性能库 |
cuBLAS | GPU 的基本线性代数函数库 |
CUFFT | GPU 的快速傅里叶函数库 |
cuSparse | GPU 的稀疏矩阵数据的线性代数和矩阵操作库 |
Magma | 一个用于数值计算和线性代数计算的函数库 |
GPU AI | GPU 路径规划函数库 |
CUDA Math lib | GPU 标准数学函数 |
参考:
《GPGPU编程技术——从GLSL、CUDA到OpenCL》♥♥♥♥♥
《数字图像处理高级应用——基于MATLAB与CUDA的实现》♥♥♥
《基于CUDA的并行程序设计》♥♥♥
《CUDA专家手册》♥♥♥♥♥
《高性能CUDA应用设计与开发》♥♥♥♥
相关文章推荐
- 架构师:要成为百科全书式的智者
- 第30讲:模式匹配高级实战:嵌套的Case class
- 年度总结和计划
- C#向其它电脑共享文件夹上传及下载文件
- 基于zepto.js的移动端H5单页面跟随手指滑动切换控件pageSlider
- 《Effective java》读书记录-第23条-请不要在新代码中使用原生态类型
- 用U盘作为启动盘安装Ubuntu(PC已有Win10)
- c++强制类型转换:dynamic_cast、const_cast 、static_cast、reinterpret_cast
- 计算兔子的总数
- C++中判断一个float类型数据是否为整数
- [转]在CentOS上安装Python
- 前端性能优化-状态码200和304
- 前端性能优化-状态码200和304
- PHP中htmlentities和htmlspecialchars的区别
- HttpClient如何 关闭连接(转)
- 分布式常用组件和算法
- hadoop 源码中NameNode与DataNode主要的类目录
- SQL Server专家的10个秘诀(翻译加注解)
- SQL Server专家的10个秘诀(翻译加注解)
- SQL Server专家的10个秘诀(翻译加注解)