CUDA 编程实例:计算点云法线
程序参考文章:http://blog.csdn.net/gamesdev/article/details/17535755 程序优化2
简介:CUDA ,MPI,Hadoop都是并行运算的工具。CUDA是基于NVIDIA GPU芯片计算。
阐述:GPU有很多个核(几百个),每个核可以跑一个线程,多个线程组成一个单位叫做块。
举个例子:
有三个向量 int a, b, c; 我们要计算a和b的向量之和存放到c中。
一般C语言:for(int i=0; i<10; i++) c = a + b; 这个程序是顺序执行的!
CUDA编程做法:
GPU中的每个线程(核)有一个独立序号叫index,那么只要序号从0到9的线程执行c[index] = a[index] + b[index]; 就可以实现以上的for循环。
GPU的可贵之处就是,可以并发运行多个线程,相当于一个时间内赋值10次。
- ////////////////////////
- cuda.cu
- ////////////////////////
- #include <stdio.h>
- #include <cuda_runtime.h>
- //运行在GPU
- __global__ void vectorADD(int* a, int* b, int* c)
- {
- int index = threadIdx.x; //获得当前线程的序号
- if(index < blockDim.x)
- c = a + b;
- }
- int main ()
- {
- //定义10个GPU运算线程
- int N = 10;
- // 本地开辟三个数组存放我们要计算的内容
- int* h_a = (int*) malloc (N * sizeof(int));
- int* h_b = (int*) malloc (N * sizeof(int));
- int* h_c = (int*) malloc (N * sizeof(int));
- // 初始化数组A, B和C
- for(int i=0; i<N; i++) {
- h_a = i;
- h_b = i;
- h_c = 0;
- }
- // 计算10个int型需要的空间
- int size = N * sizeof(int);
- // 在GPU上分配同样大小的三个数组
- int* d_a;
- int* d_b;
- int* d_c;
- cudaMalloc((void**)&d_a, size);
- cudaMalloc((void**)&d_b, size);
- cudaMalloc((void**)&d_c, size);
- // 把本地的数组拷贝进GPU内存
- cudaMemcpy(d_a, h_a, size, cudaMemcpyHostToDevice);
- cudaMemcpy(d_b, h_b, size, cudaMemcpyHostToDevice);
- cudaMemcpy(d_c, h_c, size, cudaMemcpyHostToDevice);
- // 定义一个GPU运算块 由 10个运算线程组成
- dim3 DimBlock = N;
- // 通知GPU用10个线程执行函数vectorADD
- vectorADD<<<1, DimBlock>>>(d_a, d_b, d_c);
- // 将GPU运算完的结果复制回本地
- cudaMemcpy(h_c, d_c, size, cudaMemcpyDeviceToHost);
- // 释放GPU的内存
- cudaFree(d_a);
- cudaFree(d_b);
- cudaFree(d_c);
- // 验证计算结果
- for(int j=0; j<N; j++)
- printf("%d ", h_c);
- printf("\n");
- }
警告!:这个例子是编译不通过的;
首先:对 threadidx的使用,只能在CU文件里面;
其次:在cu文件里初始化数组是错误的: int * a ; a = new int [x];是错误的; 并且 malloc也是不可以的;
再者:文件路径里面不能包含中文,否则会出现 MSB8791 这种错误!
2. 利用CUDA并行计算点云法线
两个函数都存在于CU文件里! 通过外部CPP文件函数进行调用
- void normalEstimate(
- pcl::PointCloud<pcl::PointXYZRGB> &input ,
- pcl::PointCloud<pcl::PointXYZRGB> &output,
- int k_,
- float search_parameter_,
- int THREAD_NUM
- )
//运行在GPU//cal the Normal
- __global__ void normalEstimateSingle(pcl::PointCloud<pcl::PointXYZRGB> &input ,pcl::PointCloud<pcl::PointXYZRGB> &output, int* nn_indices ,int* nn_dists, int Gap, float search_parameter_)
- {
- const size_t computeSize =input.size() / Gap;
- const size_t tID = size_t(threadIdx.x );
- int Mark;
- clock_t startTime; // 开始计时
- if ( tID == 0 ) startTime =clock( );// 选择任意一个线程进行计时
- //Thread loop!//循环发现邻域!寻找法线!
- for ( size_t idx = tID *computeSize; idx < ( tID + 1 ) * computeSize && idx < input.size(); ++idx ) {
- // pOut[threadIdx.x] += pIn[i] * pIn[i];
- Mark = pcl::searchForNeighbors (idx, search_parameter_, nn_indices, nn_dists);//对第IDX个建立索引!
- if (Mark == 0){
- output.points[idx].normal[0] = output.points[idx].normal[1] = output.points[idx].normal[2] = output.points[idx].curvature = std::numeric_limits<float>::quiet_NaN ();
- continue;
- }
- else {
- if (!isFinite (input[idx]) || Mark == 0){
- output.points[idx].normal[0] = output.points[idx].normal[1] = output.points[idx].normal[2] = output.points[idx].curvature = std::numeric_limits<float>::quiet_NaN ();
- continue;
- }
- }
- pcl::computePointNormal (input, nn_indices,output.points[idx].normal[0], output.points[idx].normal[1], output.points[idx].normal[2], output.points[idx].curvature);
- pcl::flipNormalTowardsViewpoint (input_->points[idx], vpx_, vpy_, vpz_,
- output.points[idx].normal[0], output.points[idx].normal[1], output.points[idx].normal[2]);
- }
- if ( tID == 0 ) *pElapsed =clock( ) - startTime;// 结束计时,返回至主程序
- }
//运行在CPU端!
- // as the input
- extern "C" void normalEstimate(
- pcl::PointCloud<pcl::PointXYZRGB> &input ,
- pcl::PointCloud<pcl::PointXYZRGB> &output,
- int k_,
- float search_parameter_,
- int THREAD_NUM
- )
- {
- // 在GPU上分配同样大小的三个数组
- pcl::PointCloud<pcl::PointXYZRGB> &inputX ;
- pcl::PointCloud<pcl::PointXYZRGB> &outputX;
- int* nn_indices ;
- int* nn_dists;
- // 1、设置设备
- cudaError_t cudaStatus = cudaSetDevice( 0 );// 只要机器安装了英伟达显卡,那么会调用成功
- if ( cudaStatus != cudaSuccess )
- {
- fprintf( stderr, "调用cudaSetDevice()函数失败!" );
- return ;//false;
- }
- // 使用CUDA内存分配器分配host端
- //cudaError_t cudaStatus = cudaMallocHost( &inputX, input.size() * sizeof( pcl::pointXYZRGB ) );
- //cudaError_t cudaStatus = cudaMallocHost( &outputX, output.size() * sizeof( pcl::Normal ) );
- // 2、分配显存空间
- cudaError_t cudaStatus = cudaMalloc( &inputX, input.size() * sizeof( pcl::pointXYZRGB ) );
- cudaError_t cudaStatusX = cudaMalloc( &outputX, output.size() * sizeof( pcl::Normal ) );
- // cudaStatus = cudaMalloc( (void**)&pData, DataSize * sizeof( int) );
- if ( cudaStatus != cudaSuccess)
- {
- fprintf( stderr, "调用cudaMalloc()函数初始化显卡中数组时失败!" );
- break;
- }
- // 3、将宿主程序数据复制到显存中
- cudaError_t cudaStatus2 = cudaMemcpy( inputX, input, input.size() * sizeof( pcl::pointXYZRGB ),cudaMemcpyHostToDevice );
- cudaError_t cudaStatusX2 = cudaMemcpy(outputX,output,output.size() * sizeof( pcl::pointXYZRGB ),cudaMemcpyHostToDevice );
- if ( cudaStatus != cudaSuccess)
- {
- fprintf( stderr, "调用cudaMemcpy()函数初始化宿主程序数据数组到显卡时失败!" );
- break;
- }
- //cudaMalloc( (void**)&nn_dists, k_ * sizeof( int) );
- //cudaMalloc( (void**)&nn_indices, k_ * sizeof( int) );
- //cudaMalloc( (void**)&Normal3f, 3 * sizeof( float) );
- // 4、执行程序,宿主程序等待显卡执行完毕
- normalEstimateSingle<<<1, THREAD_NUM>>>( inputX,outputX, nn_indices, nn_dists, THREAD_NUM ,search_parameter_);
- //normalEstimateSingle(pcl::PointCloud<pcl::PointXYZRGB> &input ,pcl::PointCloud<pcl::PointXYZRGB> &output, int* nn_indices ,int* nn_dists, int Gap)
- // 5、查询内核初始化的时候是否出错
- cudaStatus = cudaGetLastError( );
- if ( cudaStatus != cudaSuccess)
- {
- fprintf( stderr, "显卡执行程序时失败!" );
- break;
- }
- // 6、与内核同步等待执行完毕
- cudaStatus = cudaDeviceSynchronize( );
- if ( cudaStatus != cudaSuccess)
- {
- fprintf( stderr, "在与内核同步的过程中发生问题!" );
- break;
- }
- // 7、获取数据 //只复制出法线即可!
- cudaStatus = cudaMemcpy(output,outputX,output.size() * sizeof( pcl::pointXYZRGB ),cudaMemcpyHostToDevice );
- if ( cudaStatus != cudaSuccess)
- {
- fprintf( stderr, "在将结果数据从显卡复制到宿主程序中失败!" );
- break;
- }
- cudaFree( outputX );
- cudaFree( inputX );
- }
注意事项:运行在GPU的函数,只能是原子函数,详情请见 《高性能并行编程实践》
CUDA 编程实例:计算点云法线的更多相关文章
- CUDA编程学习笔记1
CUDA编程模型是一个异构模型,需要CPU和GPU协同工作. host和device host和device是两个重要的概念 host指代CPU及其内存 device指代GPU及其内存 __globa ...
- CUDA编程前言
GPU架构 GPU特别适用于 密集计算,高度可并行计算,图形学 晶体管主要被用于 执行计算,而不是缓存数据,控制指令流 GPU计算的历史 2001/2002 -- 研究人员把GPU当做数据并行协处理器 ...
- PHP多进程编程实例
这篇文章主要介绍了PHP多进程编程实例,本文讲解的是在Linux下实现PHP多进程编程,需要的朋友可以参考下 羡慕火影忍者里鸣人的影分身么?没错,PHP程序是可以开动影分身的!想完成任务,又觉得一个进 ...
- c#摄像头编程实例 (转)
c#摄像头编程实例 摄像头编程 安装摄像头后,一般可以找到一个avicap32.dll文件 这是一个关于设想头的类 using system;using System.Runtime.Intero ...
- 不同版本CUDA编程的问题
1 无法装上CUDA的toolkit 卸载所有的NVIDIA相关的app,包括NVIDIA的显卡驱动,然后重装. 2之前的文件打不开,one or more projects in the solut ...
- cuda编程基础
转自: http://blog.csdn.net/augusdi/article/details/12529247 CUDA编程模型 CUDA编程模型将CPU作为主机,GPU作为协处理器(co-pro ...
- CUDA学习笔记(一)——CUDA编程模型
转自:http://blog.sina.com.cn/s/blog_48b9e1f90100fm56.html CUDA的代码分成两部分,一部分在host(CPU)上运行,是普通的C代码:另一部分在d ...
- CUDA编程
目录: 1.什么是CUDA 2.为什么要用到CUDA 3.CUDA环境搭建 4.第一个CUDA程序 5. CUDA编程 5.1. 基本概念 5.2. 线程层次结构 5.3. 存储器层次结构 5.4. ...
- JAX-RS 2.0 REST客户端编程实例
JAX-RS 2.0 REST客户端编程实例 2014/01/28 | 分类: 基础技术, 教程 | 0 条评论 | 标签: JAX-RS, RESTFUL 分享到:3 本文由 ImportNew - ...
随机推荐
- codeforces 467C George and Job(简单dp,看了题解抄一遍)
题目 参考了网页:http://www.xue163.com/exploit/180/1802901.html //看了题解,抄了一遍,眼熟一下,增加一点熟练度 //dp[i][j]表示是前i个数选出 ...
- C#第十四节课
函数的调用 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System ...
- 一步一步实现基于GPU的pathtracer(二):求交算法
不管是哪种全局光照算法,最根本的都要落实到光线与物体的求交.主要分为光线与参数曲面和非参数曲面的求交,典型的参数曲面有球.盒.圆柱等基本体及基本体的组合体,以及一些更为复杂的参数曲面.非参数曲面就是所 ...
- HDU-1134 卡特兰数+java大数模板
题意: 给你一个n,然后1,2,3...2n-1,2n围一圈,让每个数都能用一条线配对并且线与线之间不能交叉,问有几种方法数. 思路: 1 可以和2,4,6...连接.假如 一共有8个数,1和2连 ...
- UDP、线程、mutex锁(day15)
一.基于UDP的网络编程模型 服务器端 .创建socket. .将fd和服务器的ip地址和端口号绑定 .recvfrom阻塞等待接收客户端数据 .业务处理 .响应客户端 客户端: .创建socket ...
- [luogu2165 AHOI2009] 飞行棋 (枚举)
传送门 Description 给出圆周上的若干个点,已知点与点之间的弧长,其值均为正整数,并依圆周顺序排列. 请找出这些点中有没有可以围成矩形的,并希望在最短时间内找出所有不重复矩形. Input ...
- request.getScheme()、 request.getServerName() 、 request.getServerPort() 、 request.getContextPath()
<% String basePath = request.getScheme() + "://" + request.getServerName() + ":&qu ...
- Python中的sorted() 和 list.sort() 的用法总结
只要是可迭代对象都可以用sorted . sorted(itrearble, cmp=None, key=None, reverse=False) =号后面是默认值 默认是升序排序的, 如果想让结果降 ...
- cogs 10. 信号无错传输
10. 信号无错传输 ★★☆ 输入文件:dlj.in 输出文件:dlj.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] 为提高传递信息的保密性和可靠性,两个军事 ...
- gcc指定头文件路径及动态链接库路径
gcc指定头文件路径及动态链接库路径 本文详细介绍了linux 下gcc头文件指定方法,以及搜索路径顺序的问题.另外,还总结了,gcc动态链接的方法以及路径指定,同样也讨论了搜索路径的顺序问题.本 ...