CUDA C++程序设计模型

本章介绍了CUDA编程模型背后的主要概念,概述了它们在C++中的暴露方式。在编程接口中给出了CUDA C++的广泛描述。

使用的矢量加法示例的完整代码可以在矢量加法CUDA示例中找到。

一. 内核

CUDA C++通过允许程序员定义C++函数,称为内核,扩展了C++,当调用时,用n个不同的CUDA线程并行执行n次,而不是像常规C++函数那样只执行一次。

一个内核使用了__global__声明说明符来定义,并且使用一个新的<<<…>执行配置语法(参见C++语言扩展)来指定执行给定内核调用的内核的CUDA线程的数量。执行内核的每个线程都有一个唯一的线程ID,可以通过内置变量在内核中访问。

下面的示例代码使用内置变量threadIdx,添加两个大小为N的向量A和B,并将结果存储到向量C中:

// Kernel definition __global__ void VecAdd(float* A, float* B, float* C)

{

int i = threadIdx.x;

C[i] = A[i] + B[i];

}

int main()

{

...

//
Kernel invocation with N threads

VecAdd<<<1, N>>>(A, B,
C);

...

}

二.线程层次结构

为了方便起见,threadIdx是一个三分量向量,因此可以使用一维、二维或三维螺纹索引来识别螺纹,形成一维、二维或三维螺纹块,称为螺纹块。这提供了一种跨域元素(如向量、矩阵或卷积)调用计算的自然方法。

一个线程的索引和它的线程ID以一种简单的方式相互关联:对于一维模块,它们是相同的;对于二维模块(Dx,Dy),索引(x,y)线程的线程ID是(x+ydx);对于三维模块(Dx,Dy,Dz),索引(x,y,z)线程的线程ID是(x+ydx+z Dx Dy)。

例如,下面的代码添加两个大小为NxN的矩阵A和B,并将结果存储到矩阵C中:

// Kernel definition __global__ void MatAdd(float
A[N][N], float
B[N][N], float
C[N][N])

{

int i = threadIdx.x;

int j = threadIdx.y;

C[i][j] = A[i][j] + B[i][j];

}

int main()

{

...

// Kernel invocation
with one block of N * N * 1 threads

int
numBlocks = 1;

dim3
threadsPerBlock(N, N);

MatAdd<<<numBlocks,
threadsPerBlock>>>(A, B,
C);

...

}

每个块的线程数是有限制的,因为块的所有线程都应该位于同一个处理器核心上,并且必须共享该核心的有限内存资源。在当前GPU上,一个线程块最多可以包含1024个线程。但是,内核可以由多个形状相同的线程块执行,因此线程总数等于每个块的线程数乘以块的数量。

块被组织成一维、二维或三维的螺纹块网格,如图1所示。网格中线程块的数量通常由正在处理的数据的大小决定,该大小通常超过系统中处理器的数量。

图1. 螺纹块网格

语法中指定的每个块的线程数和每个网格的块数可以是int或dim3类型。二维块或网格可以在上面的示例中指定。

网格中的每个块都可以由一个一维、二维或三维唯一索引标识,该索引可通过内置的blockIdx变量在内核中访问。线程块的维度可以通过内置的blockDim变量在内核中访问。扩展前面的MatAdd()示例以处理多个块,代码如下所示。

// Kernel definition __global__

void MatAdd(float
A[N][N], float
B[N][N], float
C[N][N])

{

int i = blockIdx.x * blockDim.x + threadIdx.x;

int j = blockIdx.y * blockDim.y + threadIdx.y;

if (i
< N && j < N) C[i][j] = A[i][j] + B[i][j];

}

int main()

{

...

// Kernel invocation

dim3
threadsPerBlock(16, 16);

dim3
numBlocks(N / threadsPerBlock.x, N / threadsPerBlock.y);

MatAdd<<<numBlocks,
threadsPerBlock>>>(A, B,
C);

...

}

16x16(256个线程)的线程块大小虽然在本例中是任意的,但却是常见的选择。网格是用足够的块创建的,每个矩阵元素有一个线程。为了简单起见,本例假设每个维度中每个网格的线程数可以被该维度中每个块的线程数均匀地整除,尽管事实并非如此。线程块需要独立执行:必须能够以任何顺序并行或串联执行它们。

这种独立性要求允许线程块在任意数量的内核上按任意顺序进行调度,使程序员能够编写随内核数量而扩展的代码。

块中的线程可以通过共享一些共享内存来协作,并通过同步它们的执行来协调内存访问。更准确地说,可以通过调用syncthreads()内部函数来指定内核中的同步点;syncthreads()充当一个屏障,块中的所有线程都必须在该屏障上等待,然后才能允许任何线程继续。共享内存给出了一个使用共享内存的示例。除了syncthreads()之外,协作组API还提供了一组丰富的线程同步原语。

为了实现高效的协作,共享内存应该是靠近每个处理器核心的低延迟内存(很像一级缓存),而syncthreads()应该是轻量级的。

三.内存层次结构

CUDA线程可以在执行期间从多个内存空间访问数据,如图2所示。每个线程都有专用的本地内存。每个线程块都有对该块的所有线程可见的共享内存,并且与该块具有相同的生存期。所有线程都可以访问相同的全局内存。

所有线程还可以访问另外两个只读内存空间:常量和纹理内存空间。全局、常量和纹理内存空间针对不同的内存使用进行了优化(请参阅设备内存访问)。对于某些特定的数据格式(请参见纹理和曲面内存),纹理内存还提供不同的寻址模式以及数据过滤。

全局、常量和纹理内存空间在同一个应用程序启动的内核之间是持久的。

图2. 内存层次结构

四.异构程序设计

如图3所示,CUDA编程模型假定CUDA线程在物理上独立的设备上执行,该设备作为运行C++程序的主机的协处理器。例如,当内核在GPU上执行,而C++程序的其余部分在CPU上执行时,情况就是这样。

CUDA编程模型还假设主机和设备都在DRAM中保持各自独立的内存空间,分别称为主机内存和设备内存。因此,程序通过调用CUDA运行时(在编程接口中描述)来管理内核可见的全局、常量和纹理内存空间。这包括设备内存分配和释放,以及主机和设备内存之间的数据传输。

统一内存提供托管内存以桥接主机和设备内存空间。托管内存可以从系统中的所有CPU和GPU访问,作为具有公共地址空间的单个相干内存映像。此功能支持设备内存的超额订阅,并且通过消除在主机和设备上显式镜像数据的需要,可以大大简化移植应用程序的任务。有关统一内存的介绍,请参见统一内存编程。

图3. 异构程序设计

注:串行代码在主机上执行,并行代码在设备上执行。

五.计算能力

设备的计算能力由版本号表示,有时也称为“SM版本”。此版本号标识GPU硬件支持的功能,并由应用程序在运行时用于确定当前GPU上可用的硬件功能和/或指令。计算能力包括主要修订号X和次要修订号Y,并用X.Y表示。

具有相同主要修订号的设备具有相同的核心体系结构。主要版本号为7(基于Volta架构的设备)、6(基于Pascal架构的设备)、5(基于Maxwell架构的设备)、3(基于Kepler架构的设备)、2(基于Fermi架构的设备)和1(基于Tesla架构的设备)。

次要修订号对应于核心架构的增量改进,可能包括新功能。

Turing是计算能力为7.5的设备的架构,是基于Volta架构的增量更新。

启用CUDA的GPU列出了所有启用CUDA的设备及其计算能力。计算能力给出了每个计算能力的技术规范。

注:特定GPU的计算能力版本不应与CUDA版本(如CUDA 7.5、CUDA 8、CUDA 9)混淆,后者是CUDA软件平台的版本。CUDA平台被应用程序开发人员用来创建运行在许多代GPU架构上的应用程序,包括尚未发明的未来GPU架构。虽然CUDA平台的新版本通常通过支持新GPU体系结构的计算能力版本来增加对新GPU体系结构的本机支持,但CUDA平台的新版本通常还包括独立于硬件生成的软件功能。

从CUDA 7.0和CUDA 9.0开始,Tesla和Fermi架构不再受支持。

CUDA C++程序设计模型的更多相关文章

  1. 【CUDA并行程序设计系列(1)】GPU技术简介

    http://www.cnblogs.com/5long/p/cuda-parallel-programming-1.html 本系列目录: [CUDA并行程序设计系列(1)]GPU技术简介 [CUD ...

  2. 《CUDA并行程序设计:GPU编程指南》

    <CUDA并行程序设计:GPU编程指南> 基本信息 原书名:CUDA Programming:A Developer’s Guide to Parallel Computing with ...

  3. C++对象模型笔记之程序设计模型

    C++程序设计模型支持三种程序设计模型 1.程序模型(procedural model) 可以理解为过程化模型,就像C一样 2.抽象数据类型模型(ADT) 数据结构教材里有说过,查了下资料也不是很明确 ...

  4. PL真有意思(八):其它程序设计模型

    前言 在之前几篇我们讨论的语法.语义.命名.类型和抽象适用于所有语言.然而我们的注意力都主要集中在命令式语言上,现在这篇来看看其它范式的语言.函数式和逻辑式语言是最主要的非命令式语言. 函数式语言 命 ...

  5. 【并行计算-CUDA开发】CUDA并行存储模型

    CUDA并行存储模型 CUDA将CPU作为主机(Host),GPU作为设备(Device).一个系统中可以有一个主机和多个设备.CPU负责逻辑性强的事务处理和串行计算,GPU专注于执行高度线程化的并行 ...

  6. CUDA并行计算 | 线程模型与内存模型

    文章目录 前言 CUDA线程模型(如何组织线程) CUDA内存模型(了解不同内存优缺点,合理使用) 前言   CUDA(Compute Unified Device Architecture)是显卡厂 ...

  7. CUDA并行存储模型

    CUDA将CPU作为主机(Host),GPU作为设备(Device).一个系统中可以有一个主机和多个设备.CPU负责逻辑性强的事务处理和串行计算,GPU专注于执行高度线程化的并行处理任务.它们拥有相互 ...

  8. CUDA并行程序设计 开发环境搭建与远程调试

    课题需要用到GPU加速.目前使用的台式电脑只有核心显卡,而实验室有一台服务器装有NVIDIA GTX980独显.因此,想搭建一个CUDA的开发环境,来实现在台式机上面开发cuda程序,程序在服务器而不 ...

  9. 【CUDA 基础】3.1 CUDA执行模型概述

    title: [CUDA 基础]3.1 CUDA执行模型概述 categories: CUDA Freshman tags: CUDA SM SIMT SIMD Fermi Kepler toc: t ...

随机推荐

  1. The 2014 ACM-ICPC Asia Mudanjiang Regional First Round A

    网选A,水题: 这个是水题,只要枚举一遍,看有多少a[i-1]<a[i]>a[i+1],不解释了.

  2. Python中Selenium模块的使用

    目录 Selenium的介绍.配置和调用 Selenium的配置 Selenium的调用 Selenium的使用 定位 定位元素的使用 定位下拉标签元素 在iframe框架之间切换 上传文件 Webd ...

  3. 关于PHP动态的接收传递的GET,POST和COOKIE变量

    0x01 我们知道 PHP 接收的变量最常用的是 GET,POST,COOKIE 这三个变量.GET变量是附在 url 后传输的,而 POST 变量是放在 http 包中传输的,COOKIE 则是浏览 ...

  4. PhpMyWind储存型XSS漏洞练习(CVE-2017-12984)

    0x01 介绍 又是一款开源CMS内容管理系统PhpMyWind,在小于等于5.4版本中存在储存型XSS漏洞.如下图所示,这个就是发生储存型XSS漏洞的代码 0x02 演示 1.第一张图是客户留言时, ...

  5. OGG-Oracle同步Sequence

    一.需求,使用OGG同步软件,将Oracle 11g Sequence实时同步到19c新库中 参考文档 Implementing replication of cyclic sequences in ...

  6. linux当前运行进程

    一:linux查询服务器服务进程 inux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照, 就是执行ps命令的那个时刻的 ...

  7. layui在toolbar使用上传控件在reload后失效的问题解决

    问题描述 ​使用layui中的upload组件来上传文件,将按钮放了表格中的toolbar(头部工具栏中),碰到的问题是:第一次可以实现上传文件,但是第二次再上传文件的时候,点击按钮无效. 解决办法 ...

  8. 【转】Python调用C语言动态链接库

    转自:https://www.cnblogs.com/fariver/p/6573112.html 动态链接库在Windows中为.dll文件,在linux中为.so文件.以linux平台为例说明py ...

  9. spring.framework 版本从4.1.6.RELEASE升到5.0.20.RELEASE

    将org.springframework 使用到的jar 版本号改为5.0.20.RELEASE后运行会报错: Servlet.service() for servlet [springmvc] in ...

  10. Windows服务与会话的理解

    服务 Windows NT操作系统是基于客户/服务器模式的(C/S).将操作系统中最基本的部分放到内核中,而把操作系统的绝大多数部分都放到微内核外面的一组服务器(进程)中实现.如对进程管理的进程管理服 ...