《CUDA高性能并行计算》----2.2 需要知道的CUDA API和C语言拓展

简介: CUDA并行所需要的基本任务包含以下几点: 使用特定的网格维度加载核函数(线程块和线程的数目)。 明确哪些函数编译后运行在设备(GPU)上、主机(CPU)上,或者两者之上。 访问和运用线程块和线程的计算索引值。 分配内存和传输数据。

本 节 书 摘 来 自 华 章 出 版 社 《CUDA高性能并行计算》 一 书 中 的 第2章,第2.2节, 作 者 CUDA for Engineers: An Introduction to High-Performance Parallel Computing[美] 杜安·斯托尔蒂(Duane Storti)梅特·尤尔托卢(Mete Yurtoglu) 著,苏统华 项文成 李松泽 姚宇鹏 孙博文 译 , 更 多 章 节 内 容 可 以 访 问 云 栖 社 区 “华 章 计 算 机” 公 众 号 查 看。

2.2 需要知道的CUDA API和C语言拓展

CUDA并行所需要的基本任务包含以下几点:

使用特定的网格维度加载核函数(线程块和线程的数目)。

明确哪些函数编译后运行在设备(GPU)上、主机(CPU)上,或者两者之上。

访问和运用线程块和线程的计算索引值。

分配内存和传输数据。

让我们从介绍核函数的加载开始。正如上面讨论的,核函数是一种特殊的函数,加载核函数与常规的函数调用看起来很像,详细来说,加载核函数从一个函数名开始,比如aKernel,然后以一个包含了以逗号分开的参数列表的括号结尾。现在我们来看一下编程语言拓展:为了自然地表达并行并且声明计算网格,在函数名和含有参数的括号中间加入了网格的维度和线程块的维度(被放在三个尖括号中):

需要注意的是,Dg、网格中的线程块数和Db、线程块中的线程数目,一起组成了加载核函数中的执行配置和维度的声明。

这构成了加载一个和函数的语法,但是如何声明一个从主机端调用但是在设备端执行的函数仍有一些疑问。CUDA使用在函数前面添加下面的一个函数标识符来作为区分:

__global__是标志着和函数的标识符(可以在主机端调用并在设备端执行)。

__host__函数从主机端调用在主机端执行。(这是一个默认的限定符,通常被省略。)

__device__函数从设备端调用并在设备端执行。(从核函数中调用的函数需要有__device__限定符。)

在函数头添加__host____device__函数会让系统分别编译这个函数的主机版本和设备版本。


68428a2f88b07d466995c0c115ce6046f1ba8eaa

核函数有几个值得注意的权限和限制:
核函数不能带有返回值,因此返回类型通常为void。并且核函数需如下声明:

核函数提供了对于每一个线程块和线程的维度数和索引变量。

维度数目变量:
gridDim声明了网格中的线程块数目。

blockDim声明了每个线程块中的线程数目。

索引变量:
blockIdx给出了这个线程块在网格中的索引。

threadIdx给出了这个线程在线程块中的索引。

在GPU上执行的核函数通常不能访问主机端CPU可以访问的内存中的数据。


c8d8b99a681345ab708d77051d19ae3ed8dc1c8e

CUDA运行时API提供了一些可以将输入数据传输到设备端和将结果传回到主机端的函数,如下所示:

cudaMalloc()函数可以分配设备端内存。

cudaMemcpy()将数据传入或传出设备。

cudaFree()释放掉设备中不再使用的内存。

核函数并行进行多次运算,但是它们也放弃了对执行顺序的控制。CUDA为需要同步和并发执行时提供了相应的函数:

__syncThreads()可以在一个线程块中进行线程同步。

cudaDeviceSynchronize()函数可以有效地同步一个网格中的所有线程。

原子操作,例如atomicAdd(),可以防止多线程并发访问一个变量时造成的冲突。

除了上文介绍的函数和标识符以外,CUDA同时提供了一些额外的有用的数据类型:

size_t:代表内存大小的专用变量类型。

cudaError_t:错误处理的专用变量。

向量类型:CUDA将标准C的向量数据类型拓展到了4个。独立的组件通过后缀.x、.y、.z和.w进行访问。


379962e59cdf64eb114769d3cc935ec74544257c
相关文章
|
7月前
|
API 数据库 C语言
【C/C++ 数据库 sqlite3】SQLite C语言API返回值深入解析
【C/C++ 数据库 sqlite3】SQLite C语言API返回值深入解析
281 0
|
19天前
|
SQL 缓存 测试技术
构建高性能RESTful API:最佳实践与避坑指南###
—— 本文深入探讨了构建高性能RESTful API的关键技术要点,从设计原则、状态码使用、版本控制到安全性考虑,旨在为开发者提供一套全面的最佳实践框架。通过避免常见的设计陷阱,本文将指导你如何优化API性能,提升用户体验,确保系统的稳定性和可扩展性。 ###
55 12
|
2月前
|
中间件 Go API
使用Go语言构建高性能RESTful API
在现代软件开发中,RESTful API因其简洁和高效而成为构建网络服务的首选。Go语言以其并发处理能力和高性能著称,是开发RESTful API的理想选择。本文将介绍如何使用Go语言构建RESTful API,包括基础的路由设置、中间件的使用、数据验证、错误处理以及性能优化。通过实际代码示例,我们将展示Go语言在API开发中的强大功能和灵活性。
|
3月前
|
Go API 开发者
深入探讨:使用Go语言构建高性能RESTful API服务
在本文中,我们将探索Go语言在构建高效、可靠的RESTful API服务中的独特优势。通过实际案例分析,我们将展示Go如何通过其并发模型、简洁的语法和内置的http包,成为现代后端服务开发的有力工具。
|
2月前
|
消息中间件 缓存 API
构建高性能RESTful API的策略与实践
构建高性能RESTful API的策略与实践
38 0
|
4月前
|
缓存 API 数据库
打造高性能后端API:从设计到部署的实战之旅
【8月更文挑战第31天】在数字化时代的浪潮中,后端API成为了连接用户、数据与服务的桥梁。本文将带领读者踏上一段从API设计、开发到部署的旅程,通过实际案例分析,揭示如何构建一个高性能的后端系统。我们将探讨现代后端架构的关键要素,包括RESTful API设计原则、数据库优化技巧、缓存策略、以及容器化部署的实践。文章旨在为开发者提供一套实用的方法论,帮助他们在面对复杂业务需求时,能够设计出既高效又可扩展的后端服务。
|
4月前
|
存储 缓存 编译器
【C语言篇】scanf和printf万字超详细介绍(基本加拓展用法)(下篇)
scanf处理⽤⼾输⼊的原理是,⽤⼾的输⼊先放⼊缓存,等到按下回⻋键后,按照占位符对缓存进⾏解读。 解读⽤⼾输⼊时,会从上⼀次解读遗留的第⼀个字符开始,直到读完缓存,或者遇到第⼀个不符合条件的字符为⽌。
176 2
|
4月前
|
存储 C语言
【C语言篇】scanf和printf万字超详细介绍(基本加拓展用法)(上篇)
printf 的作⽤是将参数⽂本输出到屏幕。它名字⾥⾯的 f 代表 format (格式化),表⽰可以定制输出⽂本的格式。
88 1
|
4月前
|
UED 存储 自然语言处理
【语言无界·体验无疆】解锁Vaadin应用全球化秘籍:从代码到文化,让你的应用畅游世界每一个角落!
【8月更文挑战第31天】《国际化与本地化实战:构建多语言支持的Vaadin应用》详细介绍了如何使用Vaadin框架实现应用的国际化和本地化,提升用户体验和市场竞争力。文章涵盖资源文件的创建与管理、消息绑定与动态加载、日期和数字格式化及文化敏感性处理等方面,通过具体示例代码和最佳实践,帮助开发者构建适应不同语言和地区设置的Vaadin应用。通过这些步骤,您的应用将更加灵活,满足全球用户需求。
58 0
|
4月前
|
API 数据库 UED
全面解析构建高性能API的秘诀:运用Entity Framework Core与异步编程提升Web应用响应速度及并发处理能力的详细指南与实践案例
【8月更文挑战第31天】本文详细介绍了如何利用 Entity Framework Core (EF Core)的异步编程特性构建高性能 API。通过创建基于 EF Core 的 .NET Core Web API 项目,配置数据库上下文,并定义领域模型,文章展示了如何使用异步方法进行数据查询、加载相关实体及事务处理。具体代码示例涵盖了 GET、POST、PUT 和 DELETE 操作,全面展示了 EF Core 异步编程的优势,有助于提升 API 的响应速度和处理能力。
48 0