草庐IT

GPU并行效率问题——通过MPS提升GPU计算收益

Dancen 2024-03-15 原文

现象描述

使用V100_32G型号的GPU运行计算程序时,发现程序每5秒能够完成一次任务,耗费显存6G。

鉴于V100 GPU拥有32G的显存,还有很多空闲,决定同时运行多个计算程序,来提升GPU计算收益。

然而,这一切都是想当然的。运行多个计算程序时,每个计算程序的处理耗时大大增加。例如,同时运行4个计算程序,则这些计算程序差不多需要20秒才能完成一次任务,几乎是单进程运行时的4倍,算上并行的收益,20秒能够处理4个任务,这和单进程的计算程序的运行效果几乎没有区别,也就是说,多进程并行和单进程运行完全没有效率的提升。

单进程:

5秒/任务

4进程:

20秒/任务

问题原因

一种可能的解释是,当前的计算程序对GPU的利用率很高,单进程执行时已经几乎占用全部的GPU计算核心,因此,多进程执行实际上也只相当于单进程执行,但事实并非如此。

与单核CPU的调度方式类似,在单一时间片内,GPU中只会有一个GPU进程在运行,当多个进程同时把CUDA任务发射到GPU时,GPU使用时间片轮转调度的方式,多个GPU进程之间在微观层面上是交替运行的。这也导致,在某一个时间片内,如果正在运行的GPU进程没有很好地利用计算资源,那么空闲的计算资源就是浪费掉的。也就是说,GPU并没有真正地进行并发计算。再加上不同进程的上下文切换,也带来了更多的时间开销。

MPS简介

Nvidia针对多进程并发执行的场景推出了多进程服务解决方案-MPS,该方案可以做到空分复用。

MPS的运行模式为一个MPS Server和多个MPS Client。MPS Server通过一个CUDA Context管理GPU硬件资源,每个MPS Client对应一个GPU进程,多个MPS Client会将它们的任务通过MPS Server传入GPU,MPS Server可以把多个进程的上下文进行融合,合并后的进程将多个进程的Kernel交织到一起进行发射,从而越过了硬件时间分片调度的限制,使得它们的CUDAkernels实现真正意义上的并行,这可以带来以下好处:

> 进程之间无需上下文切换,减少了上下文切换的开销。

> 同一个时间片里,多个进程的kernel一起执行,提升了GPU计算资源的利用率。

MPS在单进程对GPU利用率不高的情况下是非常有用的,MPS的缺点则在于故障隔离问题,本文忽略。

MPS的使用

1. 启动MPS。

a. 设置GPU计算模式为exclusive mode。

设置GPU compute mode 为 exclusive mode (非必须,但推荐设置,设置后有可能使得原本正常的计算程序运行失败)

nvidia-smi -i 0 -c EXCLUSIVE_PROCESS

注意:

执行该设置需要root权限。

除非使用-i参数指定单个GPU,否则将影响所有GPU。

此操作的效果立即生效,但它不会在主机重新启动后持续存在,主机重新启动后,计算模式将重置为“DEFAULT”。

补充说明:

-c选项设置目标GPU的计算模式。计算模式标志指示单个或多个计算应用程序是否可以在GPU上运行。

0/Default:表示每个设备允许多个上下文。

1/Exclusive_Thread:已弃用,改用 Exclusive_Process。

2/Prohibited:表示每台设备不允许使用任何上下文(无计算应用程序)。

3/Exclusive_Process:表示每个设备只允许一个上下文,一次可从多个线程使用。

b. 启动MPS守护进程。

服务器中有多个GPU时,选择特定的GPU运行程序可在程序运行命令前使用:CUDA_VISIBLE_DEVICES=0命令。0为服务器中的GPU编号,可以为0, 1, 2, 3等,表明对程序可见的GPU编号。

CUDA_VISIBLE_DEVICES=1

只有编号为1的GPU对程序是可见的,在代码中gpu[0]指的就是这块GPU

CUDA_VISIBLE_DEVICES=0,2,3

只有编号为0,2,3的GPU对程序是可见的,在代码中gpu[0]指的是第0块,gpu[1]指的是第2块,gpu[2]指的是第3块

CUDA_VISIBLE_DEVICES=2,0,3

只有编号为0,2,3的GPU对程序是可见的,但是在代码中gpu[0]指的是第2块,gpu[1]指的是第0块,gpu[2]指的是第3块

首先设置CUDA变量:

export CUDA_VISIBLE_DEVICES=0

export CUDA_MPS_PIPE_DIRECTORY=/tmp/nvidia-mps

(cuda 7.0以后非必须)

export CUDA_MPS_LOG_DIRECTORY=/tmp/nvidia-log

(cuda 7.0以后非必须)

启动mps:

nvidia-cuda-mps-control -d

查看MPS 守护进程是否正在运行:

ps -ef | grep mps

此时可以看到一个mps进程:

root 1826 1 0 Nov27 ? 00:00:04 nvidia-cuda-mps-control -d

接着运行计算程序,并再次查看mps进程,此时可以看到多出了一个mps-server进程:

root 1826 1 0 Nov27 ? 00:00:04 nvidia-cuda-mps-control -d

root 2544 1826 0 Nov27 ? 00:00:43 nvidia-cuda-mps-server

2. 关闭MPS。

关闭mps-control:

echo quit | nvidia-cuda-mps-control

让GPU计算模式恢复为默认模式:

nvidia-smi -i 0 -c DEFAULT

3. Volta MPS资源配置。

nvidia-cuda-mps-control

set_default_active_thread_percentage 10

该命令为每个MPS Client限制10%的threads。不是为每个Client预留专用资源,而是限制它们可以最多使用多少threads。默认情况下,每个Client可以获取所有threads(即100%)。

4. MPS与docker。

为了配合MPS的使用,docker在创建容器时需要通过

--ipc=host

参数启用内存共享:

docker run -itd --gpus all --ipc=host --network host -p 5501:5501 -v /mnt/data/enhancefox:/home/server-v /etc/timezone:/etc/timezone -v /etc/localtime:/etc/localtime --name enhancefox vsr_trt

注意:

在没有启动MPS的情况下,这样创建的容器仍然能够正常运行(非MPS模式);此时,在启动mps之后,即使重启docker中的程序,该程序仍然不会以mps模式运行。要以mps模式运行程序,必须重启docker:

docker restart enhancefox

5. 如何查看GPU进程是否处于MPS模式?

通过NVIDIA的nvidia-smi命令我们可以知道显卡上的任务可以分为图形图像任务和计算任务两种,其中图形图形任务类型为Graphic,计算任务类型(Type)为compute,缩写分别为G和C,在使用nvidia-smi命令后我们可以通过查看process内容知道不同的进程是属于G类型还是C类型。当启用MPS之后,Type将会对应地变为M+G或者M+C:

有关GPU并行效率问题——通过MPS提升GPU计算收益的更多相关文章

  1. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  2. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  4. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  5. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  6. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  7. ruby - Fast-stemmer 安装问题 - 2

    由于fast-stemmer的问题,我很难安装我想要的任何ruby​​gem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=

  8. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  9. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  10. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

随机推荐