Ubuntu 16.04 LTS+NVIDIA@GT620M+CUDA6.5环境搭建总结

引言

为了完成tensorflow中CIFAR10关于cuda-convnet最后两层的实现联系,我重新搭建了一下CUDA环境。可我万万没想到,这环境竟然倒腾了我两个星期的业余时间,搞得我心烦意乱,像个鬼影似的,在我脑子里萦绕又挥之不去。不过最终还是走出了阴霾,我现在做一个经验总结,把我对cuda的一些理解与我对某些问题的解决思路分享给大家。

问题

众所周知,官方驱动对Ubuntu的貌似一向都不大给力,因此apt里面的驱动才是王道。但这并不是绝对的,毕竟确实也有不少人用官方驱动才安装成功NVIDIA-Linux-x86_64-xxx.xx.run的。而我其实最初的搭建目标,是打算在Ubuntu14.04安装CUDA7.5的。当时,我还以为都更新了这么多次,感觉Nvidia支持力度应该不差,结果出现了循环登录界面现象,这个现象不大好解,而且貌似在tty1上用
user@machine:~$ apt-get remove --purge nvidia*
都不好使,所以我改回了cuda-6.5。然而,网上流传着cuda-6.5只支持到nvidia-340的驱动。因此,我直接来一个apt-get install nvidia-340 把它给装上了。本以为这问题就这么解决了,可是却出现了另一个问题——系统黑屏。完了….直接连登陆界面都看不见,其实面对这个情况我还是一如既往的淡定,使用
user@machine:~$ apt-get upgrade
能进系统到system-settings了。接着安装cuda6.5,这部分还没多大问题,但装完后,进入sample编译完后跑deviceQuery的时候就悲剧了,error(30) 是一个unkown有点无语了。难道是GPU驱动没装好?(其实不是,后面我就介绍)最后,又因为我从win系统切换回来,不知得罪哪个系统了,又回到了,黑屏的问题……连重装系统都不好使,upgrade也废了….看起来貌似真全废了。当时,我一直尝试各种方法,但都没得到好结果(包括升级到16.04LTS后依然出现unkown的问题,并且因为编译工具的更新出现各种不适)……然而,我用TRIZ仔细分析了下矛盾后,找到了突破点。

矛盾分析

TRIZ苏联的创新发明理论,我这里不多做介绍,直接用它进行分析。从上面的问题描述上,我们能分析出一种东西,叫做矛盾。当下最主要的矛盾,我想可能在Nvidia的Ubuntu驱动方面。我觉着这个矛盾应该是,在Ubuntu14.04LTS环境下安装官方驱动会登录死循环,安装apt的驱动又会黑屏,不装又跑不起CUDA,装了就进不了系统。这是一个技术矛盾,而我们希望得到的理想结果是,装上驱动而且不会出现故障,但装上驱动就一定会出现故障,其实可以认为N卡驱动坏了。因此我们需要安装一个不是驱动的驱动。乍看这话很怪,我后面分析完就不怪了。

我们需要从微观层面分析,到底为什么N卡驱动是坏的,驱动是跟谁发生冲突,从而寻找物理矛盾?据我的了解加上实验的验证,我发现N卡驱动虽然装上后进不了图形界面,但实际上能进系统的tty1模式并能够正常运行,甚至还能够跑CUDA的程序。也就是说,N卡驱动只是跟上层图形界面启动器发生了冲突,而非底层驱动失效。物理矛盾找到了,那怎么解决呢?大家都明白,换个图形界面启动器就好了嘛,Ubuntu14.04的Xserver启动器,我不是很会换。但前面Ubuntu16.04LTS不是已经把驱动装上了吗?行,我先把系统升级,再让驱动给安上。结果确实没问题了,原因是Ubuntu16.04LTS已经放弃了过去的Xserver,而换成了wayland的图形启动器。这就是我们的那个不是(Ubuntu14.04的)驱动的(Ubuntu16.04的)驱动了。那接下来新的问题出现了,跑CUDA例程出现的unkown怎么解决,还有编译工具过新的问题怎么解决?

因为Ubuntu16.04LTS更新了gnu,而且在string的memcpy方面有比较大的改动,因此老会出现问题

"/usr/include/string.h:652:42: error: 'memcpy' was not declared in this scope"

这个问题还是比较好解决的,一般我是在编译文件里面,添加一个叫做-D_FORCE_INLINES 的编译选项。不过,面对cuda6.5的编译,由于不支持gnu-4.9及以上的版本,我是直接使用

user@machine:~$ sudo update-alternative --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 0
user@machine:~$ sudo update-alternative --install /usr/bin/gcc gcc /usr/bin/gcc-5.0 1
user@machine:~$ sudo update-alternative --install /usr/bin/g++ g++ /usr/bin/g++-4.8 0
user@machine:~$ sudo update-alternative --install /usr/bin/g++ g++ /usr/bin/g++-5.0 1

这时我们就可以使用下面的两条指令来选择切换gnu版本

user@machine:~$ sudo update-alternative --config g++
user@machine:~$ sudo update-alternative --config gcc

最后,就是编译了CUDA提供的sample后,在跑deviceQuery时出现的unkown问题,类似如下:

./deviceQuery Starting...

CUDA Device Query (Runtime API) version (CUDART static linking)

cudaGetDeviceCount returned 30
-> unknown error
Result = FAIL

这个问题其实也很独特,每个人这个问题都可能不一样,我只能介绍我遇到的情况。我的这个问题主要的原因其实是因为~/.bashrc里面没有真正的加上LD_LIBRARY_PATH。(其实我有根据cuda的安装提示加上,只是LD_LIBRARY_PATH我漏掉了最后的PATH成了LD_LIBRARY,结果引发了这出惨案……)另外,还有一种可能是权限不够,可以通过执行的时候加上sudo解决这个问题,下面是我的log:

user@machine:~$ sudo ./deviceQuery
[sudo] password for user: 
./deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Detected 1 CUDA Capable device(s)

Device 0: "GeForce GT 620M"
  CUDA Driver Version / Runtime Version          6.5 / 6.5
  CUDA Capability Major/Minor version number:    2.1
  Total amount of global memory:                 1024 MBytes (1073479680 bytes)
  ( 2) Multiprocessors, ( 48) CUDA Cores/MP:     96 CUDA Cores
  GPU Clock rate:                                1250 MHz (1.25 GHz)
  Memory Clock rate:                             900 Mhz
  Memory Bus Width:                              64-bit
  L2 Cache Size:                                 131072 bytes
  Maximum Texture Dimension Size (x,y,z)         1D=(65536), 2D=(65536, 65535), 3D=(2048, 2048, 2048)
  Maximum Layered 1D Texture Size, (num) layers  1D=(16384), 2048 layers
  Maximum Layered 2D Texture Size, (num) layers  2D=(16384, 16384), 2048 layers
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       49152 bytes
  Total number of registers available per block: 32768
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  1536
  Maximum number of threads per block:           1024
  Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
  Max dimension size of a grid size    (x,y,z): (65535, 65535, 65535)
  Maximum memory pitch:                          2147483647 bytes
  Texture alignment:                             512 bytes
  Concurrent copy and kernel execution:          Yes with 1 copy engine(s)
  Run time limit on kernels:                     Yes
  Integrated GPU sharing Host Memory:            No
  Support host page-locked memory mapping:       Yes
  Alignment requirement for Surfaces:            Yes
  Device has ECC support:                        Disabled
  Device supports Unified Addressing (UVA):      Yes
  Device PCI Bus ID / PCI location ID:           1 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 6.5, CUDA Runtime Version = 6.5, NumDevs = 1, Device0 = GeForce GT 620M
Result = PASS

出现这个log就意味着,cuda环境成功配置了。

解答总结

下面是整个CUDA环境的配置流程:
1.安装Ubuntu16.04LTS系统,也可以从较低版本中升级上来。
2.从System Settings中安装Nvidia驱动。
3.用 apt-get install g++-4.8 gcc-4.8安装老版本gnu。
4.用update-alternative指令配置gnu环境,使其能够升降级。
5.编译CUDA工具。
6.编译CUDA的sample,并调用deviceQuery测试安装是否成功。

一些注意事项:
1.Ubuntu16.04LTS使用wayland图形界面启动器,比原来的Xserver更容易避免N卡驱动与系统应用层的冲突。
2.安装好N卡驱动并进入图形界面后,可以利用Nvidia X server Settings来切换显卡。
3.注意用编译选项-D_FORCE_INLINES解决“‘memcpy’ was not declared in this scope”的问题。
4.想要知道N卡驱动是否安装成功,我们可以查看System Settings的detail信息,看是否又有我们的独显型号来判断。
5.编译sample的过程中可能遇到/usr/bin/ld -nvcudev:can’t find the directories 类似的现象,这是有可能是因为我们使用了nvidia-340以上的显卡驱动,从而找不着路径,在默认编译环境里面找不到相应的库,这时我们只要在.barshrc文件里面最后加上下面一行就解决问题了:
export LIBRARY_PATH=/usr/lib/nvidia-xxx(版本号):LIBRARY_PATH

总的来讲,CUDA其实只是一套编译工具,它是在原有的GNU工具的基础上加入了兼容NVIDIA的GPU架构的指令集,提供了一套能调用GPU资源的API。因此CUDA本身的安装并不存在多大问题,大部分都只是N卡驱动以及编译链接的问题。所以,我建议如果在CUDA环境搭建的时候,遇到问题有优先从编译链接上找原因,尤其是驱动已经明确安装成功的时候,基本可以明确是编译链接的问题。N卡驱动一般只会跟上层图形界面应用服务产生矛盾,所以基本可以分离N卡驱动与CUDA代码执行的问题。不过,有一个很重要的例外,就是执行一些不符合自身显卡计算能力的代码时,同样也会出现code=30的unknown错误,如下:

CUDA error at src/nvmatrix.cu:1548 code=30(cudaErrorUnknown) "cudaCreateTextureObject(&_texObj, &resDesc, &texDesc, NULL)"

这个错误是因为我的GT620M的计算能力只有2.1,编译的时候使用sm_20架构的编译选项,而这个TextureObject的代码只能在sm_30以上的架构使用,所以会出现这种错误。实际上,我很鄙视Nvidia CUDA的nvcc编译工具。因为在编译阶段这个使用架构不兼容代码的问题是可以提示错误的,从而减少开发者遇到问题的处理效率,而且我觉着这只是一个宏定义处理的问题而已,看来Nvidia在这方面的支持力度还有待提高!

关于Ubuntu 12.04 下 CUDA5.5 的安装请参看如下链接 Ubuntu 12.04 安装 CUDA-5.5

猜你喜欢

转载自www.linuxidc.com/Linux/2016-10/135911.htm
今日推荐