cuda学习

CUDA 安装测试部分 https://blog.csdn.net/sunmc1204953974/article/details/51000970
CUDA的HelloWorld程序编写 https://www.cnblogs.com/neopenx/p/4643705.html
对多线程并行处理的解释:https://blog.csdn.net/sunmc1204953974/article/details/51025801
以下的CUDA知识全部转载自:https://blog.csdn.net/sunmc1204953974

数组中求立方和(CUDA编程举例)
//简单的CUDA程序,转载自:https://blog.csdn.net/sunmc1204953974/article/details/51025801
//代码功能:计算数组中数字的立方和
//maintest.cu文件
#include <stdio.h> 
#include <time.h>
#include <iostream>//CUDA RunTime API
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <atomic>using namespace std;
//数组的大小
#define DATA_SIZE 1048576
//程序中用到的线程数,注意要小于设备中的maxThreadsPerBlock变量
#define THREAD_NUM 1024
//GPU的运行频率
int gpu_clock_rate = 0;
int data[DATA_SIZE];void GenerateNumbers(int *number, int size)
{for (int i = 0; i < size; i++){number[i] = rand() % 10;}
}void PrintDeviceProp(const cudaDeviceProp &prop)
{printf("Device Name : %s.\n", prop.name);printf("totalGlobalMem : %d.\n", prop.totalGlobalMem);printf("sharedMemPerBlock : %d.\n", prop.sharedMemPerBlock);printf("regsPerBlock : %d.\n", prop.regsPerBlock);printf("warpSize : %d.\n", prop.warpSize);printf("memPitch : %d.\n", prop.memPitch);printf("maxThreadsPerBlock : %d.\n", prop.maxThreadsPerBlock);printf("maxThreadsDim[0 - 2] : %d %d %d.\n", prop.maxThreadsDim[0], prop.maxThreadsDim[1], prop.maxThreadsDim[2]);printf("maxGridSize[0 - 2] : %d %d %d.\n", prop.maxGridSize[0], prop.maxGridSize[1], prop.maxGridSize[2]);printf("totalConstMem : %d.\n", prop.totalConstMem);printf("major.minor : %d.%d.\n", prop.major, prop.minor);printf("clockRate : %d.\n", prop.clockRate);printf("textureAlignment : %d.\n", prop.textureAlignment);printf("deviceOverlap : %d.\n", prop.deviceOverlap);printf("multiProcessorCount : %d.\n", prop.multiProcessorCount);}//CUDA 初始化
bool InitCUDA()
{int count;//取得支持Cuda的装置的数目cudaGetDeviceCount(&count);//没有符合的硬件if (count == 0) {fprintf(stderr, "There is no device.\n");return false;}int i;for (i = 0; i < count; i++) {cudaDeviceProp prop;if (cudaGetDeviceProperties(&prop, i) == cudaSuccess) {gpu_clock_rate = prop.clockRate;cout << endl;PrintDeviceProp(prop);cout << "---" << endl;cout << endl;if (prop.major >= 1) {break;}}}if (i == count) {fprintf(stderr, "There is no device supporting CUDA 1.x.\n");return false;}cudaSetDevice(i);return true;
}__global__ static void SumOfSquares(int *num, int *result,clock_t *time)
{//表示目前的 thread 是第几个 thread(由 0 开始计算)const int tid = threadIdx.x;//计算每个线程需要完成的量const int size = DATA_SIZE / THREAD_NUM;int sum = 0;int i;//记录运算开始的时间clock_t start;//只在 thread 0(即 threadIdx.x = 0 的时候)进行记录if (tid == 0) start = clock();for (i = tid * size; i < (tid + 1) * size; i++) {sum += num[i] * num[i] * num[i];}result[tid] = sum;//计算时间的动作,只在 thread 0(即 threadIdx.x = 0 的时候)进行//相减得到的是GPU执行单元的频率,也就是GPU的时钟周期(timestamp),需要除以GPU的运行频率才能得到以秒为单位的时间if (tid == 0) *time = clock() - start;
}int maintest()
{srand(time(0));if (!InitCUDA()){return 0;}printf("CUDA initialized.\n");GenerateNumbers(data, DATA_SIZE);//显卡内存数据表示int *gpudata, *result;clock_t *time;cudaMalloc((void**)&gpudata, sizeof(int)*DATA_SIZE);cudaMalloc((void**)&result, sizeof(int)*THREAD_NUM);cudaMalloc((void**)&time, sizeof(clock_t));//cudaMemcpy将产生的随机数复制到显卡内存中//cudaMemcpy(gpudata, data, sizeof(int)*DATA_SIZE, cudaMemcpyHostToDevice);//在CUDA中执行函数,语法<<<block数目,thread数目,shared memory大小>>>(参数...);SumOfSquares << <1, THREAD_NUM, 0 >> >(gpudata, result, time);//从显卡数据复制到内存int sum[THREAD_NUM];clock_t time_use;cudaMemcpy(&sum,result,sizeof(int)*THREAD_NUM, cudaMemcpyDeviceToHost);cudaMemcpy(&time_use, time, sizeof(int), cudaMemcpyDeviceToHost);//freecudaFree(gpudata);cudaFree(result);cudaFree(time);long final_sum = 0;for (int i = 0; i < THREAD_NUM; i++){final_sum += sum[i];}cout << "gpu sum " << final_sum << endl;cout << "gpu time " << time_use << endl;cout << "gpu time(second) " << time_use*1.0/(gpu_clock_rate * 1000) << endl;long time_s, time_e;time_s = clock();final_sum = 0;for (int i = 0; i < DATA_SIZE; i++){final_sum += data[i] * data[i] * data[i];}time_e = clock();cout << "cpu sum " << final_sum << endl;cout << "cpu time(second) " << (time_e - time_s)*1.0/CLOCKS_PER_SEC<< endl;return 0;
}

cpu 文件代码

#include <stdio.h>
#include <iostream>
using namespace std;
//调用cu文件函数的接口
extern int maintest();
int main()
{maintest();return 0;
}

显示结果


Device Name : GeForce GT 630.
totalGlobalMem : -2147483648.
sharedMemPerBlock : 49152.
regsPerBlock : 65536.
warpSize : 32.
memPitch : 2147483647.
maxThreadsPerBlock : 1024.
maxThreadsDim[0 - 2] : 1024 1024 64.
maxGridSize[0 - 2] : 2147483647 65535 65535.
totalConstMem : 65536.
major.minor : 3.0.
clockRate : 875500.
textureAlignment : 512.
deviceOverlap : 1.
multiProcessorCount : 1.
---CUDA initialized.
gpu sum 212139366
gpu time 6795883
gpu time(second) 0.00776229
cpu sum 212139366
cpu time(second) 0.002
结果分析

倒数第一行和倒数第三行,可以看到gpu和cpu中的计算结果是一样的,sum=212139366,gpu中所花费时间为0.00776229秒。
可以看到CPU的运行时间比GPU还短,但如果把加和函数编写的复杂,就能明显的看到GPU并行计算的优势。

并行线程的解释

这段代码主要是对相互独立的单元进行计算时,可以编写CUDA函数进行调用,调用时内部的逻辑我个人的分析如下:多个线程会依据__global__函数的副本,几乎同一时间调用副本函数,进行并行的计算,多个线程之间独立运行;const int tid = threadIdx.x;这行代码会获得调用该副本函数的线程id,依据id可以执行具体的单元。

GPU显卡中显存连续存取
for (i = tid * size; i < (tid + 1) * size; i++) {sum += num[i] * num[i] * num[i];
}

这样for循环的编写没有利用到显存连续存取的优点,在GPU中,thread在等待数据读入时,会切换下一个thread,thread的切换速度要远比显存存取的速度要快,并行的处理如下图:
在这里插入图片描述
如果显存反复载入的话,太消耗时间,如果换一种for循环编程方式,速度会提高很多,

for (i = tid ; i < DATA_SIZE; i+= THREAD_NUM) {sum += num[i] * num[i] * num[i] ;	
}

显示结果如下:

CUDA initialized.
gpu sum 212259240
gpu time 1122455
gpu time(second) 0.00128207
cpu sum 212259240
cpu time(second) 0.002

可以看到GPU消耗时间是1122455个时钟周期,简单的改变比上一个结果的时间消耗6795883要快6倍。
GPU下的0.00128207秒的计算总耗时,终于比0.002秒的CPU耗时要短了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/492731.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

英特尔第七任CEO敲定 斯旺为何受到董事会青睐?

来源&#xff1a;网易科技2019年1月最后一天&#xff0c;芯片巨头英特尔公司(Intel)宣布任命临时首席执行官罗伯特斯旺(Robert Swan)为正式CEO&#xff0c;从而结束了长达数月的猎头工作。此前&#xff0c;英特尔前任CEO布莱恩柯再奇(Brian Krzanich)因与员工存在“暧昧关系”而…

sudo使用

sudo使用 /etc/sudo.conf /etc/sudoers /etc/sudoers.d/ /etc/sudo-ldap.conf /etc/sudoer sudo安全策略配置文件 Defaults requiretty Defaults !visiblepw Defaults always_set_home Defaults env_reset Defaults env_keep "COLORS DISPLAY HOSTNAME HI…

图灵奖得主长文报告:是什么开启了计算机架构的新黄金十年?

来源&#xff1a;AI科技评论摘要&#xff1a;2017 年图灵奖的两位得主 John L. Hennessy 和 David A. Patterson 就是这个新浪潮的见证者和引领者。近几年来&#xff0c;不论是普通消费者还是科研人员们都可以感受到两种浪潮&#xff0c;一种是CPU速度的提升越来越不显著了&…

ubuntu安装wine之后进不了系统

以前曾经装过一次wine&#xff0c;安装的时候没碰到什么问题&#xff0c;但卸载的时候却出问题了&#xff0c;把我nouvean显卡给删除了。 自然&#xff0c;我下一次启动的时候就进不了桌面了。所以我得重装一次&#xff0c;那一次重装的是整个系统&#xff01; 今天突然觉得evi…

5G到底有哪些能力

来源&#xff1a;工信头条作者&#xff1a;华为5G首席科学家 童文摘要&#xff1a;华为5G首席科学家告诉你5G到底有哪些能力&#xff01;2019年是5G产业进入全面商用的关键一年&#xff0c;全球5G网络的部署已经启动。2018年6月&#xff0c;5G独立组网标准冻结&#xff0c;5G完…

口琴简易吹奏法

摘自上海口琴说明书。 口琴体积小巧&#xff0c;携带方便&#xff0c;有"带着走的音乐"、"口袋里的钢琴"之称。 口琴是一种簧舌乐器&#xff0c;用嘴吹吸发音。 复音口琴每孔上下两个是同音&#xff0c;吹奏时两格内的簧片同时发音。 口琴的 "1、3…

商业航天:通往太空旅程的新门票

来源&#xff1a;资本实验室自1969年美国实现人类首次登月之后&#xff0c;很长一段时间里&#xff0c;人类对月球的探索计划因各种原因变得沉寂。近年来&#xff0c;随着各国航天科技的持续发展&#xff0c;人类正在启动对月球的全新探索旅程。今年1月3日&#xff0c;我国“嫦…

win32程序调试

win32程序调试函数&#xff1a;https://blog.csdn.net/github_35160620/article/details/51864872 显示在编译器调试时的输出栏&#xff1b; debugView的使用&#xff0c;注意是程序单独运行时的调试工具&#xff0c;不是在VS编译器下&#xff1a;https://blog.csdn.net/bearc…

关于用css实现的文字超出部分显示省略号

文字超出部分显示省略号还是比较常用的一个效果,最近看到网上的一些方法亲自实践了一下,发现有些以前一些浏览器不能用的属性现在可以用了&#xff0c;于是研究了一番&#xff0c;现总结如下&#xff1a; 我们先来看下HTML代码&#xff1a; <div><p><span>用…

AIoT的生死局:未来的AIoT很赚钱,但目前的AI+IoT很花钱

来源&#xff1a;物联网智库整理摘要&#xff1a;AIoT目前仍处于发展的起步阶段&#xff0c;只能作为一种美好的愿想&#xff0c;无论从AI还是IoT本身来看&#xff0c;仍然存在着许许多多的问题。如同互联网等新兴技术发展初期一样&#xff0c;AIoT也多少存在追捧与泡沫。尽管从…

指针数组和数组指针

int p[4] 与 int (p[4]) 等价 &#xff3b;&#xff3d;优先级比高&#xff0c;因此p先和&#xff3b;&#xff3d;结合&#xff0c;表明p是一个数组&#xff0c;且含有4个元素&#xff0c;然后再和结合&#xff0c;表明数组元素为指针&#xff0c;最后指明指针指向的是int类型…

链表的经典问题

链表的经典问题 如何判断两个单链表是否相交&#xff0c;如果相交&#xff0c;找出交点&#xff08;两个链表都不存在环&#xff09; 如果两个单链表相交&#xff0c;那应该呈“Y”字形&#xff0c;也就是从交点以后的部分是两个链表的公共节点。 所以&#xff0c;判断是否相交…

亚马逊、谷歌和微软寸土必争的新战场

作者&#xff1a; Caroline Donnelly 编译&#xff1a;机器之能 张玺摘要&#xff1a;当亚马逊、谷歌与微软都表示要争取所有可能的垂直市场客户时&#xff0c;云服务三巨头在零售市场的竞争变得愈发有趣。云技术在零售市场应用方面表现抢眼&#xff0c;但是竞争问题正在影响客…

duilib环境配置以及简单入门介绍

内容全部为转载&#xff1a; VS2013的编译&#xff0c;https://www.cnblogs.com/Alberl/p/3342030.html duilib框架介绍&#xff0c;以及VS2013配置&#xff0c;创建工程&#xff0c;调试代码部分&#xff1a; https://blog.csdn.net/lanuage/article/details/52040306 https:/…

Android开发之Java集合类性能分析

对于Android开发者来说深入了解Java的集合类很有必要主要是从Collection和Map接口衍生出来的&#xff0c;目前主要提供了List、Set和 Map这三大类的集合&#xff0c;今天就他们的子类在标准情况和多线程下的性能做简单的分析。 Collection接口主要有两种子类分别为List和Set&am…

2019年汽车行业深度投资研究

来源&#xff1a;中泰证券2018年预计我国汽车销售负增长&#xff0c;为30年来首次&#xff0c;批发数据自5月份开始逐步下降&#xff0c;尤其是9月之后,销售增速加速下滑,判断汽车市场弱势的原因和持续时间长短&#xff0c;是思考2019年汽车行业投资策略的前提。我们认为&#…

duilib消息事件产生和分发解释

参考博客&#xff1a;https://www.cnblogs.com/haomiao/p/5055413.html

有没有哪些数学猜想是验证到很大的数以后才发现是错的?

来源&#xff1a;孙天任算数学苑素数的分布密度为 ρ(x)~1/ln(x)&#xff0c;从而在 x 以内的素数个数——通常用 π(x) 表示——为&#xff1a; π(x) ~ Li(x) 其中 Li(x) ≡ ∫ 1/ln(x) dx 是对数积分函数 。这个结果有些读者可能也认出来了&#xff0c;它正是著名的素数定理…

JAVA动态代理(JDK和CGLIB)

JAVA的动态代理 代理模式 代理模式是常用的java设计模式&#xff0c;他的特征是代理类与委托类有同样的接口&#xff0c;代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类&#xff0c;以及事后处理消息等。代理类与委托类之间通常会存在关联关系&#xff0c;一…

duilib消息机制的介绍

参考&#xff1a;https://www.cnblogs.com/redrainblog/p/4209721.html