DAY22:阅读计算模式

3.3. Versioning and Compatibility【版本控制和兼容性】

There are two version numbers that developers should care about when developing a CUDA application: The compute capability that describes the general specifications and features of the compute device (see Compute Capability) and the version of the CUDA driver API that describes the features supported by the driver API and runtime.

The version of the driver API is defined in the driver header file as CUDA_VERSION. It allows developers to check whether their application requires a newer device driver than the one currently installed. This is important, because the driver API is backward compatible, meaning that applications, plug-ins, and libraries (including the C runtime) compiled against a particular version of the driver API will continue to work on subsequent device driver releases as illustrated in Figure 11. The driver API is not forward compatible, which means that applications, plug-ins, and libraries (including the C runtime) compiled against a particular version of the driver API will not work on previous versions of the device driver.

It is important to note that there are limitations on the mixing and matching of versions that is supported:

· Since only one version of the CUDA Driver can be installed at a time on a system, the installed driver must be of the same or higher version than the maximum Driver API version against which any application, plug-ins, or libraries that must run on that system were built.

· All plug-ins and libraries used by an application must use the same version of the CUDA Runtime unless they statically link to the Runtime, in which case multiple versions of the runtime can coexist in the same process space. Note that if nvcc is used to link the application, the static version of the CUDA Runtime library will be used by default, and all CUDA Toolkit libraries are statically linked against the CUDA Runtime.

· All plug-ins and libraries used by an application must use the same version of any libraries that use the runtime (such as cuFFT, cuBLAS, ...) unless statically linking to those libraries.

Figure 11. The Driver API Is Backward but Not Forward Compatible

3.4. Compute Modes

On Tesla solutions running Windows Server 2008 and later or Linux, one can set any device in a system in one of the three following modes using NVIDIA's System Management Interface (nvidia-smi), which is a tool distributed as part of the driver:

· Default compute mode: Multiple host threads can use the device (by calling cudaSetDevice() on this device, when using the runtime API, or by making current a context associated to the device, when using the driver API) at the same time.

· Exclusive-process compute mode: Only one CUDA context may be created on the device across all processes in the system and that context may be current to as many threads as desired within the process that created that context.

· Exclusive-process-and-thread compute mode: Only one CUDA context may be created on the device across all processes in the system and that context may only be current to one thread at a time.

· Prohibited compute mode: No CUDA context can be created on the device.

This means, in particular, that a host thread using the runtime API without explicitly calling cudaSetDevice() might be associated with a device other than device 0 if device 0 turns out to be in the exclusive-process mode and used by another process, or in the exclusive-process-and-thread mode and used by another thread, or in prohibited mode. cudaSetValidDevices() can be used to set a device from a prioritized list of devices.

Note also that, for devices featuring the Pascal architecture onwards (compute capability with major revision number 6 and higher), there exists support for Compute Preemption. This allows compute tasks to be preempted at instruction-level granularity, rather than thread block granularity as in prior Maxwell and Kepler GPU architecture, with the benefit that applications with long-running kernels can be prevented from either monopolizing the system or timing out. However, there will be context switch overheads associated with Compute Preemption, which is automatically enabled on those devices for which support exists. The individual attribute query function cudaDeviceGetAttribute() with the attribute cudaDevAttrComputePreemptionSupported can be used to determine if the device in use supports Compute Preemption. Users wishing to avoid context switch overheads associated with different processes can ensure that only one process is active on the GPU by selecting exclusive-process mode.

Applications may query the compute mode of a device by checking the computeMode device property (see Device Enumeration).

本文备注/经验分享:

Versioning and Compatibility——

这里主要说了:

什么是backword compatible?

这个东西也叫downward compatible,对应的反义词是forward compatible / upword compatible。backward (downword)compatible是向下兼容,也就是兼容低版本。例如这里说的Driver API is backword compatible,就是在高版本的Driver API下,可以兼容以前的老的低版本的Driver API环境。因为环境总是给程序用的,所以用了老版本的Driver API环境的程序,总是被高版本的Driver API所兼容。

(1)这包含直接使用Driver API的应用程序,可以在高版本的Driver API的未来环境下(更新了显卡驱动)运行。 (2)因为Runtime API是构建在Driver API之上的,所以使用了低版本的Runtime所针对的低版本的Driver API的应用,也可以在高版本的Driver API的未来环境下运行。 (3)因为CUDA跟随Runtime自带了一些扩展库(cublas,cusparse,cufft之类的)是针对当前版本的runtime的,而根据(2)runtime已知可以在未来的高版本的Driver API下运行,所以他们也能被未来的高版本的Driver API环境兼容。

所以The Driver API Is Backward Compatible等于是说,在当前的低Driver API版本基础上的所有开发(包括直接的Driver API应用,还是在其之上的Runtime API应用,还是在Runtime API之上的应用(例如只进行cublas计算的应用)),都可以被未来的高版本Driver API保证支持。 这就是为何说Driver API能向下兼容的原因。

但是Driver API不能向上兼容,你不能被设计成一个用高版本的Driver API的应用,编译好了,去要求一台10年前,从来没有更新驱动的老机器,能直接兼容这个高版本的应用。

实际上我们经常看到错误提示是说,驱动版本不够。这个时候我们应当更新驱动。论坛有个例子:

我们的答复:

这个用户感觉自己不能使用高版本的驱动。这种是一种很错误的常见想法的。驱动版本(Driver)可以随时更新到最新的。而开发包可以保持低版本。因为新驱动总是兼容老开发包里的Driver API的接口文件,Runtime API文件,其他补充库文件。这就是刚才说的Driver API是向下兼容的用途。看过手册章节这节的,就不会疑惑能不能随时更新驱动的问题了。

接着说开发包的版本。开发包是死的,从你下载安好的那一刻起,它就是这个版本了。这个版本信息所以说是固定的。可以通过一个常量(cuda.h头文件中的CUDA_VERSION常量)来确定。这也是我们常说的,我们为CUDA XXX开发了应用这里的XXX的含义。第二种则是驱动版本,这个是可变的,但总是兼容以前的低版本下开发的应用(就是刚才说的),因为这个是可变的,动态的,我们可以通过程序,随时通过调用cudaDriverGetVersion()或者cuDriverGetVersion()来获取到当前实际的驱动版本。例如deviceQuery运行的时候,显示的Driver / Runtime: XXX.0 / YYY.0对比,就是从这里来的。如果你运行过deviceQuery的时候看的仔细一点,会发现这点。第三个则是实际的runtime版本。类似的这个可以通过cudaRuntimeGetVersion()来获取。但是因为现在runtime默认总是静态链接(静态链接就是一个库或者runtime变成你的可执行文件的一部分,而不是单独的一个文件。例如一个dll),而静态链接发生在你用当前的开发包开发的时候。所以目前通过这个函数得到的版本,总是和第一个版本相同。而在很早很早之前,runtime默认是动态链接的,是磁盘上单独存在的一个文件(cudart***.dll),当时即使在之前,人们也总是将从开发包中的这个dll跟随exe发布,所以以前动态获取的版本种类3的值,也是等于第一种的静态值的。所以这个函数(cudaRuntimeGetVersion)很大程度上没有用了)。因为总是可以从静态的CUDA_VERSION中获得,值是一样的。 CUDA_VERSION这个常量的格式是XXYY, 例如6.5的CUDA开发包里,这个值是6050, 代表CUDA 6.5 。

请注意这里的6050和CUDA 6.5的对应关系,前者是一个整数,百位以后的是主版本,百位以内的是副版本。没有小数点的。常见的代码中,往往是这个值(CUDA_VERSION)和3020对比。CUDA 3.2版本对Driver和Runtime API接口做了较大的改动。很多代码(特别是老代码)往往需要将这个值和3.2来进行对比。从而选择性的进行一些处理。而CUDA 3.2到今天的CUDA 9.1,软件接口趋于稳定好久了。这是从软件方面说的。硬件上也有一个版本数字,计算能力版本。例如我们常说的计算能力6.1,

计算能力6.0....这个是硬件所支持的特性版本。软件开发包(例如CUDA 9.1)总是包含了它所支持范围的最高硬件特性(计算能力)的卡的所有特性。但是用户需要自行判断实际使用的卡的计算能力,较低的卡的计算能力有些东西不能用的。例如,CUDA开发包,总是提供了动态并行支持,但是实际的硬件的计算能力需要大于等于3.5,才能启用这个特性。否则如果硬件不支持,而硬要使用CUDA软件开发包里的动态并行特性,虽然编译的时候能正常在这个CUDA开发包版本下编译。 但是运行的时候会出错。运行不起来的。所以这是为何说,要自行判断卡的计算能力的原因。不要以为CUDA开发包里的所有特性都能使用,很多需要看卡的。但NV保证了,高版本的计算能力,总是向下兼容低版本的计算能力的所有特性。有的时候为了这个保证,会出现一些奇葩的硬件情况。

之前有人问我普通的家用6.1的卡(Pascal,例如1080Ti), 的half支持情况么? 我当时说,普通的家用的Pascal只有兼容性的半精度支持。你还记得当时我用的词么。这是因为6.0的卡,已经支持half了(GP100,200% half),根据NV的设计理念,6.1的卡必须支持half。 但是实际上,6.0的卡(GP100)是作为训练卡来用的,它有200%的half。而6.1的卡只是用来做推导的,因为它有的只是400%的INT8(6.0的卡没有INT8),但是根据刚才说的,6.1的必须要支持half的,这怎么办?于是NV想出了绝招,6.1的卡的确支持half,但速率只有1/64, 为6.0设计的使用half的程序的确可以在6.1上跑。但是速度极度缓慢....所以实际上,这一代的卡,我们只将6.0作为训练卡来用,而只将6.1作为推理的卡来用(用half训练好用,用tensorrt转换成INT8部署)

Compute Modes——

关于计算模式,这个是专业卡的专有特性。我来简单说一下。一共有4种模式: (1)默认是完全不限制。这个是专业卡的默认模式。也是家用卡的唯一模式。就是说CUDA应用可以随意的使用该卡。你平常见的,我们说的,没有特殊说明的,就是这种模式。

(2)是禁止使用该卡。也就是禁用掉该卡的CUDA能力了。例如一个学校,有用户登录了一个8卡的系统,根据用户的不同,管理员可以设定 成,学生只能使用CPU计算,而当老师登录的时候,可以自动切换成老师可以使用CPU+GPU。这样学生不会黑用烧卡或者用学校资产挖矿,而老师可以充分发挥这台机器的作用,但又不需要人工的每次拆除掉卡,或者安装上卡。注意:专业卡才能这样,普通卡(例如GTX1080Ti)用户只能完全不限制。需要说明的是,Titan系列除外,Titan系列也能。(但是Titan没有ECC啊!!!!一般称为Titan叫做准专业卡。)

(3)将卡只能被1个用户进程使用。对于非计算专业的人来说,你可以理解成1个进程是一个启动的应用。模式3则是进程独占模式,每次只能有1个进程使用该卡。无论你启动多种不同的应用产生的进程,还是1个应用启动多次产生的进程,这些进程里面,只能有1个能用卡的,其他都会运行失败挂掉。这样保证了一个应用的1个进程可以独占一个卡。以便独享该卡的所有性能。不要以为这个是降低了性能,这个设计是有用的,某些情况下,更好的响应性更为关键。能保证性能的稳定,保证性能的独占是很关键的。所以虽然说这个设计貌似降低了总体性能,但既然是专业卡能设计出这个特性,说明还是有人需要的。 类似的,专业卡还能设定禁用Boost,总是以一个较低的频率运行。而家用卡不能禁用掉Boost,随时可以提升性能。专业卡为何要这样设计?有的时候,性能的稳定(总是一个稍微低一点,但是恒定的性能--例如某个处理总是10.1ms完成),好处可能超过了性能可能提升,但不稳定(例如家用卡不能禁用Boost,频率随时可能提升,实际时间轴9.5到10.1之间变动)。 具体原文的说明是,对该设备,系统上的所有进程,只能有一个进程在该卡上创建CUDA Context。这个说法实际上就是等效于刚才的说法(只能有一个应用的1个进程使用该卡)

因为:

  • CUDA必须有CUDA Context才能用卡,所以能否创建context等于能否使用卡(如果你忘记了context是什么,之前你阅读过。往回看)
  • CUDA的Runtime API是隐式初始化+自动管理Context的,而大部分的人总是使用的是Runtime而不是直接Driver API的,这也等效于在一个卡上能否用CUDA。所以这是为何说进程独占模式等于只有1个进程能使用CUDA。而不是原文的解释。(但精确的解释是原文的这种。因为可能有人用CUDA Driver API,需要手工管理context。此时等于原文说法,系统上的1个进程才能为该卡创建1个context)

(4)进程+线程独占模式。

还记得线程是神马吗?一种常见的说法是,为了能充分利用多核心的CPU(或者GPU),你需要多线程。而不能1个线程跑到黑。这个说法很好的描绘了线程的作用----利用CPU或者计算设备的计算能力。但线程的实际定义是,代码流执行的调度实体。(类似的,进程实际上是资源管理的实体)。 你一个CPU进程打开了一个文件,文件句柄是对所有的该进程中的线程可见的。你从一个EXE启动了一个进程,EXE中所包含的数据或者代码(统称资源),是被启动的这个进程所有的。所以说进程是实际上的资源管理的实体。 而线程是执行调度的实体。然后你会有疑惑。我从来没有写过创建线程的代码啊,也从来没用过多线程编程,我就将我的编译出来的exe双击了一下,里面就一个main函数,根据刚才的说法,只是启动了一个进程啊,只是包含一些资源而已,怎么能开始执行下去? 执行的代码流不是线程负责的么?1个进程中总是至少包含1个线程的, 如果你从来没有启动过任何线程,一个CPU上的进程,操作系统将自动为他创建1个线程来从头开始执行的。但是在本手册中,所有的进程都是指的CPU进程,而CUDA进程被总是成为Context。 context等于是GPU上的进程。手册故意不用进程这个词,是为了怕你混淆。

好了。回到刚才的最后一种模式,进程和线程独占模式,这里的进程根据刚才说的,是指host上的进程的。 在这种模式下,该系统上(例如一台GPU服务器),只能同时有1个应用的1个进程中的1个线程,能在同1个时刻使用该卡上的CUDA能力的。如果你不是一个多线程的CPU应用, 此模式将等价于刚才的倒数第二种模式。无区别的。如果你是一个多线程的CPU应用程序,那么该CPU进程中的多个CPU线程, 只能有一个1线程在同一个时刻使用该卡的。类似的,这降低了总体性能。但能保证为一个特定的进程中的特定线程,保证性能的稳定性。 有的时候这个很重要的。专业卡很看重稳定性的,而不是性能。(不过现在大家都黑上深度学习了,跑的越快越好, 所以这个就不注重了。但深度学习不是100%的用户都用的,很多其他领域依然需要稳定性的)。

类似的,这个也是解释后的说法,原文是“该进程中,只有1个线程能将context设定成本线程current的”,这个也涉及到context手工管理的概念(SetCurrent)具体是什么等到了Driver API的时候再说。对于Runtime API用户(大部分用户), 直接理解成只有1个进程中的1个线程能用1个卡的CUDA能力即可。

以上就是 4种模式。其中后三种模式只能专业卡用。

有不明白的地方,请在本文后留言

或者在我们的技术论坛bbs.gpuworld.cn上发帖

原文发布于微信公众号 - 吉浦迅科技(gpusolution)

原文发表时间:2018-05-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

Miguel de Icaza 细说 Mix 07大会上的Silverlight和DLR

Mono之父Miguel de Icaza 详细报道微软Mix 07大会上的Silverlight和DLR ,上面还谈到了Mono and Silverligh...

2707
来自专栏闻道于事

js登录滑动验证,不滑动无法登陆

js的判断这里是根据滑块的位置进行判断,应该是用一个flag判断 <%@ page language="java" contentType="text/html...

6768
来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3105
来自专栏大内老A

The .NET of Tomorrow

Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciti...

31310
来自专栏跟着阿笨一起玩NET

c#实现打印功能

2702
来自专栏张善友的专栏

LINQ via C# 系列文章

LINQ via C# Recently I am giving a series of talk on LINQ. the name “LINQ via C...

2625
来自专栏张善友的专栏

Silverlight + Model-View-ViewModel (MVVM)

     早在2005年,John Gossman写了一篇关于Model-View-ViewModel模式的博文,这种模式被他所在的微软的项目组用来创建Expr...

2948
来自专栏pangguoming

Spring Boot集成JasperReports生成PDF文档

由于工作需要,要实现后端根据模板动态填充数据生成PDF文档,通过技术选型,使用Ireport5.6来设计模板,结合JasperReports5.6工具库来调用渲...

1.2K7
来自专栏落花落雨不落叶

canvas画简单电路图

60811
来自专栏陈仁松博客

ASP.NET Core 'Microsoft.Win32.Registry' 错误修复

今天在发布Asp.net Core应用到Azure的时候出现错误InvalidOperationException: Cannot find compilati...

4828

扫码关注云+社区