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 ...
随机推荐
- 经典问题(c++/python)素数、杨辉三角(金字塔型)、统计单词数、简单计算器、密码安全程度、凯撒密码加密、汉诺塔 (python课设实验实例)-- biaobiao88
[编写程序,输人一个大于2的自然数,然后输出小于该数字的所有素数组成的列表.]所谓素数,是指除了1和自身之外没有其他因数的自然数,最小的素数是2,后面依次是3.5.7.11.13... c++代码: ...
- [LINQ2Dapper]最完整Dapper To Linq框架(八)---导航属性
目录 [LINQ2Dapper]最完整Dapper To Linq框架(一)---基础查询 [LINQ2Dapper]最完整Dapper To Linq框架(二)---动态化查询 [LINQ2Dapp ...
- gcc 命令详解
1. gcc -E source_file.c-E,只执行到预编译.直接输出预编译结果. 2. gcc -S source_file.c -S,只执行到源代码到汇编代码的转换,输出汇编代码. 3. g ...
- JavaScript 继承小记
面向对象编程很重要的一个方面,就是对象的继承.A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法.这对于代码的复用是非常有用的. 大部分面向对象的编程语言,都是通过“类”(class) ...
- Java String类相关知识梳理(含字符串常量池(String Pool)知识)
目录 1. String类是什么 1.1 定义 1.2 类结构 1.3 所在的包 2. String类的底层数据结构 3. 关于 intern() 方法(重点) 3.1 作用 3.2 字符串常量池(S ...
- 道格拉斯-普克算法(JavaScript实现)
需求: 有时候当移动速度很慢,GPS定位的轨迹点就非常的多,这时候为了缩减数据量,需要将不突出的点去掉. 思路: (1) 在曲线首尾两点间虚连一条直线,求出其余各点到该直线的距离. (2)选其最大者与 ...
- cogs 826. [Tyvj Feb11] GF打dota 次短路详细原创讲解! dijkstra
826. [Tyvj Feb11] GF打dota ★★☆ 输入文件:dota.in 输出文件:dota.out 简单对比时间限制:1 s 内存限制:128 MB 众所周知,GF同学喜 ...
- 【PCIE-2】---PCIE配置空间及访问方式简介
对新手来说,第一步了解PCIE的相关基本概念,第二步了解PCIE配置空间,第三步深入研究PCIE设备枚举方式.本章主要总结第二步的PCIE配置空间 按照国际惯例,先提问题: 1. 什么是PCIE的配置 ...
- Anaconda的CondaHTTPError问题
在Anaconda+Spyder配置Opencv的过程中遇到了缺乏cv2的问题,当时我在cmd的窗口(管理员身份)中输入了如下命令 conda install --channel https://co ...
- 带限制的广搜 codeforces
You are playing some computer game. One of its levels puts you in a maze consisting of n lines, each ...