CUDA C编程权威指南(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-18 13:02:49

点击下载

作者:(美)程润伟(John Cheng)

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

CUDA C编程权威指南

CUDA C编程权威指南试读:

前言

欢迎来到用CUDA C进行异构并行编程的奇妙世界!

现代的异构系统正朝一个充满无限计算可能性的未来发展。异构计算正在不断被应用到新的计算领域——从科学到数据库,再到机器学习的方方面面。编程的未来将是异构并行编程的天下!

本书将引领你通过使用CUDA平台、CUDA工具包和CUDA C语言快速上手GPU(图形处理单元)计算。本书中设置的范例与练习也将带你快速了解CUDA的专业知识,助你早日达到专业水平!本书写给谁

本书适用于任何想要利用GPU计算能力来提高应用效率的人。它涵盖了CUDA C编程领域最前沿的技术,并有着以下突出的优势:

·风格简洁

·描述透彻

·大量范例

·优质习题

·覆盖面广

·内容聚焦高性能计算的需求

如果你是一个经验丰富的C程序员,并且想要通过学习CUDA C来提高高性能计算的专业才能,本书中建立在你现有知识之上的例题和习题,将使掌握CUDA C编程更加简单。仅需掌握一些C语言延伸的CUDA知识,你便可以从大量的并行硬件中获益。CUDA平台、编程模型、工具和库将使得异构架构编程变得简捷且高效。

如果你是计算机科学领域以外的专业人士,而且想要通过GPU上的并行编程来最大限度地提高工作效率,并提高应用性能,那么本书正是为你量身打造的。书中的阐述清晰而简明,专人精心设计的示例,使用配置文件驱动的方法,这些都将帮助你深入了解GPU编程并迅速掌握CUDA。

如果你是教授或任何学科的研究者,希望通过GPU计算推进科学发现和创新,本书中将有你找到解决方案的捷径。即使你没有多少编程经验,在并行计算概念和计算机科学的知识方面也不够精通,本书也可带你快速入门异构架构并行编程。

如果你是C语言初学者并且有兴趣探索异构编程,本书也完全适合你,因为它不强制要求读者有丰富的C语言编程经验。即使CUDA C和C语言使用相同的语法,二者的抽象概念和底层硬件也是全然不同的,因而对其中之一的经验并不足以使你在学习另一个时感到轻松。所以,只要你对异构编程有浓厚的兴趣,只要你乐于学习新事物且乐于尝试全新的思维方式,只要你对技术相关的话题有深入探索的热情,本书也完全适合你。

即使你有不少关于CUDA C的经验,本书还是有助于知识更新、探索新工具以及了解最新CUDA功能。虽然本书旨在从零开始培养CUDA的专业人才,但它也含有许多先进的CUDA概念、工具和框架的概述,它们将对CUDA开发人员大有裨益。本书的内容

本书讲解了CUDA C编程的基本概念与技术,用于大幅加速应用程序的性能,并包含了随着CUDA工具包6.0和NVIDIA Kepler GPU一起发布的最新功能。在对从同质架构到异构架构的并行编程模式转变进行了简要介绍之后,本书将引导你学习必要的CUDA编程技能和最佳的练习实践,包含但不仅限于CUDA编程模型、GPU执行模型、GPU内存模型、CUDA流和事件、多GPU编程的相关技术、CUDA感知MPI编程和NVIDIA开发工具。

本书采用一种独特的方法来教授CUDA知识,即将基础性的概念讲解与生动形象的示例相结合,这些示例使用配置文件驱动的方法来指导你实现最佳性能。我们对每一个主题都进行了详尽的讲解,清晰地展示出了采用代码示例形式详细操作的过程。书中不仅教授如何使用基于CUDA的工具,还介绍了如何以抽象编程模型为基础并凭借悟性与直觉对开发过程每一步骤的结果做出解释,从而帮助你快速掌握CUDA的开发流程。

每章围绕一个主题展开讲解,运用可行的代码示例来演示GPU编程的基本功能和技术,这之后就是我们精心设计的练习,以便你进一步探索加深理解。

所有的编程示例都是在装有CUDA 5.0(或更高版本)和Kepler或Fermi GPU的Linux系统上运行的。由于CUDA C是一种跨平台的语言,因而书中的示例在其他平台上也同样适用,比如嵌入式系统、平板电脑、笔记本电脑、个人电脑、工作站以及高性能计算服务器。许多OEM供应商支持各种类型的NVIDIA GPU。本书的结构

本书共有10章,包含了以下主题。

第1章:基于CUDA的异构并行计算

本章首先简要介绍了使用GPU来完善CPU的异构架构,以及向异构并行编程进行的模式转变。

第2章:CUDA编程模型

本章介绍了CUDA编程模型和CUDA程序的通用架构,从逻辑视角解释了在CUDA中的大规模并行计算:通过编程模型直观展示的两层线程层次结构。同时也探讨了线程配置启发性方法和它们对性能的影响。

第3章:CUDA执行模型

本章通过研究成千上万的线程是如何在GPU中调度的,来探讨硬件层面的内核执行问题。解释了计算资源是如何在多粒度线程间分配的,也从硬件视角说明了它如何被用于指导内核设计,以及如何用配置文件驱动方法来开发和优化内核程序。另外,本章还结合示例阐述了CUDA的动态并行化和嵌套执行。

第4章:全局内存

本章介绍了CUDA内存模型,探讨全局内存数据布局,并分析了全局内存的访问模式。本章介绍了各种内存访问模式的性能表现,阐述了统一内存和CUDA 6.0中的新功能是如何简化CUDA编程的,以及如何提高程序员工作效率。

第5章:共享内存和常量内存

本章阐释了共享内存,即管理程序的低延迟缓存,是如何提高内核性能的。它描述了共享内存的优化数据布局,并说明了如何避免较差的性能。最后还说明了如何在相邻线程之间执行低延迟通信。

第6章:流和并发

本章介绍了如何使用CUDA流实现多内核并发执行,如何重叠通信和计算,以及不同的任务分配策略是如何影响内核间的并发的。

第7章:调整指令级原语

本章解释了浮点运算、标准的内部数学函数和CUDA原子操作的性质。它展示了如何使用相对低级别的CUDA原语和编译器标志来优化应用程序的性能、准确度和正确性。

第8章:GPU加速库和OpenACC

本章将介绍实现程序并行的CUDA专用函数库,包括线性代数、傅里叶变换和随机数生成等范例。本章还解释了OpenACC和基于编译器指令的GPU编程模型是如何利用更简单的方法辅助CUDA挖掘GPU计算能力的。

第9章:多GPU编程

本章介绍了支持P2P GPU内存访问的GPUDirect技术,阐述了如何在多个GPU上管理和执行计算问题,还说明了在GPU加速计算集群上的大规模应用是如何利用MPI与GPUDirect RDMA来实现性能线性扩展的。

第10章:程序实现的注意事项

本章介绍了CUDA的开发过程和各种配置文件驱动的优化策略,演示了如何使用CUDA调试工具来调试内核和内存错误,通过案例教你如何将一个传统的C程序一步步移植到CUDA C中,以有助于加强你对于这一方法的理解,同时将此过程可视化,并验证了这些工具。阅读本书前的准备

本书不对GPU作特殊要求,使用本书前也不需要你具备并行编程的相关经验,不过你最好会一些Linux的基本操作。运行本书各示例代码的理想机器环境是:安装有CUDA 6.0工具包的Linux系统,C/C++6.0编译程序和NVIDIA Kepler GPU。

尽管某些使用CUDA 6.0的示例可能需要Kepler GPU,但大多数示例仍需在Fermi设备上运行。它们中的大多数可以使用CUDA 5.5来编译。CUDA工具包的下载

你可以从https://developer.nvidia.com/cuda-toolkit下载CUDA 6.0工具包。

该CUDA工具包包括了NVIDIA GPU编译器、CUDA数学库以及用于调试和优化应用程序性能的工具,此外还有编程指南、用户手册、API参考指南和其他文档,它们都将帮助你快速掌握GPU应用程序的开发。规范

为了使你的阅读体验达到最佳,我们在书中使用了一些规范。对于新出现的术语和重要的词语,在其第一次被引入时,我们会对它们进行突出强调。文中出现的文件名、URL地址和代码表示如下:

我们用以下方式表示代码:

我们按如下方式介绍CUDA运行时的函数:

我们按如下方式显示程序输出:

我们用以下方式给出命令行指令:源代码

在学习本书中的示例时,你可以选择手动输入所有代码或者使用附在本书上的源代码。所有本书中的源代码都可在www.wrox.com/go/procudac下载。在页面上,只要找到本书的标题(通过搜索框查找或直接查看书名列表),然后单击书中的详细信息页面上的代码下载链接,就可以获取书中所有的源代码。

在完成每章结尾的练习时,推荐你利用参考示例代码亲自编写代码。所有练习用的代码文件同样也可从Wrox网站下载。勘误表

尽管我们已竭尽所能来避免书中出现文本或代码错误,然而事实上,难免百密一疏。如果你在阅读本书的过程中发现了如拼写或编码上的错误,并愿意与我们联系进行反馈,我们将不胜感激。若你能帮助勘误,这将会使其他读者免于在困惑中长久徘徊,同时,你也是在帮助我们给读者提供更加高质量的信息。

本书的勘误表可在www.wrox.com/go/procudac处找到。在本书的详细信息页面,点击图书勘误表链接即可。在这个页面上,你可以查看所有已提交并由Wrox的编辑发布的勘误表。致谢

假如没有同事们提供的诸多建议和建设性的批评意见,假如不是朋友们共同出谋划策和鼎力相助,很难想象,我们到底能否顺利给这次出书工作画上完美的句号。

我们在此要向NVIDIA公司致谢,感谢贵公司协办的历场GTC会议,也感谢提供给我们的CUDA技术文件,这些在很大程度上提升了本书的价值和权威性。

我们尤其要感谢NVIDIA公司的两位技术研发工程师——Paulius Micikevicius博士和王鹏博士,本书的编写离不开他们的建议和帮助。同样,特别感谢NVIDIA公司的CUDA首席专家马克·埃伯索尔先生在本书的审查过程中给予的指导和反馈。

我们要向NVIDIA公司的高级产品经理威尔·雷米先生和产品营销员纳迪姆·穆罕默德先生表示感谢,感谢他们在整个过程中不渝的支持和鼓励。

感谢NVIDIA公司的石油天然气总监保罗·霍尔茨豪尔先生在本书初始阶段的大力支持。

我们万分感激历场GTC会议上的演讲人和发言者,感谢你们在GPU计算技术领域的工作和付出。我们已在本书的推荐阅读书目中记录了对你们的称赞。(程润伟)我在工作中应用GPU已有多年,忝列专家行列。这些年来得到过的帮助和指导无数,对此我始终心存感激。特别是戴南浔博士和鲍照博士,他们在地震成像项目上的边界网关协议(BGP)的鼓励、支持和指导。同样,感谢周正振博士、张伟博士、格雷斯张女士和凯杨先生四位同事,他们都出类拔萃,同他们一起工作倍感愉悦。我们的团队同样十分出色,很荣幸能够成为其中的一员。在此,还想特别感谢我博士课程的导师也是国际知名教授三雄根博士,感谢他向我伸出橄榄枝,给予我在日本的大学里任教的宝贵机会,并邀我与他共同执笔完成学术专著,当年我在东京经营一家计算技术类的公司时,在最初的起步阶段三雄根博士曾给予我大力支持。与我一同攻克本书的还有泰和马克斯,很开心与他们合作,在撰写本书的同时,不得不说我也从他们身上学到了许多。还要向我亲爱的妻子乔莉和儿子里克说声谢谢,在过去的一年中,在我为出书工作忙得焦头烂额的许多个夜晚和周末,谢谢他们无条件的爱,谢谢他们的全心支持,谢谢他们的包容和耐心。(泰·麦克切尔)25年来,我一直致力于同软件开发人员一起攻克高性能计算(HPC)这一艰巨任务。我很高兴能够在NVIDIA公司工作,给客户提供更多专业知识来实现GPU的大规模并行。在这里要感谢许多NVIDIA公司的工作人员,尤其是Paulius Micikevicius博士,他具有天才般的洞察力和精益求精的工作态度,纵使手头的项目十分繁重,修改本书的工作也绝不打折扣。当约翰邀请我一同编著一本书来讲解CUDA知识的时候,我欣然应允。NVIDIA公司的高级主管戴维·琼斯批准了我参与这本书的编写,但遗憾的是,戴维在与癌症病魔的斗争中没能坚持到最后。我们向戴维及他的家人深表哀思,即使戴维不幸过世,但他依然激励我们继续前行逐梦。另外,山克·特里维迪和马克·汉密尔顿不断的鼓励也始终是我们前进的动力。由于工作繁重,我还招募了马克斯加入这个项目。约翰和马克斯负责具体编写本书的内容,而我负责技术审校,审校的过程也让我从两位编者那里受益良多,这当真是一件乐事。最后,还应当感谢我的妻子朱迪和我的四个孩子,感谢他们给予我无条件的支持和爱——能够在为自己真心热爱的事业奋斗的同时得到如此的鼓励和鞭策,我是多么的幸运!(马克斯·格罗斯曼)能够与诸多才华横溢的工程师与研究人员合作,能够得到优秀导师的不倦教诲,我感到无比幸运。首先要感谢莱斯大学的维韦克·萨卡教授和整个阿巴内罗研究小组。在那里,我开始涉足高性能计算且进入到CUDA的学术领域。正是维韦克教授与其他团队成员的殷切指导和无私帮助,引领我开启了探索神奇的学术研究世界的大门。另外还要感谢雷普索尔公司的毛里西奥·阿拉亚波罗和格莱迪斯·冈萨雷斯,也正是在他们的指导下所取得的宝贵经验,助我在参与本书编写时感到下笔有神。我相信,本书定能在科研和工程学领域提供实际有益的指导。最后,感谢约翰和泰邀请我参与本书的编写,感谢这段难忘的经历,无论是在CUDA领域还是写作和生活中都给予我无数宝贵经验。

没有技术编辑、项目编辑和审校者不可能有一本高质量的专业书籍的面世。诚挚地感谢我们的组稿编辑玛丽E.詹姆斯,项目编辑马丁V.明纳,文字编辑凯瑟琳·伯特和技术审校张伟、赵超。感谢这支颇具见地与才干的专业编辑团队为本书的成功出版所做的一切。与你们合作完成本书的编写着实愉悦之至。第1章基于CUDA的异构并行计算

本章内容:

·了解异构计算架构

·认识并行程序设计的范例转换

·掌握GPU程序设计的基本要素

·了解CPU和GPU编程的区别

随着新科技和处理方法的普及,高性能计算(HPC)领域也在不断变化,而HPC的定义也随之产生了相应的变化。一般来说,它涉及多个处理器或计算机的使用,以高吞吐量和高效率来完成一个复杂的任务。HPC不仅可以认为是一个计算架构,还可以认为是包括硬件系统、软件工具、编程平台及并行编程范例的一组元素列表。

在过去的十几年中,高性能计算取得了极大的发展,尤其是GPU-CPU异构架构的出现,直接导致了在并行程序设计中一个基本的范例转变。将从本章开始学习异构并行程序设计。1.1 并行计算

在过去的几十年间,人们对并行计算产生了越来越多的兴趣。并行计算的主要目标是提高运算速度。

从纯粹的计算视角来看,并行计算可以被定义为计算的一种形式,在这种形式下,计算机可以同时进行许多运算,计算原则是一个大的问题往往可以被划分为很多可以同时解决的小问题。

从程序员的角度来说,一个很自然的疑问,就是如何将并发计算映射到计算机上。假设你有许多计算资源,并行计算可以被定义为同时使用许多计算资源(核心或计算机)来执行并发计算,一个大的问题可以被分解成多个小问题,然后在不同的计算资源上并行处理这些小问题。并行计算的软件和硬件层面是紧密联系的。事实上,并行计算通常涉及两个不同的计算技术领域。

·计算机架构(硬件方面)

·并行程序设计(软件方面)

计算机架构关注的是在结构级别上支持并行性,而并行编程设计关注的是充分使用计算机架构的计算能力来并发地解决问题。为了在软件中实现并行执行,硬件必须提供一个支持并行执行多进程或多线程的平台。

大多数现代处理器都应用了哈佛体系结构(Harvard architecture),如图1-1所示,它主要由3个部分组成。图 1-1

·内存(指令内存和数据内存)

·中央处理单元(控制单元和算术逻辑单元)

·输入/输出接口

高性能计算的关键部分是中央处理单元(CPU),通常被称为计算机的核心。在早期的计算机中,一个芯片上只有一个CPU,这种结构被称为单核处理器。现在,芯片设计的趋势是将多个核心集成到一个单一的处理器上,以在体系结构级别支持并行性,这种形式通常被称为多核处理器。因此,并行程序设计可以看作是将一个问题的计算分配给可用的核心以实现并行的过程。

当实现一段串行算法时,你可能不需要为了编写一个程序而特意去理解计算机架构的细节。但是,当在多核计算机上执行算法时,对于程序员来说,了解基本的计算机架构的特点就显得非常重要了。要编写一个既正确又高效的并行程序需要对多核体系结构有一个基本的认识。

以下介绍了并行计算的一些基本概念,以及这些概念与CUDA编程设计的联系。1.1.1 串行编程和并行编程

当用计算机程序解决一个问题时,我们会很自然地把这个问题划分成许多的运算块,每一个运算块执行一个指定的任务,如图1-2所示。这样的程序叫作串行程序。图 1-2

有两种方法可以区分两个计算单元之间的关系:有些是有执行次序的,所以必须串行执行;其他的没有执行次序的约束,则可以并发执行。所有包含并发执行任务的程序都是并行程序。如图1-3所示,一个并行程序中可能会有一些串行部分。图 1-3

从程序员的角度来看,一个程序应包含两个基本的组成部分:指令和数据。当一个计算问题被划分成许多小的计算单元后,每个计算单元都是一个任务。在一个任务中,单独的指令负责处理输入和调用一个函数并产生输出。当一个指令处理前一个指令产生的数据时,就有了数据相关性的概念。因此,你可以区分任何两个任务之间的依赖关系,如果一个任务处理的是另一个任务的输出,那么它们就是相关的,否则就是独立的。

在并行算法的实现中,分析数据的相关性是最基本的内容,因为相关性是限制并行性的一个主要因素,而且在现代编程环境下,为了提高应用程序的运行速度,理解这些是很有必要的。在大多数情况下,具有依赖关系的任务之间的独立的关系链为并行化提供了很好的机会。1.1.2 并行性

如今,并行性的应用非常广泛,在编程领域,并行编程设计正在成为主流。多层次的并行性设计是架构设计的驱动力。在应用程序中有两种基本的并行类型。

·任务并行

·数据并行

当许多任务或函数可以独立地、大规模地并行执行时,这就是任务并行。任务并行的重点在于利用多核系统对任务进行分配。

当可以同时处理许多数据时,这就是数据并行。数据并行的重点在于利用多核系统对数据进行分配。

CUDA编程非常适合解决数据并行计算的问题。本书的重点便是如何使用CUDA编程解决数据并行问题。许多处理大数据集的应用可以使用数据并行模型来提高计算单元的速度。数据并行处理可以将数据映射给并行线程。

数据并行程序设计的第一步是把数据依据线程进行划分,以使每个线程处理一部分数据。通常来说,有两种方法可以对数据进行划分:块划分(block partitioning)和周期划分(cyclic partitioning)。在块划分中,一组连续的数据被分到一个块内。每个数据块以任意次序被安排给一个线程,线程通常在同一时间只处理一个数据块。在周期划分中,更少的数据被分到一个块内。相邻的线程处理相邻的数据块,每个线程可以处理多个数据块。为一个待处理的线程选择一个新的块,就意味着要跳过和现有线程一样多的数据块。

图1-4所示为对一维数据进行划分的两个例子。在块划分中,每个线程仅需处理数据的一部分,而在周期划分中,每个线程要处理数据的多个部分。图1-5所示为对二维数据进行划分的3个例子:沿y轴的块划分,沿x轴和y轴的块划分,以及沿x轴的周期划分。其余的划分方式为沿x轴的块划分,沿x轴和y轴的周期划分,以及沿y轴的周期划分留作练习。图 1-4图 1-5

通常,数据是在一维空间中存储的。即便是多维逻辑数据,仍然要被映射到一维物理地址空间中。如何在线程中分配数据不仅与数据的物理储存方式密切相关,并且与每个线程的执行次序也有很大关系。组织线程的方式对程序的性能有很大的影响。数据划分

对数据划分有两种基本的方法:

·块划分:每个线程作用于一部分数据,通常这些数据具有相同大小。

·周期划分:每个线程作用于数据的多部分。

程序性能通常对块的大小比较敏感。块划分与周期划分中划分方式的选择与计算机架构有密切关系。具体实例详见本书其他章节。1.1.3 计算机架构

有多种不同的方法可以对计算机架构进行分类。一个广泛使用的分类方法是弗林分类法(Flynn’s Taxonomy),它根据指令和数据进入CPU的方式,将计算机架构分为4种不同的类型(如图1-6所示)。

·单指令单数据(SISD)

·单指令多数据(SIMD)

·多指令单数据(MISD)

·多指令多数据(MIMD)图 1-6

SISD指的是传统计算机:一种串行架构。在这种计算机上只有一个核心。在任何时间点上只有一个指令流在处理一个数据流。

SIMD是一种并行架构类型。在这种计算机上有多个核心。在任何时间点上所有的核心只有一个指令流处理不同的数据流。向量机是一种典型的SIMD类型的计算机,现在大多数计算机都采用了SIMD架构。SIMD最大的优势或许就是,在CPU上编写代码时,程序员可以继续按串行逻辑思考但对并行数据操作实现并行加速,而其他细节则由编译器来负责。

MISD类架构比较少见,在这种架构中,每个核心通过使用多个指令流处理同一个数据流。

MIMD是一种并行架构,在这种架构中,多个核心使用多个指令流来异步处理多个数据流,从而实现空间上的并行性。许多MIMD架构还包括SIMD执行的子组件。

为了实现以下目的,在架构层次上已经取得了许多进展。

·降低延迟

·提高带宽

·提高吞吐量

延迟是一个操作从开始到完成所需要的时间,常用微秒来表示。带宽是单位时间内可处理的数据量,通常表示为MB/s或GB/s。吞吐量是单位时间内成功处理的运算数量,通常表示为gflops(即每秒十亿次的浮点运算数量),特别是在重点使用浮点计算的科学计算领域经常用到。延迟用来衡量完成一次操作的时间,而吞吐量用来衡量在给定的单位时间内处理的操作量。

计算机架构也能根据内存组织方式进行进一步划分,一般可以分成下面两种类型。

·分布式内存的多节点系统

·共享内存的多处理器系统

在多节点系统中,大型计算引擎是由许多网络连接的处理器构成的。每个处理器有自己的本地内存,而且处理器之间可以通过网络进行通信。图1-7所示为一个典型的分布式内存的多节点系统,这种系统常被称作集群。图 1-7

多处理器架构的大小通常是从双处理器到几十个或几百个处理器之间。这些处理器要么是与同一个物理内存相关联(如图1-8所示),要么共用一个低延迟的链路(如PCI-Express或PCIe)。尽管共享内存意味着共享地址空间,但并不意味着它就是一个独立的物理内存。这样的多处理器不仅包括由多个核心组成的单片机系统,即所谓的多核系统,而且还包括由多个芯片组成的计算机系统,其中每一个芯片都可能是多核的。目前,多核架构已经永久地取代了单核架构。图 1-8“众核”(many-core)通常是指有很多核心(几十或几百个)的多核架构。近年来,计算机架构正在从多核转向众核。

GPU代表了一种众核架构,几乎包括了前文描述的所有并行结构:多线程、MIMD(多指令多数据)、SIMD(单指令多数据),以及指令级并行。NVIDIA公司称这种架构为SIMT(单指令多线程)。

GPU和CPU的来源并不相同。历史上,GPU是图形加速器。直到最近,GPU才演化成一个强大的、多用途的、完全可编程的,以及任务和数据并行的处理器,它非常适合解决大规模的并行计算问题。GPU核心和CPU核心

尽管可以使用多核和众核来区分CPU和GPU的架构,但这两种核心是完全不同的。

CPU核心比较重,用来处理非常复杂的控制逻辑,以优化串行程序执行。

GPU核心较轻,用于优化具有简单控制逻辑的数据并行任务,注重并行程序的吞吐量。1.2 异构计算

最初,计算机只包含用来运行编程任务的中央处理器(CPU)。近年来,高性能计算领域中的主流计算机不断添加了其他处理元素,其中最主要的就是GPU。GPU最初是被设计用来专门处理并行图形计算问题的,随着时间的推移,GPU已经成了更强大且更广义的处理器,在执行大规模并行计算中有着优越的性能和很高的效率。

CPU和GPU是两个独立的处理器,它们通过单个计算节点中的PCI-Express总线相连。在这种典型的架构中,GPU指的是离散的设备从同构系统到异构系统的转变是高性能计算史上的一个里程碑。同构计算使用的是同一架构下的一个或多个处理器来执行一个应用。而异构计算则使用一个处理器架构来执行一个应用,为任务选择适合它的架构,使其最终对性能有所改进。

尽管异构系统比传统的高性能计算系统有更大的优势,但目前对这种系统的有效利用受限于增加应用程序设计的复杂性。而且最近得到广泛关注的并行计算也因包含异构资源而增加了复杂性。

如果你刚开始接触并行编程,那么这些性能的改进和异构架构中可用的软件工具将对你以后的编程有很大帮助。如果你已经是一个很好的并行编程程序员了,那么适应并行异构架构的并行编程是很简单的。1.2.1 异构架构

一个典型的异构计算节点包括两个多核CPU插槽和两个或更多个的众核GPU。GPU不是一个独立运行的平台而是CPU的协处理器。因此,GPU必须通过PCIe总线与基于CPU的主机相连来进行操作,如图1-9所示。这就是为什么CPU所在的位置被称作主机端而GPU所在的位置被称作设备端。图 1-9

一个异构应用包括两个部分。

·主机代码

·设备代码

主机代码在CPU上运行,设备代码在GPU上运行。异构平台上执行的应用通常由CPU初始化。在设备端加载计算密集型任务之前,CPU代码负责管理设备端的环境、代码和数据。

在计算密集型应用中,往往有很多并行数据的程序段。GPU就是用来提高这些并行数据的执行速度的。当使用CPU上的一个与其物理上分离开的硬件组件来提高应用中的计算密集部分的执行速度时,这个组件就成为了一个硬件加速器。GPU可以说是最为常见的硬件加速器。

以下产品应用了NVIDIA公司的GPU计算平台。

·Tegra

·GeForce

·Quadro

·Tesla

Tegra系列产品是专为移动和嵌入式设备而设计的,如平板电脑和手机,GeForce面向图形用户,Quadro用于专业绘图设计,Tesla用于大规模的并行计算。Fermi是Tesla系列产品中的一种,用作GPU加速器,近来在高性能计算中获得了广泛应用。NVIDIA于2010年发布的Fermi架构是世界上第一款完整的GPU计算架构。Fermi GPU加速器的出现让许多领域的高性能计算有了新的发展,如地震资料处理、生化模拟、天气和气候建模、信号处理、计算金融、计算机辅助工程、计算流体力学和数据分析等。Fermi之后的新一代GPU计算架构Kepler,于2012年秋季发布,其处理能力相比以往的GPU有很大提升,并且提供了新的方法来优化和提高GPU并行工作的执行,有望将高性能计算提升到新的高度。Tegra K1包含一个Kepler GPU,并能满足GPU在嵌入式应用中的一切要求。

以下是描述GPU容量的两个重要特征。

·CUDA核心数量

·内存大小

相应的,有两种不同的指标来评估GPU的性能。

·峰值计算性能

·内存带宽

峰值计算性能是用来评估计算容量的一个指标,通常定义为每秒能处理的单精度或双精度浮点运算的数量。峰值性能通常用GFlops(每秒十亿次浮点运算)或TFlops(每秒万亿次浮点运算)来表示。内存带宽是从内存中读取或写入数据的比率。内存带宽通常用GB/s表示。表1-1所示为Fermi架构和Kepler架构的一些性能指标。表1-1 Fermi和Kepler

①单精度浮点性能的峰值。

本书中的大多数示例程序均可在Fermi和Kepler两种GPU上运行。一些示例需要在只包含Kepler GPU中特殊的架构上运行。计算能力

NVIDIA使用一个术语“计算能力”(compute capability)来描述整个Tesla系列的GPU加速器的硬件版本。表1-2给出了Tesla产品的各个版本及其计算能力。

具有相同主版本号的设备具有相同的核心架构。

·主版本NO.3是Kepler类架构。

·主版本NO.2是Fermi类架构。

·主版本NO.1是Tesla类架构。

NVIDIA发布的第一版GPU包含了与整个Tesla GPU加速器系列相同的名称“Tesla”。

本书中的所有示例都需要版本2以上的计算能力。表1-2 Tesla GPU计算产品的计算能力1.2.2 异构计算范例

GPU计算并不是要取代CPU计算。对于特定的程序来说,每种计算方法都有它自己的优点。CPU计算适合处理控制密集型任务,GPU计算适合处理包含数据并行的计算密集型任务。GPU与CPU结合后,能有效提高大规模计算问题的处理速度与性能。CPU针对动态工作负载进行了优化,这些动态工作负载是由短序列的计算操作和不可预测的控制流程标记的;而GPU在其他领域内的目的是:处理由计算任务主导的且带有简单控制流的工作负载。如图1-10所示,可以从两个方面来区分CPU和GPU应用的范围。图 1-10

·并行级

·数据规模

如果一个问题有较小的数据规模、复杂的控制逻辑和/或很少的并行性,那么最好选择CPU处理该问题,因为它有处理复杂逻辑和指令级并行性的能力。相反,如果该问题包含较大规模的待处理数据并表现出大量的数据并行性,那么使用GPU是最好的选择。因为GPU中有大量可编程的核心,可以支持大规模多线程运算,而且相比CPU有较大的峰值带宽。

因为CPU和GPU的功能互补性导致了CPU+GPU的异构并行计算架构的发展,这两种处理器的类型能使应用程序获得最佳的运行效果。因此,为获得最佳性能,你可以同时使用CPU和GPU来执行你的应用程序,在CPU上执行串行部分或任务并行部分,在GPU上执行数据密集型并行部分,如图1-11所示。图 1-11

这种代码的编写方式能保证GPU与CPU相辅相成,从而使CPU+GPU系统的计算能力得以充分利用。为了支持使用CPU+GPU异构系统架构来执行应用程序,NVIDIA设计了一个被称为CUDA的编程模型。这个新的编程模型是本书将要介绍的重点。图 1-11CPU线程与GPU线程

CPU上的线程通常是重量级的实体。操作系统必须交替线程使用启用或关闭CPU执行通道以提供多线程处理功能。上下文的切换缓慢且开销大。

GPU上的线程是高度轻量级的。在一个典型的系统中会有成千上万的线程排队等待工作。如果GPU必须等待一组线程执行结束,那么它只要调用另一组线程执行其他任务即可。

CPU的核被设计用来尽可能减少一个或两个线程运行时间的延迟,而GPU的核是用来处理大量并发的、轻量级的线程,以最大限度地提高吞吐量。

现在,四核CPU上可以同时运行16个线程,如果CPU支持超线程可支持多至32个线程。

现代的NVIDIA GPU在每个多处理器上最多可以并发支持1536个同时活跃的线程。有16个多处理器的GPU,可以并发支持超过24000个同时活跃的线程。1.2.3 CUDA:一种异构计算平台

CUDA是一种通用的并行计算平台和编程模型,它利用NVIDIA GPU中的并行计算引擎能更有效地解决复杂的计算问题。通过使用CUDA,你可以像在CPU上那样,通过GPU来进行计算。

CUDA平台可以通过CUDA加速库、编译器指令、应用编程接口以及行业标准程序语言的扩展(包括C、C++、Fortran、Python,如图1-12所示)来使用。本书重点介绍CUDA C的编程。

CUDA C是标准ANSI C语言的一个扩展,它带有的少数语言扩展功能使异构编程成为可能,同时也能通过API来管理设备、内存和其他任务。CUDA还是一个可扩展的编程模型,它使程序能对有不同数量核的GPU明显地扩展其并行性,同时对熟悉C编程语言的程序员来说也比较容易上手。图 1-12

CUDA提供了两层API来管理GPU设备和组织线程,如图1-13所示。图 1-13

·CUDA驱动API

·CUDA运行时API

驱动API是一种低级API,它相对来说较难编程,但是它对于在GPU设备使用上提供了更多的控制。运行时API是一个高级API,它在驱动API的上层实现。每个运行时API函数都被分解为更多传给驱动API的基本运算。运行时API与驱动API

运行时API和驱动API之间没有明显的性能差异。在设备端,内核是如何使用内存以及你是如何组织线程的,对性能有更显著的影响。

这两种API是相互排斥的,你必须使用两者之一,从两者中混合函数调用是不可能的。本书中所有例子都使用运行时API。

一个CUDA程序包含了以下两个部分的混合。

·在CPU上运行的主机代码

·在GPU上运行的设备代码

NVIDIA的CUDA nvcc编译器在编译过程中将设备代码从主机代码中分离出来。如图1-14所示,主机代码是标准的C代码,使用C编译器进行编译。设备代码,也就是核函数,是用扩展的带有标记数据并行函数关键字的CUDA C语言编写的。设备代码通过nvcc进行编译。在链接阶段,在内核程序调用和显示GPU设备操作中添加CUDA运行时库。图 1-14

CUDA nvcc编译器是以广泛使用LLVM开源编译系统为基础的。在GPU加速器的支持下,通过使用CUDA编译器SDK,你可以创建或扩展编程语言,如图1-15所示。

CUDA平台也是支持多样化并行计算生态系统的基础,如图1-16所示。现在,随着越来越多的公司可以提供全球性的工具、服务和解决方案,CUDA生态系统迅速成长。如果你想在GPU上建立你的应用程序,强化GPU性能的最简单方法是使用CUDA工具包(http://deve-loper.nvidia.com/cuda-toolkit),它为C和C++开发人员提供了一个综合的开发环境。CUDA工具包包括编译器、数学库,以及调试和优化应用程序性能的工具。同时提供了代码样例、编程指南、用户手册、API参考文档和其他帮助你入门的文档。图 1-15图 1-161.3 用GPU输出Hello World

学习一个新编程语言的最好方法就是使用这种新语言来编写程序。在本节,你将开始编写在GPU上运行的第一个内核代码。像其他任何编程语言一样编写GPU上的第一个程序是输出字符串“Hello World”。

如果这是你第一次使用CUDA,在Linux系统中,你可能想使用以下命令来检查CUDA编译器是否正确安装:

通常的结果可能是:

你还需要检查你的机器上是否安装了GPU加速卡。对此你可以在Linux系统上使用以下命令:

通常的结果是:

在这个例子中,你安装了两个GPU卡(不同的用户配置可能有所不同,因此显示结果会有所差异)。现在你要准备好写你的第一个CUDA C程序。写一个CUDA C程序,你需要以下几个步骤:

1.用专用扩展名.cu来创建一个源文件。

2.使用CUDA nvcc编译器来编译程序。

3.从命令行运行可执行文件,这个文件有可在GPU上运行的内核代码。

首先,我们编写一个C语言程序来输出“Hello World”,如下所示:

把代码保存到hello.cu中,然后使用nvcc编译器来编译。CUDA nvcc编译器和gcc编译器及其他编译器有相似的语义。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载