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 ...
随机推荐
- Jmeter阶梯加压监听
巧用beanshell,做阶梯加压监听 1. 首先先添加阶梯加压线程组 bzm - Concurrency Thread Group 设置阶梯加压值,目标最大并发用户为80,加速步率时长为100秒, ...
- JAVA8学习——从源码角度深入Stream流(学习过程)
从源代码深入Stream / 学习的时候,官方文档是最重要的. 及其重要的内容我们不仅要知道stream用,要知道为什么这么用,还要知道底层是怎么去实现的. --个人注释:从此看出,虽然新的jdk版本 ...
- CF1272E. Nearest Opposite Parity 题解 广度优先搜索
题目链接:http://codeforces.com/contest/1272/problem/E 题目大意: 有一个长度为n的数组 \(a\) ,数组坐标从 \(1\) 到 \(n\) . 假设你现 ...
- 一个.NET程序员 "2019" 跳槽3次的悲惨故事
2019年是值得深思的一年,在找工作上没有那么用心,导致碌碌无为,在这里我建议大家找工作的时候不要太着急...要不然会被逼疯的,一定不能被“工作”挑,一定要做到挑"工作".:那我就 ...
- mysql 执行计划查看
使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的,分析你的查询语句或是表结构的性能瓶颈.explain执行计划包含的信息 其中最重要的字段为:id ...
- Flask 作者 Armin Ronacher:我不觉得有异步压力
英文 | I'm not feeling the async pressure[1] 原作 | Armin Ronacher,2020.01.01 译者 | 豌豆花下猫@Python猫 声明 :本翻译 ...
- 【转】Eclipse插件收藏列表
使用了多年了Eclipse每个人都有自己的插件私藏列表,本系列文章会记录Eclipse市场推荐的个人私藏插件列表,希望对大家有帮助. 这一期的主人公是Zous Pantalons. viPlugin ...
- linux死机解决办法
linux死机后不要长按电源建强制关机,容易对损坏系统配置或者电脑硬件,导致重启后产生不必要的麻烦 如果是在图形界面下死机的话,不要再依赖任何图形界面的工具,解决方法如下: 1.一种方式是进入终端界面 ...
- svn或git 提交文件排除
也可以参考 https://blog.csdn.net/chenmintong/article/details/79725324 乌龟git 过滤掉忽略文件(首先右键 某文件 删除并添加到忽略列表 ...
- hadoop各版本hadoop.dll和winutils.exe缺少这两个文件
1.1 缺少winutils.exeCould not locate executable null \bin\winutils.exe in the hadoop binaries1.2 缺少had ...