大黄蜂

4

这两天,笔记本里的主板上有两个卡在折磨着我,一个是显卡,另一个还是显卡。

擎天柱

起初,在笔记本里预装的 Windows 7 系统里,我发现了它们的存在。于是我试着在设备管理器里禁用了其中一个,然后发现另一个也不再工作了。这个时候我才亲自接触了一种技术的存在,也因此明白了 Linux 之父 Linus 当年为何对 Nvidia 公司竖中指。这是六年前的事了,很不凑巧,我得到的这部笔记本也是六年前的机器。

这个技术叫做 Nvidia Optimus(Optimus,意思是擎天柱)。这个技术解决的主要问题就是笔记本电源节能问题。支持这种技术的笔记本有两个显卡,一个显卡是集成在 CPU 里的,简称核显;另一个显卡是独立的 Nvidia 显卡,简称独显或 N 卡。平时在运行桌面系统的时候,Optimus 会让核显工作,而在运行三维图形程序的时候,Optimus 便会将显卡切换到更适合处理三维图形渲染的 N 卡。

在 WIndows 系统里,可通过 Nvidia 显卡的配置程序将三维图形渲染所用的显卡设定为 N 卡,便可以让两个显卡各司其职。这是因为 Nvidia 公司为 Windows 系统提供的驱动程序支持 Optimus 技术,否则它能把 N 卡卖给谁呢?但是 Nvidia 公司为 Linux 提供的驱动程序不支持 Optimus,也许它觉得即使支持了,也没几个人买,毕竟拿 Linux 当桌面系统来用的人是那么的少,那么的少。再加上,Nvidia 公司为 Linux 系统提供的驱动,在性能上也一直比它为 Windows 系统提供的驱动逊色。于是,2012 年,Linus 在公众场合对 Nvidia 公司竖起了中指。

选择

现在,要让 Linux 支持 Optimus,会让选择障碍者有所不适,因为有五个方案:

  1. 若在 BIOS 里能够将 N 卡关掉,那么就关掉,这样会更省电。若在 Linux 里不玩三维游戏,这个方案应当作为首选。好在,Linux 里也没几个可以玩的三维游戏。
  2. 使用 Nvidia 公司为 Linux 提供的 N 卡闭源驱动,它提供了 Optimus 支持,但是不支持显卡的切换,亦即核显的功能被阉割,此外驱动里有不少 bug。
  3. 使用 N 卡开源驱动 nouveau 的 PRIME 功能,支持显卡切换,但是在三维图形渲染性能上比 N 卡闭源驱动逊色很多,此外在待机和休眠时可能会出问题。
  4. 使用第三方开发的 Bumblebee 程序,与其他方案相比,这是最接近 Nvidia 为 Windows 提供的 Optimus 的一个方案,但是在配置上要繁琐一些。
  5. 使用 nvidia-xrun,直接开启一个搭载 N 卡驱动的 X 窗口系统。其开发者似乎对 Bumblebee 的性能不满意,便另起炉灶。

我当然是选 Bumblebee 了,因为它是大黄蜂。

大黄蜂

为了让大黄蜂进驻新得来的旧本子(Thinkpad T420)里的 Funtoo 系统,需要做一点准备工作。

先在 /etc/portage/make.conf 文件中,将 VIDEO_CARDS 设为:

VIDEO_CARDS="intel i195 nvidia"

其中,i915 是我的笔记本上的核显芯片的型号(得名于该款芯片相应的 Linux 驱动),nvidia 自然就是 N 卡的芯片了。至于那个 intel 只是为了某些软件包不确定显卡芯片的型号但是只知道它是 intel 家的而设立。

然后更新一下系统,

$ sudo emerge -uDNa @world

因为改了 VIDEO_CARDS,会影响一些依赖显卡类型的软件包,所以要重新编译一遍它们。

接下来,我历经了三劫。

首先是内核劫。因为我嫌弃 Funtoo 文档推荐的 Debian 内核源码编译极为耗时,所以就换成了 Gentoo 内核源码,然后用了一整天,反复将内核编译了七次,将内核里冗余的功能逐步消除了很大一部分。但是,有一个选项

-> Kernel hacking
        -> Lock Debugging (spinlocks, mutexes, etc...)
                [*] Mutex debugging: basic checks 

我没有注意到它的存在,因此未将其取消。结果导致 N 卡闭源驱动装不上,出错信息大概是说 N 卡驱动使用了一个 gpl-only 的符号 mutex_destroy。我在内核配置界面里搜索了一番,感觉只有这个选项有很大概率与这个错误有关,便取消了这个选项,又重新编译了一次内核。之后,N 卡闭源驱动就能够安装了。gpl 是自由软件协议,自由软件协议在西方被认为是有马克思主义精神,所以内核代码里也有意识形态。

再者就是显卡驱动劫。我安装了最新的 N 卡闭源驱动 nvidia-driver-396.45-r1,但是这个驱动已经把我的显卡打入冷宫了。我忘记了我的机器是 6 年前的,而 Nvidia 公司爱幼而不尊老。似乎只要只要年龄超过 5 岁的 N 卡,就会被 N 卡视为皓首匹夫、苍髯老贼般地存在。在 Funtoo 系统里,我能找到的可以用的最新的驱动版本是 nvidia-driver-390.77-r1。于是,只好将 nvidia-drivers 钉在 Funtoo 的耻辱柱上,

$ echo ">x11-drivers/nvidia-drivers-390.77-r1" | sudo tee -a /etc/portage/package.mask 

第三劫来自 Bumblebee 的配置文件。先是安装了 bumblebee 和 primus,将 bumblebee 服务设为开机启动

$ sudo emerge bumblebee primus
$ sudo rc-update add bumblebee default

primus 像是一个桥,bumblebee 通过它将 N 卡中的数据转移到核显里,由核显将数据转换为信号传至显示器。这也应该是 Nvidia Optimus 技术背后的原理。

之后运行 optirun(Bumblebee 提供的用于运行程序的程序,被它运行的程序所看到的显卡是 N 卡):

$ optirun -b primus glxgears
注:glxgears 是三维图形程序,来自 mesa-progs 包,模拟了三维空间里三个齿轮啮合并转动的过程。

注:之前在这个环节,我根据 dmesg 输出的信息断定最新的 nvidia-drivers 与我的显卡不匹配的问题的存在。

程序出错,错误信息为

[ 8146.323225] [ERROR]Cannot access secondary GPU - error: [XORG] (EE) Screen 0 deleted because of no matching config section.

[ 8146.323258] [ERROR]Aborting because fallback start is disabled.

这个错误与 Xorg 的配置文件有关。在 /etc/bumblebee 目录有个 xorg.conf.nvidia 文件,需要在尾部添加以下内容:

Section "Screen"
    Identifier "Default Screen"
    Device "DiscreteNvidia"
EndSection

然后重新启动 bumblebee,

$ sudo /etc/init.d/bumblebee restart

再度执行

$ optirun -b primus glxgears

现在没有出错信息了,但是它似乎什么都没有做就结束了。用 optirun 的 -vv 选项,可以查看调试信息:

$ optirun -vv -b primus glxgears
[14089.726500] [DEBUG]Reading file: /etc/bumblebee/bumblebee.conf
[14089.726635] [INFO]Configured driver: nvidia
[14089.726720] [DEBUG]optirun version 3.2.1-2016-11-07-Format:%h$ starting...
[14089.726731] [DEBUG]Active configuration:
[14089.726736] [DEBUG] bumblebeed config file: /etc/bumblebee/bumblebee.conf
[14089.726742] [DEBUG] X display: :8
[14089.726748] [DEBUG] LD_LIBRARY_PATH: /usr/lib64/opengl/nvidia/lib:/usr/lib32/opengl/nvidia/lib:/usr/lib/opengl/nvidia/lib
[14089.726754] [DEBUG] Socket path: /var/run/bumblebee.socket
[14089.726760] [DEBUG] Accel/display bridge: primus
[14089.726771] [DEBUG] VGL Compression: proxy
[14089.726776] [DEBUG] VGLrun extra options: 
[14089.726784] [DEBUG] Primus LD Path: /usr/lib/primus:/usr/lib32/primus
[14090.533963] [INFO]Response: Yes. X is active.

[14090.533985] [INFO]Running application using primus.
[14090.534098] [DEBUG]Process glxgears started, PID 16071.
[14090.600035] [DEBUG]SIGCHILD received, but wait failed with No child processes
[14090.600064] [DEBUG]Socket closed.
[14090.600081] [DEBUG]Killing all remaining processes.

这个信息表明,glxgears 似乎在启动后遭遇了不测,然后挂掉了,从而导致 bumblebee 抱怨「SIGCHILD received, but wait failed with No child processes」。若将这个抱怨翻译成人类语言,最为贴切的是「何立从东来,我向西方走」。若要确认,不妨用 optirun 运行一个 shell,然后在这个 shell 里运行 glxgears:

$ optirun -b primus bash
$ glxgears
Segmentation fault

结果是段错误。这应该是 primus 出了问题。即便如此,我也无能为力,毕竟我用的是一个过时了的显卡,它亲爹都抛弃它了,primus 没有理由更正常。

不过,我在 /etc/bumblebee/bumblebee.conf 文件中看到,除了 primus 之外,还有 virgualgl 这个桥可以用。于是,便安装 virtualgl:

$ sudo emerge virtualgl

然后将 optirun 的桥换成 virtualgl:

$ optirun -b virtualgl glxgears

结果成功了。

为了不需要每次都用 -b 选项将桥设为 virtualgl,可将 /etc/bumblebee/bumblebee.conf 文件中的 Bridge 设为 virtualgl

Bridge=virtualgl

保存修改后的 bumblebee.conf 文件(需要重新启动 bumblebee 方能使得改动生效),便可直接用 optirun 运行程序,即

$ optirun glxgears

性能

既然 Bumblebee 所模拟的 Optimus 技术可以让 N 卡来负责与三维图形程序,让核显负责二维图形,那么想必在 N 卡模式下,三维图形程序的性能应当明显胜过核显模式才对。由于 glxgears 可以输出显卡每秒渲染的画面数量——帧率(FPS);帧率越大,说明显卡的性能越好,那么就基于 glxgears 在两种显卡模式下的帧数来比较一下 Bumblebee 是否有效。

先在核显模式下,直接运行 glxgears:

$ glxgears
7032 frames in 5.0 seconds = 1406.312 FPS
7264 frames in 5.0 seconds = 1452.739 FPS
7264 frames in 5.0 seconds = 1452.604 FPS
7137 frames in 5.0 seconds = 1427.297 FPS
... ... ...

再在 N 卡模式下运行 glxgears:

$ optirun glxgears
7277 frames in 5.0 seconds = 1455.311 FPS
7335 frames in 5.0 seconds = 1466.953 FPS
7441 frames in 5.0 seconds = 1488.063 FPS
7431 frames in 5.0 seconds = 1486.161 FPS
... ... ...

在这两个显卡模式中,glxgears 输出的帧率相差很小。于是,可以断定 Bumblebee 无效么?不可以。因为 glxgears 不能用来作为判断显卡性能的依据了 [1],理由是这个程序

  • 所用的三维图形的顶点/多边形数量太少了;
  • 没用纹理;
  • 只有简单的平面着色(只是在齿轮中间额孔洞内有这简单的曲面着色);
  • 所有的顶点数据存储于显示列表,因此在渲染过程中从 CPU 到显卡几乎没有数据传输,很大程度上意味着显卡填充速率受限;
  • 默认窗口尺寸是 300 x 300,其中很大一部分区域没有东西需要渲染,因此这甚至不是一个很好的填充速率测试;
  • 完整的渲染步骤由 21 个 OpenGL 函数调用构成,其中有 6 个只是一次性调用,因此这并非很好的 OpenGL API 压力测试,像 glean 这样要比它好一些。

那么,应该怎样测试?使用 virtualgl 提供的 glxspheres 程序,在 64 位的系统中,就是 glxspheres64。

先在核显模式下运行 glxspheres64:

$ glxspheres64
Polygons in scene: 62464 (61 spheres * 1024 polys/spheres)
Visual ID of window: 0x1ce
Context is Direct
OpenGL Renderer: llvmpipe (LLVM 5.0, 256 bits)
23.343345 frames/sec - 24.632832 Mpixels/sec
23.723458 frames/sec - 25.033942 Mpixels/sec
23.116926 frames/sec - 24.393905 Mpixels/sec
23.188665 frames/sec - 24.469607 Mpixels/sec
... ... ...

再在 N 卡模式下运行 glxspheres64:

$ optirun glxspheres64
Polygons in scene: 62464 (61 spheres * 1024 polys/spheres)
Visual ID of window: 0x20
Context is Direct
OpenGL Renderer: NVS 4200M/PCIe/SSE2
173.323775 frames/sec - 182.898181 Mpixels/sec
171.952649 frames/sec - 181.451313 Mpixels/sec
182.521840 frames/sec - 192.604346 Mpixels/sec
172.199391 frames/sec - 181.711686 Mpixels/sec
... ... ...

现在,高下立判。N 卡的三维图形渲染性能大概是核显的 8 倍。

最后

劫波渡尽之后,我删除了 bumblebee、primus、vitualgl 以及 nvidia-drivers,然后在系统重启的过程中,进入了 BIOS,关掉了 N 卡。一切活动,只是为了写一篇除了我不会有人真的会看的文章么?不完全是这样。拼好了的魔方,终归还是要再度打乱的。

附录

查验核显和 N 卡的型号,可以用 lspci -nn 命令。例如:

$ sudo lspci -nn | grep "VGA"
00:02.0 VGA compatible controller [0300]: Intel Corporation 2nd Generation Core Processor Family Integrated Graphics Controller [8086:0126] (rev 09)
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GF119M [Quadro NVS 4200M] [10de:1057] (rev ff)

在 lspci 输出的信息中,第一行是核显,要查询它的型号,需要根据 [8086:0126] 和 CPU 型号信息(可通过命令 cat /proc/cuinfo 查询),去 Intel 显卡列表网页 [2] 搜索,结果我确定了核显的型号是 HD Graphics 3000。至于 N 卡的型号,上述信息已经很完备了。

备忘:

CPU:Intel Corei5-2520M
核显:HD Graphics 3000
独显:GF119M(Quadro NVS 4200M)

[1] Glxgears is not a Benchmark
[2] List of Intel Graphics processing units


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

李润泽 · 8月24日

"一切活动,只是为了写一篇除了我不会有人真的会看的文章么?"
谁说没人看的?(虽然应该不可能会用得上)

回复

0

:D

garfileo 作者 · 8月25日
adam1q84 · 8月27日

“拼好了的魔方,终归还是要再度打乱的。”
有这一句就够了。

回复

_RiChuXiang · 12月4日

看开头,我以为你要自己开始写一个教程:如何在linux下手写一个官网不支持的驱动。

回复

载入中...