程序参考文章: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 编程实例:计算点云法线的更多相关文章

  1. CUDA编程学习笔记1

    CUDA编程模型是一个异构模型,需要CPU和GPU协同工作. host和device host和device是两个重要的概念 host指代CPU及其内存 device指代GPU及其内存 __globa ...

  2. CUDA编程前言

    GPU架构 GPU特别适用于 密集计算,高度可并行计算,图形学 晶体管主要被用于 执行计算,而不是缓存数据,控制指令流 GPU计算的历史 2001/2002 -- 研究人员把GPU当做数据并行协处理器 ...

  3. PHP多进程编程实例

    这篇文章主要介绍了PHP多进程编程实例,本文讲解的是在Linux下实现PHP多进程编程,需要的朋友可以参考下 羡慕火影忍者里鸣人的影分身么?没错,PHP程序是可以开动影分身的!想完成任务,又觉得一个进 ...

  4. c#摄像头编程实例 (转)

    c#摄像头编程实例 摄像头编程 安装摄像头后,一般可以找到一个avicap32.dll文件 这是一个关于设想头的类 using  system;using  System.Runtime.Intero ...

  5. 不同版本CUDA编程的问题

    1 无法装上CUDA的toolkit 卸载所有的NVIDIA相关的app,包括NVIDIA的显卡驱动,然后重装. 2之前的文件打不开,one or more projects in the solut ...

  6. cuda编程基础

    转自: http://blog.csdn.net/augusdi/article/details/12529247 CUDA编程模型 CUDA编程模型将CPU作为主机,GPU作为协处理器(co-pro ...

  7. CUDA学习笔记(一)——CUDA编程模型

    转自:http://blog.sina.com.cn/s/blog_48b9e1f90100fm56.html CUDA的代码分成两部分,一部分在host(CPU)上运行,是普通的C代码:另一部分在d ...

  8. CUDA编程

    目录: 1.什么是CUDA 2.为什么要用到CUDA 3.CUDA环境搭建 4.第一个CUDA程序 5. CUDA编程 5.1. 基本概念 5.2. 线程层次结构 5.3. 存储器层次结构 5.4. ...

  9. JAX-RS 2.0 REST客户端编程实例

    JAX-RS 2.0 REST客户端编程实例 2014/01/28 | 分类: 基础技术, 教程 | 0 条评论 | 标签: JAX-RS, RESTFUL 分享到:3 本文由 ImportNew - ...

随机推荐

  1. eas之排序接口

    KDTable目前本身并不支持排序功能,但提供了排序的接口,用户通过实现该接口(ISortManager)即可实现排序的功能.同时KDTable提供了一个简单实现KDTSortManager,这个类完 ...

  2. eas之创建一个UI界面并对其操作

    private void BranchAddNew(ActionEvent e) {       UIContext uiContext = new UIContext(this);       ui ...

  3. [SDFZOJ]1069:树上统计

    神题...std丑的不行. 我们可以发现i->i+1的边被覆盖过i×(n-i)次. 因为以1->i为左端点,以i+1->n的为右端点,i->i+1都将被覆盖这么多次. 然后从1 ...

  4. Python之Django的Model2

    一.创建数据库 创建数据库 进入数据库: mysql -uroot -p 创建数据库: CREATE DATABASE test1 CHARSET=utf8; 连接数据库 虚拟环境中安装数据库模块:p ...

  5. 【日常学习】【搜索/递归】codevs2802 二的幂次方题解

    转载请注明出处 [ametake版权全部]http://blog.csdn.net/ametake欢迎来看 题目描写叙述 Description 不论什么一个正整数都能够用2的幂次方表示. 比如:13 ...

  6. [DLX精确覆盖] hdu 3663 Power Stations

    题意: 给你n.m.d,代表有n个城市.m条城市之间的关系,每一个城市要在日后d天内都有电. 对于每一个城市,都有一个发电站,每一个发电站能够在[a,b]的每一个连续子区间内发电. x城市发电了.他相 ...

  7. Item 8:析构函数不要抛出异常 Effective C++笔记

    Item 8: Prevent exceptions from leaving destructors. 析构函数不要抛出异常 因为析构函数经常被自己主动调用,在析构函数中抛出的异常往往会难以捕获,引 ...

  8. 在IIS6,7中部署ASP.NET网站

    查看web.config文件 ASP.NET网站与一般的桌面程序不同,不是拷贝过来就能运行的(数据库连接除外). 要想运行它,通常需要一些配置过程.但是,我们到底需要配置什么呢?答案是:查看web.c ...

  9. Uva1335 二分+贪心

    /* 奇数怎么搞呢 二分到答案怎么judge呢 贪心怎么贪呢 假设贪心方案是 前两个挨着取 后面的能靠前就靠前 这样子似乎保证了ans最min 但是不管贪的对不对 操作起来时间GG 而且 如果真的这样 ...

  10. Windows 平台下 Go 语言的安装和环境变量设置

    1. Go 语言 SDK 安装包下载和安装 最新稳定版 1.5.3 安装包 go1.5.3.windows-amd64.msi下载地址 https://golang.org/dl/,大小约 69 MB ...