前回 までに、LLVM、MesaLibとビルドを進め、ようやくXorgサーバを動かせるところまで辿りつきました。起動したサーバの情報をxdpyinfo で調べると、バージョン1.14.2であることは確認できたものの、果してこのサーバは本当にMesaLibが提供しているドライバやLLVMが提供しているライブラリを使っているのでしょうか?
Xorgサーバのように多くの部品から構成されている複雑なソフトウェアでは、一見正しく動作しているように見えても、実は想定した機能が利用できずにフォールバックモード で動いていた、ということもよくあります。そこでXorgサーバの動作を詳しく調べてみることにしました。
Xorgサーバのログファイル
Xorgサーバは/var/logディレクトリにXorg.0.log という名称のログファイルを作成し、起動時に認識したハードウェアやロードした各種モジュールについて記録しています。そこで、まずこのログファイルを眺めてみました。
$ cat -n /var/log/Xorg.0.log
1 [415001.067]
2 X.Org X Server 1.14.2
3 Release Date: 2013-06-25
4 [415001.067] X Protocol Version 11, Revision 0
5 [415001.067] Build Operating System: Linux 3.8.13-plamo64 x86_64
6 [415001.067] Current Operating System: Linux corei7 3.11.1-plamo64 #1 SMP PREEMPT Fri Sep 2014:48:13 JST 2013 x86_64
7 [415001.067] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-3.11.1-plamo64 root=/dev/sdc2 ro vga16 unicon=eucjp vt.default_utf8=0 panic_output=7
8 [415001.067] Build Date: 29 August 2013 05:11:53PM
....
ログファイルの先頭部分では、起動しているXorgサーバのバージョン(1.14.2)やソースコードの公開日(2013-06-25) 、ビルドされた環境(Linux 3.8.13-plamo64 x86_64) 、現在動いている環境(Linux corei7 3.11.1-plamo64..)起動時のカーネルパラメータ、ビルドされた日時等の情報が記録されています。動作中の環境はXorgサーバをビルドした環境から更新されていることも正しく認識しています。
各行の先頭部分に表示されている[..]内の数字は、それぞれのイベントを区別するためのタイムスタンプで、数字自体に特に意味はありません。たぶん、カーネルが起動してからの経過秒数を利用しているのでしょう。
ログファイルを読み進めていくと、現在のABI (Application Binary Interface)設定についての記述がありました。前回にも触れましたが、Xorgサーバのように、必要なモジュールドライバを動的に組み込んで動作するソフトウェアでは、両者のABIのバージョンを合わせておく必要があります。
39 [415001.148] (II) Module ABI versions:
40 [415001.148] X.Org ANSI C Emulation: 0.4
41 [415001.148] X.Org Video Driver: 14.1
42 [415001.148] X.Org XInput driver : 19.1
43 [415001.148] X.Org Server Extension : 7.0
実際のモジュール類のロードがこのあたりからです。76行目からはlibglamoregl.so というglamor_eglパッケージとしてビルドしたモジュールドライバをロードしていることが記録されています。このモジュールドライバのバージョンは0.5.0、Xorgサーバ1.14.2用にコンパイルされ、ANSI C Emulationのバージョン0.4というABIでサーバとやりとりするようです。
72 [415001.151] Initializing built-in extension DRI2
73 [415001.151] (II) "glx" will be loaded by default.
74 [415001.151] (II) LoadModule: "dri2"
75 [415001.151] (II) Module "dri2" already built-in
76 [415001.151] (II) LoadModule: "glamoregl"
77 [415001.151] (II) Loading /usr/lib64/xorg/modules/libglamoregl.so
78 [415001.152] (II) Module glamoregl: vendor="X.Org Foundation"
79 [415001.152] compiled for 1.14.2, module version = 0.5.0
80 [415001.152] ABI class: X.Org ANSI C Emulation, version 0.4
もう少し先から、利用しているグラフィックカード用のドライバのロードが始まります。今使っているのは、AMD(ATI) RADEON HD5770を使ったグラフィックカードなので、それを利用するためにati_drv.so とradeon_drv.so がロードされています。バージョン番号やABIの情報から、新しくビルドしたモジュールと確認できます。
94 [415001.161] (II) LoadModule: "ati"
95 [415001.161] (II) Loading /usr/lib64/xorg/modules/drivers/ati_drv.so
96 [415001.170] (II) Module ati: vendor="X.Org Foundation"
97 [415001.170] compiled for 1.14.2, module version = 7.2.0
98 [415001.170] Module class: X.Org Video Driver
99 [415001.170] ABI class: X.Org Video Driver, version 14.1
100 [415001.170] (II) LoadModule: "radeon"
101 [415001.170] (II) Loading /usr/lib64/xorg/modules/drivers/radeon_drv.so
102 [415001.177] (II) Module radeon: vendor="X.Org Foundation"
103 [415001.177] compiled for 1.14.2, module version = 7.2.0
104 [415001.177] Module class: X.Org Video Driver
105 [415001.177] ABI class: X.Org Video Driver, version 14.1
この後しばらくは、RADEONドライバが認識したハードウェア情報が続きますが、そのあたりは省略して先を見ていくと、MesaLibが提供しているドライバをロードしている部分がありました。
486 [415001.344] (II) RADEON(0): [DRI2] Setup complete
487 [415001.344] (II) RADEON(0): [DRI2] DRI driver: r600
488 [415001.344] (II) RADEON(0): [DRI2] VDPAU driver: r600
489 [415001.345] (II) RADEON(0): Front buffer size: 8000K
490 [415001.345] (II) RADEON(0): VRAM usage limit set to 929451K
491 [415001.345] (==) RADEON(0): Backing store disabled
492 [415001.345] (II) RADEON(0): Direct rendering enabled
手元のRADEON HD5700は、AMD GPUの世代的に言うとR600よりも2世代くらい後のEvergreenと呼ばれる世代になります。しかしながら、AMD GPUの基本設計は次のNorthern Island世代までは共通しているようで、MesaLibではr600ドライバがr600、r700、Evergreen、Northern IslandまでのGPUに対応しています。
488行目にあるVDPAU とは、Video Decode and Presentation API for Unixと呼ばれる最近のGPUが持っている動画再生機能を使うためのライブラリで、それも正しくR600用のドライバが利用されているようです。
各種ライブラリのメモリマップ
/var/log/Xorg.0.log を調べた限りでは、新しくビルドしたXorgサーバとそれに対応したドライバは正しく動作しているようです。しかしながら、このログファイルだけではXorgサーバがr600 のドライバを使っていることはわかるものの、r600のドライバが本当に LLVMのライブラリを利用しているのかまではわかりません。
現実的には、前回見たようにr600のドライバ(/usr/lib64/dri/r600_dri.so)はLLVMの提供するライブラリ群を参照しているので、r600のドライバを正しくロードするには参照を解決することが必要で、そのためにはLLVMのライブラリもロードされている、と考えることができます。しかしながら、グラフィックカードのドライバ(が利用するモジュール)がコンパイラのライブラリを動作時に利用する、という前代未聞の設定を見ると、このあたりを改めて確認したくなります。
動作しているバイナリファイル(Xorgサーバ)が実際にどのようなライブラリを利用しているのかは、procファイルシステム を使って調べることができます。
procファイルシステムは、/proc ディレクトリにマウントされる仮想的なファイルシステムで、カーネルが管理していてユーザ環境からは直接アクセスすることができない動作中のプロセスについての情報を、ユーザ環境に提供するために用意されています。
$ ls /proc
1/ 17345/ 28944/ 29142/ 29299/ 30213/ 3367/ 3621/ 5/ 7623/ fs/ scsi/
10/ 17346/ 28960/ 29145/ 29300/ 30429/ 3379/ 3634/ 5036/ 8/ interrupts self@
11/ 18/ 28973/ 29150/ 29303/ 3046/ 3396/ 3701/ 5037/ 8099/ iomem slabinfo
...
UNIX/Linuxの設計思想では、ハードウェアを直接操作するカーネルは特権モードで動作して、ユーザ環境で動作するアプリケーションからは直接アクセスできない ようになっています。しかしながら、両者の分離を徹底しすぎると不便なことも多いので、Linuxではカーネルの内部情報をprocファイルシステム経由でユーザ環境のアプリケーションに公開すると共に、アプリケーションからいくつかの設定を変更することを認めています。
procファイルシステムに現われた数字だけのディレクトリは、その数字をプロセスIDとするプロセス について、カーネルが管理している各種情報を提供するために使われます。
動作しているXorgサーバのプロセスIDはpsコマンドで知ることができます。
$ ps ax | grep X
8832 pts/5 S+ 0:00 grep X
28973 tty1 S+ 0:00 xinit /home/kojima/.xinitrc -- /usr/bin/X :0
28974 tty7 Ssl+ 7:20 /usr/bin/X :0
現在、動作しているXorgサーバのプロセスIDは28974なので、/proc/28974がXorgサーバの動作状態を提供するディレクトリになります。なお、procファイルシステムを参照する際にはroot権限が必要となることが多いので、以下の操作ではsudoを介して実行しています。
$ sudo ls -F /proc/28974
auxv cpuset limits mountstats pagemap stack wchan
cgroup cwd@ loginuid net/ personality stat
clear_refs environ maps ns/ root@ statm
cmdline exe@ mem oom_adj sched status
comm fd/ mountinfo oom_score sessionid syscall
coredump_filter fdinfo/ mounts oom_score_adj smaps task/
このディレクトリにあるファイルやディレクトリには動作しているプロセスについての各種情報が収められています。これらのうちからmaps というファイルを参照して、プロセスが利用しているメモリの状態(メモリのマッピング情報)を調べてみます。
$ sudo cat /proc/28974/maps
00400000-00604000 r-xp 00000000 08:22 1603887 /usr/bin/Xorg
00803000-00811000 rw-p 00203000 08:22 1603887 /usr/bin/Xorg
00811000-03e12000 rw-p 00000000 00:00 0 [heap]
7f02269f8000-7f0226d93000 rw-s 114f2c000 00:0d 6251 /dev/dri/card0
7f022712e000-7f022712f000 rw-s 10c57d000 00:0d 6251 /dev/dri/card0
...
7f022c3bd000-7f022cbbd000 rw-p 00000000 00:00 0 [stack:28977]
7f022cbbd000-7f022cc9d000 r-xp 00000000 08:22 1576862 /usr/lib64/libstdc++.so.6.0.16
7f022cc9d000-7f022ce9c000 ---p 000e0000 08:22 1576862 /usr/lib64/libstdc++.so.6.0.16
7f022ce9c000-7f022cea4000 r--p 000df000 08:22 1576862 /usr/lib64/libstdc++.so.6.0.16
7f022cea4000-7f022cea6000 rw-p 000e7000 08:22 1576862 /usr/lib64/libstdc++.so.6.0.16
7f022cea6000-7f022cebb000 rw-p 00000000 00:00 0
7f022cebb000-7f022cf73000 r-xp 00000000 08:22 1602804 /usr/lib64/libLLVMSupport.so
7f022cf73000-7f022d173000 ---p 000b8000 08:22 1602804 /usr/lib64/libLLVMSupport.so
7f022d173000-7f022d179000 rw-p 000b8000 08:22 1602804 /usr/lib64/libLLVMSupport.so
7f022d179000-7f022d17b000 rw-p 00000000 00:00 0
7f022d17b000-7f022d2d0000 r-xp 00000000 08:22 1602806 /usr/lib64/libLLVMCore.so
7f022d2d0000-7f022d4d0000 ---p 00155000 08:22 1602806 /usr/lib64/libLLVMCore.so
7f022d4d0000-7f022d4dc000 rw-p 00155000 08:22 1602806 /usr/lib64/libLLVMCore.so
7f022d4dc000-7f022d515000 r-xp 00000000 08:22 1602826 /usr/lib64/libLLVMObject.so
7f022d515000-7f022d714000 ---p 00039000 08:22 1602826 /usr/lib64/libLLVMObject.so
...
7f0231e8b000-7f0231e8d000 rw-p 00036000 08:22 1602818 /usr/lib64/libLLVMVectorize.so
7f0231e8d000-7f0232468000 r-xp 00000000 08:22 1597588 /usr/lib64/dri/r600_dri.so
7f0232468000-7f0232668000 ---p 005db000 08:22 1597588 /usr/lib64/dri/r600_dri.so
7f0232668000-7f02326c3000 rw-p 005db000 08:22 1597588 /usr/lib64/dri/r600_dri.so
7f02326c3000-7f02328a4000 rw-p 00000000 00:00 0
...
7f02334fc000-7f0233558000 r-xp 00000000 08:22 1603363 /usr/lib64/xorg/modules/drivers/radeon_drv.so
7f0233558000-7f0233757000 ---p 0005c000 08:22 1603363 /usr/lib64/xorg/modules/drivers/radeon_drv.so
7f0233757000-7f0233763000 rw-p 0005b000 08:22 1603363 /usr/lib64/xorg/modules/drivers/radeon_drv.so
7f0233763000-7f0233764000 r-xp 00000000 08:22 1603361 /usr/lib64/xorg/modules/drivers/ati_drv.so
7f0233764000-7f0233964000 ---p 00001000 08:22 1603361 /usr/lib64/xorg/modules/drivers/ati_drv.so
7f0233964000-7f0233965000 rw-p 00001000 08:22 1603361 /usr/lib64/xorg/modules/drivers/ati_drv.so
...
上記のように、mapsファイルにはXorgサーバ自身が利用しているライブラリやドライバモジュール類、さらにそれらドライバモジュールが利用しているライブラリが、メモリ上のどの位置に配置されているかが表示されています。今回ビルドしたXorgサーバは確かにLLVMのライブラリを組み込んで動作しています。
MesaLibの状況
X Window SystemはOpenGLのような3Dグラフィック技術が生まれるはるか以前に開発が始まったので、動作にOpenGLは必須ではありません。そのためX Window System用に開発されてきたソフトウェアのOpenGLへの対応はバラつきがあるのが現状です。しかしながら、現在も開発が続いているソフトウェアでは、次第にOpenGLにも積極的に対応するようになってきました。
たとえば、KDE4環境ではOpenGLに対応したPlasma と呼ばれる機能が画面描画等を一手に引き受けており、「 3Dグラフィックを利用した仮想画面切り替え」といったデスクトップ効果を使うことができます。
図1 デスクトップキューブを使った仮想デスクトップの切り替え例
このような機能を持つため、KDEではKInfocenter と呼ばれるシステム情報を表示するツールでも、XサーバとともにOpenGLに関する詳しい情報が確認できます。
図2 KInfocenterのOpenGL情報
この結果を見ても、MesaLib 9.2.2のGallium3Dフレームワークのドライバとradeonカーネルモジュールが正しく認識されていることがわかります。
さて、それではこの環境のOpenGLの性能はどれくらいなのでしょう? 今回構築したOpenGL環境は、カーネルに付属のradeonモジュールとMesaLibが提供するDRI用ドライバ、X Window Systemの提供するradeon用ドライバ、というソースコードが公開されたソフトウェアのみを組み合わせて実現しています。
一方、AMDやNVIDIAといったグラフィックカードメーカは、自社製のグラフィックカード用にソースコードを(一部)公開していないLinux版のドライバを提供しています。それらのドライバには製造元のみが知る非公開のノウハウや機能が盛り込まれていて、OSS版のドライバよりも高性能と考えられています。そこで今回は、AMDが提供しているCatalyst-13.11-beta-v9.4というドライバと比較してみることにしました。
図3 KInfocenterで見たAMD Catalystドライバ
OpenGLの性能テストには、Geeks3d.com が公開しているGpuTestというツールを試してみました。このツールはOpenGLのさまざまな機能の性能(速度)を7種のテストから測定するように構成されています。
図4 GpuTestのfurmarkテスト
GpuTestが提供している各テストを試してみると、AMD Catalystのドライバは7種のテスト全てを実行できるものの、MesaLibのドライバでは、OpenGL 4.0の機能を必要とするTessMarkは実行不能、GiMarkと2種のPixMarkテストはドライバのバグで計測不能となり、実行できた残り3種のテストでも、成績はAMD Catalystドライバに大きく引き離される、という結果になりました。
FurMark GiMark PixMark Piano PixMark Volplosion Plot3D TessMark (X16/X16) Triangle
AMD Catalyst 1272 2733 305 1068 17133 10914 267133
MesaLib 633 N/A N/A N/A 10094 N/A 65195
あれこれ苦労してMesaLibのドライバをビルドしてきたことを考えるとやや残念な結果ですが、このあたりはGPUの製造元に一日以上の長があるということでしょう。もっとも、KDEのPlasma環境を使っている程度では両者の差は感じませんし、AMD Catalystドライバが自社製のグラフィックカードのみを対象とするのに対し、MesaLibはより広い視点から、IntelやNVIDIAのカードにも共通のフレームワークで対応しようとしています。LLVMと組み合わせたこのGallium3Dフレームワークはまだまだ発展途上で、開発者たちは性能改善に日夜取り組んでいることを忘れてはならないでしょう。