CUDA 计算pi (π)
通过简单的程序设计熟练CUDA的使用步骤
下面是cuda代码及相关注释
#include <stdio.h>
#include <iostream>
#include <time.h>
//#include <cutil_inline.h>
using namespace std; //*****************************************//
//以下两部分将在设备上编译 由__global__标识;
template<typename T> __global__ void reducePI1(T* __restrict__ d_sum, int num){
//__restrict__ 是说从只读缓存中读取该数据,会有什么优势呢?
//printf("blockIdx.x is %d\n",blockIdx.x);//线程块索引,0~grid-1
//printf("blockDim.x is %d\n",blockDim.x);//线程块包含的线程数,这里就是<<<grid,block,size>>>中的block
//printf("threadIdx.x is %d\n",threadIdx.x);//每个线程块中线程的标号,0~block-1
int id = blockIdx.x*blockDim.x + threadIdx.x;//为每个线程构建唯一标号,0~grid*block-1 T temp;
T pSum = ;
extern T __shared__ s_pi[];//数据存放在共享存储上,只有本线程块内的线程可以访问
T rnum = 1.0/num; for(int i=id;i<num;i +=blockDim.x*gridDim.x){
//每个线程计算的次数是总的次数(num)除以总的线程数(grid*block)
temp = (i+0.5f)*rnum;
pSum += 4.0f/(+temp*temp);
} s_pi[threadIdx.x] = pSum*rnum;//每个线程块中的线程会把自己计算得到的s_pi独立存储在本块的共享存储上
__syncthreads();//等待本块所有线程计算完毕 for(int i = (blockDim.x>>);i >;i >>= ){
//将本块内的 计算结果 进行累加
if (threadIdx.x<i){
s_pi[threadIdx.x] += s_pi[threadIdx.x+i];
}
__syncthreads();
}
//将加和的结果写到本块对应的显存中,以备reducePI2使用
if (threadIdx.x==)
{
d_sum[blockIdx.x]=s_pi[];
} //下面这段代码应该是在执行类似的算法但是结果会有很大偏差,并未找到原因^_^
//if (warpSize>63){
// if (threadIdx.x<32){
// s_pi[threadIdx.x] += s_pi[threadIdx.x +32];
// }
//}
//if (threadIdx.x<16){
// s_pi[threadIdx.x] += s_pi[threadIdx.x +16];
//printf("threadIdx.x 16 is %d\n",threadIdx.x);
//}
//if (threadIdx.x<8){
// s_pi[threadIdx.x] += s_pi[threadIdx.x +8];
//printf("threadIdx.x 8 is %d\n",threadIdx.x);
//}
//if (threadIdx.x<4){
// s_pi[threadIdx.x] += s_pi[threadIdx.x +4];
//printf("threadIdx.x 4 is %d\n",threadIdx.x);
//}
//if (threadIdx.x<2){
// s_pi[threadIdx.x] += s_pi[threadIdx.x +2];
//printf("threadIdx.x 2 is %d\n",threadIdx.x);
//}
//if (threadIdx.x<1){
// d_sum[blockIdx.x] = s_pi[0]+s_pi[1];
//printf("threadIdx.x 1 is %d\n",threadIdx.x);
//} } template<typename T> __global__ void reducePI2(T* __restrict__ d_sum, int num, T* __restrict__ d_pi){
int id = threadIdx.x;//这个函数的线程块只有一个,线程数是grid,这里依然用id作为索引名
extern T __shared__ s_sum[];//这个是共享内存中的,只有块内可见
s_sum[id]=d_sum[id];//把显存中的数据装载进来
__syncthreads();//等待装载完成 for(int i = (blockDim.x>>);i>;i >>=)
//仍然采用半对半折和的方法对本块内所有线程中的s_sum进行求和
{
if (id<i){
s_sum[id] += s_sum[id+i];
}
__syncthreads();//等待求和完成
}
//将求和结果写入显存,使得cpu主机端可见
if(threadIdx.x==)
{
*d_pi =s_sum[];
}
//if (warpSize>63){
// if (threadIdx.x<32){
// s_sum[threadIdx.x] += s_sum[threadIdx.x +32];
// }
//}
//if (threadIdx.x<16){
// s_sum[threadIdx.x] += s_sum[threadIdx.x +16];
//}//
//if (threadIdx.x<8){
// s_sum[threadIdx.x] += s_sum[threadIdx.x +8];
//}
//if (threadIdx.x<4){
// s_sum[threadIdx.x] += s_sum[threadIdx.x +4];
//}
//if (threadIdx.x<2){
// s_sum[threadIdx.x] += s_sum[threadIdx.x +2];
//}
//if (threadIdx.x<1){
// *d_pi = s_sum[0]+s_sum[1];
//} } //**********************************************//
//以下代码在主机上编译 template <typename T> T reducePI(int num){ int grid = ;//用来调整线程块的数量 T *tmp;
cudaMalloc((void**)&tmp,grid*sizeof(T));//在设备存储器(显存)上开辟grid*sizeof(T)大小的空间,主机上的指针tmp指向该空间
reducePI1<<<grid,,*sizeof(T)>>>(tmp,num);//调用reducePI1
//参数表示有grid个线程块,每个线程块有256个线程,每个线程块使用256*size大小的共享存储器(只有块内可以访问) //执行之后,会在tmp为首的显存中存储grid 个中间结果
//printf("%d\n",__LINE__);//显示代码所在行号,不知会有什么用
T *d_PI;
cudaMalloc((void**)&d_PI,sizeof(T));//显存中为π的计算结果开辟空间 reducePI2<<<,grid,grid*sizeof(T)>>>(tmp,grid,d_PI);//只有一个线程块,有grid个线程
//执行后在显存中d_PI的位置存放最后结果
T pi;//这是在主机内存上的空间
cudaMemcpy(&pi,d_PI,sizeof(T),cudaMemcpyDeviceToHost);//从显存中将数据拷贝出来
cudaFree(tmp);//释放相应的显存空间
cudaFree(d_PI); return pi;
} template <typename T> T cpuPI(int num){ T sum = 0.0f;
T temp;
for (int i=;i<num;i++)
{
temp =(i+0.5f)/num;
sum += /(+temp*temp);
}
return sum/num; } int main(){
printf("test for compell \n");
clock_t start, finish;//用来计时
float costtime;
start = clock();
//************
printf("cpu pi is %f\n",cpuPI<float>());//调用普通的串行循环计算 π
//*************
finish = clock();
costtime = (float)(finish - start) / CLOCKS_PER_SEC; //单位是秒
printf("costtime of CPU is %f\n",costtime); start = clock();
//************
printf("gpu pi is %f\n",reducePI<float>());//调用主机上的并行计算函数
//************
finish = clock();
costtime = (float)(finish - start) / CLOCKS_PER_SEC;
printf("costtime of GPU is %f\n",costtime);
return ;
}
编译和执行
nvcc computePIsave.cu -I /usr/local/cuda-8.0/include -L /usr/local/cuda-8.0/lib64 -o test
./test
当设定num数量少时cpu的计算耗时会比gpu短,但是随着num的增加,cpu的耗时会成比例增加,但是gpu耗时基本没有变化。
CUDA 计算pi (π)的更多相关文章
- cuda计算的分块
gpu的架构分为streaming multiprocessors 每个streaming multiprocessors(SM)又能分步骤执行很多threads,单个SM内部能同时执行的thread ...
- 计算pi的精度+进度条显示
步骤1:安装tqdm 首先,要打开cmd,输入指令,不断找到python文件的路径,知道找到Scripts,然后分别打入pip install pygame和pip install tqdm 如下图 ...
- 概率法计算PI
#include <iostream> using namespace std; //概率计算PI int main() { ; double val; int i; ; i<; i ...
- 一个很牛的计算pi的c程序!
C语言是面向过程的一种高级程序设计语言,它在世界范围内使用很广泛,而且很流行.很多大型的应用软件,基本上是用C语言所编写的.在对操作系统以及系统使用程序.需要对硬件进行操作的场合,C语言较其他的高级语 ...
- LINUX上一个命令计算PI
Linux上一个命令计算PI – 笑遍世界 http://smilejay.com/2017/11/calculate-pi-with-linux-command/ [root@d1 goEcho]# ...
- CUDA 计算线程索引的一般公式
CUDA thread index: int blockId = blockIdx.z * (gridDim.x*gridDim.y) + blockIdx.y ...
- 用随机投掷飞镖法计算Pi值(Randomness Throwing dart Pi Python)
画一个边长为r的正方形和半径为r的四分之一的圆(如下图所示),向上面随机投掷飞镖,通过计算落在星星区域和整体区域的飞镖比例,即可求出π值. 公式推导如下: 假设正方形的边长r为1,那么飞镖落在星星区域 ...
- 算法之美--1.蒙特卡洛方法计算pi
基本思想: 利用圆与其外接正方形面积之比为pi/4的关系,通过产生大量均匀分布的二维点,计算落在单位圆和单位正方形的数量之比再乘以4便得到pi的近似值.样本点越多,计算出的数据将会越接近真识的pi(前 ...
- CUDA计算矩阵相乘
1.最简单的 kernel 函数 __global__ void MatrixMulKernel( float* Md, float* Nd, float* Pd, int Width) { int ...
随机推荐
- Java动态代理 ----- jdk代理与cglib代理
1.jdk代理 针对接口进行代理,接口可以没有方法, InvocationHandler会拦截所有方法,不过好像意义不大....只能执行Object类的方法,执行结果有点奇怪... package t ...
- .NET Core 3 WPF MVVM框架 Prism系列之命令
本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的命令的用法 一.创建DelegateCommand命令 我们在上一篇.NET Core 3 WPF MVVM框架 Prism系列之 ...
- 【题解】P1373 小a和uim之大逃离
[题解]P1373 小a和uim之大逃离 考虑到可能会MLE,考虑状态压缩一下 由于只要得到他们的差就行了,所以直接少记录一维就好了 \(dp(i,j,r,1/0)\)表示在\(i,j\)点,当前ui ...
- 7.netty内存管理-ByteBuf
ByteBuf ByteBuf是什么 ByteBuf重要API read.write.set.skipBytes mark和reset duplicate.slice.copy retain.rele ...
- MacBook Pro 入手一年了,到底香不香?
最近又有小伙伴问到底值不值得入手一台 MacBook Pro,松哥自己在 2018 年 10 月份的时候入手了一台,到现在为止,也用了一年多了,今天就来和小伙伴们聊一聊使用感受,至于到底值不值,需要大 ...
- Python for Data Analysis 学习心得(三) - 文件读写和数据预处理
一.Pandas文件读写 pandas很核心的一个功能就是数据读取.导入,pandas支援大部分主流的数据储存格式,并在导入的时候可以做筛选.预处理.在读取数据时的选项有超过50个参数,可见panda ...
- 4.eclipse中导入别人用的源代码问题
最近在导入别人用的源代码问题时,出现两个问题: 问题一:提示无法解析导入,如下图: 解决方法:删除项目下的module-info.java文件即可,或者在创建项目时将创建module-info.jav ...
- Intellij Idea插件使用记录之Alibaba Java Coding Guidelines
目录 Intellij Idea插件Alibaba Java Coding Guidelines 前言 使用 感谢 Intellij Idea插件Alibaba Java Coding Guideli ...
- Prometheus+Alertmanager+Grafana监控组件容器部署
直接上部署配置文件 docker-compose.yml version: '3' networks: monitor: driver: bridge services: prometheus: im ...
- vue的param和query两种传参方式及URL的显示
路由配置: // 首页 { path: '/home', name:'home', component:Home }, // 行情 { path: '/markets', name:'market', ...