Ⅱ.INTRODUCTION TO CUDA C

前言

上一节环境配置好了,我们开始吧!

一、A First Program

1. Hello, World!

我们先写一个C语言的 Hello, World! 作为对比

int main(void){printf("Hello, World!\n");return 0;
}

大家应该知道这个代码运行在CPU上吧,我们CPU和系统的内存称作 host,GPU及其内存称作 device。

#include <stdio.h>__global__ void kernel(void){}int main(void){kernel<<<1,1>>>();printf("Hello,World!\n");return 0;
}

这个程序:
① 有一个叫kernal且被 global 修饰的函数
② 调用这个kernal函数用了 <<<1,1>>>

C语言部分的代码就是用vs编译的,CUDA C 这部分,也就是带有 global 的代码,将在GPU上编译(在GPU上执行的函数称为CUDA核函数(Kernel Function))。
(NVIDIA工具将C语言交给C编译器,核函数交给device:函数kernel()将被交给编译device代码的编译器,而main()函数将被交给host编译器)

2. Passing Parameters

#include "stdio.h"__global__ void add(int a, int b, int *c){*c = a+b;
}int main(){int c;int *dev_c;
cudaMalloc((void**)&dev_c, sizeof(int));add<<<1,1>>>(2,7,dev_c);cudaMemcpy(&c,dev_c,sizeof(int),cudaMemcpyDeviceToHost);printf("2+7 = %d\n",c);cudaFree(dev_c);return 0;
}

① 我们可以像C代码那样传递参数调用 global 函数
② 要先在device上申请内存,然后操作后返回给host

我们说一下 cudaMalloc:
和C的malloc很相似,不同的是,这个函数是要在 device – GPU 上申请内存。
第一个参数:
是一个指向指针的指针,因为我们需要新开辟内存的地址
第二个参数:
是内存大小
除了传参不同,这个函数返回值是CUDA中定义的一个错误代码。
CUDA C淡化了主机代码和设备代码之间的差异,这样的话,我们思考一个问题,我们可以在host端使用(解引用) dev_c 吗?
大家思考3秒钟…

当然不能,这是 CUDA 返回过来的,这可是GPU的内存哦。
你使用的话,编译器可是识别不出来的,要小心!
所以这里有几条限制:
① 可以将cudaMalloc()分配的指针传递给在device上执行的函数
② 可以在device代码中使用cudaMalloc()分配的指针进行内存读写操作
③ 可以将cudaMalloc()分配的指针传递给在host上执行的函数
④ 不能在主机代码中使用cudaMalloc()分配的指针进行内存读写操作

这③和④大家觉得是不是有歧义哦,是这样的:③的意思是在host可以传递参数 – 赋值操作是没问题的;④的意思是在host上解引用操作是不行的。大家可以理解吧。同样的道理,host的指针在device中也会出错哦。
cudaFree() 和 cudaMalloc() 相对应,一个释放,一个申请。
下面说一下 cudaMemcpy(dst, src, count, kind) :

  1. 前2个为指针,指向device 和 host 内存
  2. 第三个为拷贝的数据大小
  3. 第四个为拷贝的方向
  4. 返回值是错误代码
    用kind标注这个复制的方向,这次程序里的是 cudaMemcpyDeviceToHost,也就是说源地址是device,目的地址是host。
    反方向的是cudaMemcpyHostToDevice,还有一个很奇怪的cudaMemcpyDeviceToDevice,不知道这和 memcpy 有什么区别…
    这些使用方法大家可以再去英伟达官网上瞅瞅:
    https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__MEMORY.html#group__CUDART__MEMORY_1ga042655cbbf3408f01061652a075e094

2. Querying Devices

我们可以通过代码接口查看设备的情况:

#include "stdio.h"int main() {int count;cudaGetDeviceCount(&count);cudaDeviceProp prop;for (int i = 0; i < count; i++) {cudaGetDeviceProperties(&prop, i);printf("   --- General Information for device %d ---\n", i);printf("Name:  %s\n", prop.name);printf("Compute capability:  %d.%d\n", prop.major, prop.minor);printf("Clock rate:  %d\n", prop.clockRate);printf("Device copy overlap:  ");if (prop.deviceOverlap)printf("Enabled\n");elseprintf("Disabled\n");printf("Kernel execution timeout :  ");if (prop.kernelExecTimeoutEnabled)printf("Enabled\n");elseprintf("Disabled\n");printf("   --- Memory Information for device %d ---\n", i);printf("Total global mem:  %ld\n", prop.totalGlobalMem);printf("Total constant Mem:  %ld\n", prop.totalConstMem);printf("Max mem pitch:  %ld\n", prop.memPitch);printf("Texture Alignment:  %ld\n", prop.textureAlignment);printf("   --- MP Information for device %d ---\n", i);printf("Multiprocessor count:  %d\n",prop.multiProcessorCount);printf("Shared mem per mp:  %ld\n", prop.sharedMemPerBlock);printf("Registers per mp:  %d\n", prop.regsPerBlock);printf("Threads in warp:  %d\n", prop.warpSize);printf("Max threads per block:  %d\n",prop.maxThreadsPerBlock);printf("Max thread dimensions:  (%d, %d, %d)\n",prop.maxThreadsDim[0], prop.maxThreadsDim[1],prop.maxThreadsDim[2]);printf("Max grid dimensions:  (%d, %d, %d)\n",prop.maxGridSize[0], prop.maxGridSize[1],prop.maxGridSize[2]);printf("\n");}
}

在这里插入图片描述
大家见笑了,我这电脑也就是凑活能用😅
大家去这里搜这俩函数,这个 cudaDeviceProp 内容实在太多,就写了这些,大家去这里看详情:
https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__DEVICE.html#group__CUDART__DEVICE

3.Using Device Properties

假设我们需要找特定能力的GPU设备,要怎么办呢?像上面一样,把每个都打印出来一条一条挨着看吗?

int main( void ) {cudaDeviceProp  prop;int dev;cudaGetDevice( &dev );printf( "ID of current CUDA device:  %d\n", dev );memset( &prop, 0, sizeof( cudaDeviceProp ) );prop.major = 1;prop.minor = 3;cudaChooseDevice( &dev, &prop );printf( "ID of CUDA device closest to revision 1.3:  %d\n", dev );cudaSetDevice( dev );
}

我们可以用这个 cudaDeviceProp 设定出我们的需求设备,然后 cudaChooseDevice 去找找看有没有(函数返回码),有的话就去设定。

总结

我们已经在GPU上运行出来了经典的 Hello world !,大家已经入门了,继续加油哦~

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

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

相关文章

CSP初赛知识学习计划(第一天)

计算机知识全解析 一、计算机的发展历程 计算机的发展堪称一部波澜壮阔的科技史诗&#xff0c;其源头可追溯至古老的计算工具。早期&#xff0c;为了满足人类在天文、历法计算以及商业贸易中对数据处理的需求&#xff0c;算盘、算筹等手动计算器械应运而生&#xff0c;它们依…

科大讯飞android面试题及参考答案

如何理解面向对象编程? 面向对象编程(Object - Oriented Programming,简称 OOP)是一种编程范式,它以对象为核心来组织程序结构。 在面向对象编程中,对象是数据和操作这些数据的方法的集合。例如,我们可以把汽车看作一个对象。汽车有自己的属性,像颜色、品牌、速度等,这…

【数据仓库】hadoop web UI 增加账号密码认证

​ 升级了hadoop版本到3.3.6,未配置任何鉴权,默认端口9870 8088开放到了公网,结果没几天就被挖矿攻击了。通过开放的端口提交了很多非法任务到yarn上,并成功在服务器执行了恶意脚本。这次是真实真切的感受了,网络环境的险恶,以前仅仅是别人的案例来提高自己的安全意识,这…

域上的多项式环,整除,相通,互质

例1.已知 (R,,x)为域&#xff0c;请选出正确的说法:(A)(R,,x)也是整区; ABCD (B)R中无零因子; C)R在x运算上满足第一、二、三指数律; (D)R只有平凡理想; (E)R只有平凡子环。 域的特征&#xff1a; 域中&#xff0c;非0元素的加法周期 思考、在模7整数环R,中&#xff0c;…

【0x0014】HCI_Read_Local_Name命令详解

目录 一、命令概述 二、命令格式 三、返回事件及参数说明 3.1. HCI_Command_Complete 事件 3.2. Status 3.3. Local_Name 四、命令执行流程 4.1. 命令发送 4.2. 控制器接收并处理命令 4.3. 控制器返回结果 4.4. 主机接收并解析事件包 4.5. 示例代码 五、应用场景 …

【AI日记】25.01.04 kaggle 比赛 3-3 | 王慧玲与基层女性

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 工作 参加&#xff1a;kaggle 比赛 Forecasting Sticker Sales时间&#xff1a;6 小时 读书 书名&#xff1a;基层女性时间&#xff1a;3 小时原因&#xff1a;虽然我之前就知道这个作者&#xff0c;因为我…

【从零开始入门unity游戏开发之——C#篇40】C#特性(Attributes)和自定义特性

文章目录 前言一、特性&#xff08;Attributes&#xff09;基本概念二、自定义特性1、自定义特性代码示例&#xff1a;2、应用自定义特性&#xff1a;3、解释3.1 **AttributeUsage 特性**3.2 特性的命名3.3 **构造函数**&#xff1a;3.4 **属性**&#xff1a; 4、使用反射获取特…

PG起库逻辑和spill导致起库慢问题分析

问题现象-起库缓慢 版本pg13.2 数据库启动缓慢&#xff0c;startup进程在读取spill文件&#xff0c;文件名在变化。查看spill文件也很慢&#xff0c;ls -l最后跑出来有800w个文件spill文件。 为什么有上千万个spill文件 wal段和LSN的含义 LSN LSN总体是一个64位的bigint&…

【Python学习(六)——While、for、循环控制、指数爆炸】

Python学习&#xff08;六&#xff09;——While、for、循环控制、指数爆炸 本文介绍了While、for、循环控制、指数爆炸&#xff0c;仅作为本人学习时记录&#xff0c;感兴趣的初学者可以一起看看&#xff0c;欢迎评论区讨论&#xff0c;一起加油鸭~~~ 心中默念&#xff1a;Py…

【JS】期约的Promise.all()和 Promise.race()区别

概述 Promise.all() 和 Promise.race() 都是 JavaScript 中处理多个异步操作的 Promise 方法&#xff0c;但它们的行为和返回结果有所不同。 Promise.all()和Promise.race() 1. Promise.all() Promise.all() 接受一个由多个 Promise 实例组成的可迭代对象&#xff08;例如数…

5 Linux 网络编程基础 API

5 Linux 网络编程基础 API 主机字节序和网络字节序 主机&#xff08;小端&#xff09;字节序&#xff1a;0x0201网络&#xff08;大端&#xff09;字节序&#xff1a;0x0102&#xff0c;利于人看 #include <netinet/in.h> unsigned long int htonl(unsigned long int …

基于PyQt5的UI界面开发——图像与视频的加载与显示

介绍 这里我们的主要目标是实现一个基于PyQt5和OpenCV的图像浏览和视频播放应用。用户可以选择本地的图像或视频文件夹&#xff0c;进行图像自动播放和图像切换以及视频播放和调用摄像头等操作&#xff0c;并且支持图像保存功能。项目的核心设计包括文件路径选择、图像或视频的…

JAVA类和对象练习

设计一个矩形类Rectangle&#xff0c;包含私有的数据成员宽度(Width)和高度(Height)&#xff1b;公有的方法double getArea()返回矩形的面积&#xff0c;公有的方法double getPerimeter()返回矩形的周长。 例如: 测试Result Rectangle rectnew Rectangle(8,5); System.out.pr…

云手机+Facebook:让科技与娱乐完美结合

移动互联网时代&#xff0c;Facebook作为全球最大的社交媒体平台之一&#xff0c;早已成为企业、品牌和组织竞相角逐的营销阵地。而云手机的出现&#xff0c;则为Facebook营销注入了新的活力&#xff0c;其独特的优势让营销活动更加高效、精准且灵活。本文将深入探讨云手机在Fa…

全新免押租赁系统打造便捷安全的租赁体验

内容概要 全新免押租赁系统的推出&#xff0c;标志着租赁行业的一次重大变革。这个系统的最大特点就是“免押金”&#xff0c;大大减轻了用户在租赁过程中的经济负担。从此&#xff0c;不再需要为一部手机或其他商品支付高昂的押金&#xff0c;用户只需通过简单的信用评估&…

postman在软件测试中的应用

postman工具概述 Postman 是一款功能强大的 API 开发和测试工具&#xff0c;在软件开发和测试领域应用广泛。开发阶段&#xff0c;可以通过工具进行mock数据测试&#xff0c;方便开发&#xff0c;联调&#xff1b;测试阶段&#xff0c;可以通过不同环境&#xff0c;不同数据进…

电子电气架构 --- 安全相关内容汇总

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…

探索Wiki:开源知识管理平台及其私有化部署

在如今的信息时代&#xff0c;企业和团队的知识管理变得愈发重要。如何有效地存储、整理、共享和协作&#xff0c;是提高团队效率和创新能力的关键因素之一。今天&#xff0c;我要为大家介绍一款非常有用的github上开源知识管理工具——Wiki&#xff0c;并分享它的私有化部署方…

一份完整的软件测试报告如何编写?

在软件开发的过程中&#xff0c;测试是必不可少的环节。然而&#xff0c;测试报告往往是最被忽视的部分。你是否也曾在忙碌的测试工作后&#xff0c;面对一份模糊不清的测试报告感到头疼&#xff1f;一份清晰、完整且结构合理的测试报告&#xff0c;能够帮助团队快速了解软件的…

OpenEuler22.03 LTS SP3 系统优化

OpenEuler22.03 LTS SP3 系统优化 1、关闭selinux setenforce 0 sed -i "s#SELINUXenforcing#SELINUXdisabled#g" /etc/selinux/config 2、禁用swap swapoff -a sed -ri s/.*swap.*/#&/ /etc/fstab 3、公有云机器&#xff0c;必须安全加固 &#xff08;1&…