這裡紀錄在 CentOS Linux 系統上編譯、安裝與設定 ParaView,使用 OpenMPI 打造平行繪圖伺服器的過程。
本篇文章是我個人的工作記錄,由於技術細節太多了,很難完全寫下來,所以只能當作參考用,但我相信如果您想要架設 ParaView 的繪圖叢集電腦,這篇是很有價值的參考資料。
在開始安裝 ParaView 伺服器之前,請先詳讀 ParaView 官方的 Setting up a ParaView Server 教學文件,因為觀念與細節太多了,很多上面有寫的部份我就不重複說明了。
伺服器軟硬體架構
目前拿兩台伺服器作為繪圖節點,一個節點有兩張 NVIDIA GeForce GTX 1060 6GB 顯示卡,每張顯示卡的記憶體大小是 6GB。
這張架構圖是用 VRT Network Equipment 圖示集畫的,原始檔在這裡。
伺服器的作業系統是 CentOS Linux 7.2.1511,NVIDIA 的驅動程式版本為 375.26。
設定 NVIDIA 顯示卡與 X Window
使用 nvidia-xconfig
建立基本的 xorg.conf
:
sudo nvidia-xconfig --enable-all-gpus --virtual=1600x1200
加入 --enable-all-gpus
參數可產生所有 GPU 顯示卡的設定,在一台機器有多張顯示卡的時候就要加上這個參數,而 --virtual
則是用來設定虛擬螢幕解析度(virtual screen resolution)用的參數,這個不能設太小,至少要跟 ParaView client 的解析度一樣大。
通常插在伺服器上的顯示卡不會每一張都接螢幕,甚至完全不會有螢幕,在沒有螢幕的狀況下,NVIDIA 的驅動程式預設是不會啟動的,要自己額外加上 AllowEmptyInitialConfiguration
設定,強制讓顯示卡啟動。
xorg.conf
關鍵的設定如下:
Section "Device" Identifier "Device0" Driver "nvidia" VendorName "NVIDIA Corporation" BoardName "GeForce GTX 1060 6GB" BusID "PCI:3:0:0" # 強制顯示卡啟動 Option "AllowEmptyInitialConfiguration" "true" EndSection Section "Device" Identifier "Device1" Driver "nvidia" VendorName "NVIDIA Corporation" BoardName "GeForce GTX 1060 6GB" BusID "PCI:132:0:0" # 強制顯示卡啟動 Option "AllowEmptyInitialConfiguration" "true" EndSection Section "Screen" Identifier "Screen0" Device "Device0" Monitor "Monitor0" DefaultDepth 24 SubSection "Display" Virtual 1600 1200 # 設定虛擬螢幕解析度 Depth 24 EndSubSection EndSection Section "Screen" Identifier "Screen1" Device "Device1" Monitor "Monitor1" DefaultDepth 24 SubSection "Display" Virtual 1600 1200 # 設定虛擬螢幕解析度 Depth 24 EndSubSection EndSection
NVIDIA 的 X Config Options 請參考 NVIDIA 驅動程式的說明文件。
補充說明,Vim 若要編輯 xorg.conf
時,設定的 syntax
為 xf86conf
。
修改完 X Window 設定之後,要重新啟動 X Window,通常是重新啟動 gdm
服務(或是 xdm
等服務,視自己的伺服器而定):
sudo service gdm restart
讓所有人都可以連進來使用 X Window server:
DISPLAY=:0 sudo xhost +
access control disabled, clients can connect from any host
以 glxinfo
檢查一下顯示卡狀況:
DISPLAY=:0 glxinfo
以 nvidia-smi
檢查 X Window 是否有正常在每一張 NVIDIA 的顯示卡上啟動:
nvidia-smi
Fri Feb 17 08:42:14 2017 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 375.26 Driver Version: 375.26 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 GeForce GTX 106... Off | 0000:03:00.0 Off | N/A | | 28% 27C P8 7W / 120W | 84MiB / 6072MiB | 0% Default | +-------------------------------+----------------------+----------------------+ | 1 GeForce GTX 106... Off | 0000:84:00.0 Off | N/A | | 28% 25C P8 5W / 120W | 16MiB / 6072MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | 0 13747 G /usr/bin/Xorg 72MiB | | 0 13803 G gnome-shell 10MiB | | 1 13747 G /usr/bin/Xorg 14MiB | +-----------------------------------------------------------------------------+
正常來說在下方的 Processes
的部份,每一張 GPU 卡都至少要有一筆 /usr/bin/Xorg
,如果沒有的話就表示 X Window 沒有正常啟動,請檢查 /var/log/Xorg.0.log
等紀錄檔。
安裝 OpenMPI
OpenMPI 使用 yum
安裝即可:
sudo yum install openmpi openmpi-devel
CentOS 的 OpenMPI 安裝完之後,使用前要先用 module
載入:
module load mpi/openmpi-x86_64
測試 mpirun
:
mpirun --version
mpirun (Open MPI) 1.10.3 Report bugs to http://www.open-mpi.org/community/help/
如果忘記用 module
載入的話,執行時就會出現這樣找不到指令的錯誤:
bash: mpirun: command not found...
編譯 ParaView 伺服器
我嘗試過直接使用編譯好的 ParaView 伺服器,但是執行時無法正常啟動 MPI(我猜應該是沒有抓到系統的 MPI 導致的),只能以單一台機器的模式使用,所以若要使用 MPI 的話,可能還是要自己編譯。
首先下載與安裝 CMake:
wget https://cmake.org/files/v3.8/cmake-3.8.0-rc1-Linux-x86_64.sh chmod +x cmake-3.8.0-rc1-Linux-x86_64.sh ./cmake-3.8.0-rc1-Linux-x86_64.sh
接下來要準備編譯 ParaView 的伺服器,編譯過程跟一般的 CMake 專案都相同:
tar zxvf ParaView-v5.3.0-RC1.tar.gz mkdir build-mpi cd build-mpi cmake ../ParaView-v5.3.0-RC1/
在 CMakeCache.txt
中的設定有幾個地方要改,首先是設定 NVIDIA 的 OpenGL 函式庫:
// 設定 NVIDIA 提供的 libGL.so
OPENGL_gl_LIBRARY:FILEPATH=/usr/lib64/nvidia/libGL.so
還有啟用 ParaView 的 MPI 平行計算功能:
// 啟用 MPI,支援平行計算
PARAVIEW_USE_MPI:BOOL=ON
在伺服器上不需要 GUI 圖形界面,所以可以不需要編譯 QT 的 client,可以大幅減少編譯所需的時間:
// 停用 ParaView Qt GUI 圖形界面 client
PARAVIEW_BUILD_QT_GUI:BOOL=OFF
通常安裝路徑也可以改一下:
// 設定安裝路徑
CMAKE_INSTALL_PREFIX:PATH=/opt/paraview-5.3-mpi/
其他的參數則自行調整,接著就可以進行編譯。
在伺服器上用 make
編譯時,可用多顆 CPU 平行編譯,速度會快很多,例如用 40 顆 CPU 平行編譯:
make -j40
使用平行編譯只要幾分鐘就可以編完了,接著安裝:
make install
單機 MPI 執行 ParaView 伺服器
這是使用 mpirun
在一台機器上執行 ParaView 伺服器,並且平行使用兩張顯示卡的指令:
mpirun --map-by node -np 1 /opt/paraview-5.3-mpi/bin/pvserver -display :0.0 : -np 1 /opt/paraview-5.3-mpi/bin/pvserver -display :0.1
用戶端 ParaView client 就直接使用官方編譯好的版本即可,開啟 ParaView 之後,先新增一台 ParaView 伺服器,然後連線至 ParaView 伺服器,伺服器預設的連接埠(port)是 11111
(這個在 ParaView 執行時也會顯示)。
接著開啟 ParaView 官方提供的範例檔來測試,我用 headsq.vti
這個 volume 資料來測試,開啟原始資料之後,加入一個 Contour filter,讓它產生 isosurface,接著在加上一個特殊的「Process Id Scalars」filter,讓 ParaView 將不同伺服器 process 所畫出來的圖形顯示為不同的顏色。
這裡我們使用 MPI 執行兩個 ParaView 伺服器的 process,分別使用兩張不同的 GPU 顯示卡,圖形上的兩個顏色分別代表從兩張 GPU 顯示卡所畫出來的部份。
在畫圖時順便可用 nvidia-smi
觀察 GPU 顯示卡的狀況:
nvidia-smi -l 3
每 3 秒更新一次資訊:
Fri Feb 17 10:11:32 2017 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 375.26 Driver Version: 375.26 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 GeForce GTX 106... Off | 0000:03:00.0 Off | N/A | | 28% 27C P8 6W / 120W | 90MiB / 6072MiB | 0% Default | +-------------------------------+----------------------+----------------------+ | 1 GeForce GTX 106... Off | 0000:84:00.0 Off | N/A | | 28% 25C P8 5W / 120W | 38MiB / 6072MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | 0 13747 G /usr/bin/Xorg 61MiB | | 0 13803 G gnome-shell 10MiB | | 0 36853 G ...araview-5.3-mpi/lib/paraview-5.3/pvserver 16MiB | | 1 13747 G /usr/bin/Xorg 18MiB | | 1 36854 G ...araview-5.3-mpi/lib/paraview-5.3/pvserver 17MiB | +-----------------------------------------------------------------------------+
這樣就可以非常確定 ParaView 伺服器是真的使用 GPU 在畫圖,而不是使用 CPU 的軟體繪圖模式。
ParaView 的 server 與 client 一定要是相同的版本,否則不能連線,但是可以允許不同的作業系統,這裡我們的 ParaView server 是用 CentOS Linux 架設的,也可以在 Mac OS X 上使用 ParaView client 連線至 server 進行平行繪圖。
多節點平行繪圖
將單節點、兩張 GPU 顯示卡平行繪圖的架構設定好之後,接下來就要串連兩個節點,使用 4 張 GPU 卡來畫圖了。
建立 SSH 公開金鑰認證
將兩台繪圖節點都設定好之後,接著要將兩台伺服器用 MPI 串起來使用,首先解決 ssh 登入的問題。
在繪圖節點上建立 ssh 認證用的金鑰:
ssh-keygen
將產生的公鑰放入 ~/.ssh/authorized_keys
:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
將 ~/.ssh
的內容同步複製到另外一台繪圖節點,讓節點之間可不用密碼互相登入。
關於 ssh 金鑰認證登入的詳細說明請參考 SSH 公開金鑰認證。
檔案系統
這裡的檔案系統就仿照一般的 MPI 叢集電腦架設即可,可使用 NIS 與 NFS 架設,至於平行化的檔案系統與效能問題,就等以後再討論。
多節點 MPI 執行 ParaView 伺服器
設定預設的 MPI 環境:
echo "module load mpi/openmpi-x86_64" >> ~/.bashrc
先測試多節點的 OpenMPI 是否正常:
mpirun --host server1,server2 -np 2 hostname
參考 OpenMPI 的文件,建立一個 myhostfile
設定檔:
server1 slots=2 server2 slots=2
使用兩個繪圖節點,總共 4 張 GPU 顯示卡平行繪圖:
mpirun --map-by node --hostfile myhostfile -np 2 /opt/paraview-5.3-mpi/bin/pvserver -display :0.0 : -np 2 /opt/paraview-5.3-mpi/bin/pvserver -display :0.1
ParaView client 的連線方式與單節點相同,這是顯示的結果。
最後用 nvidia-smi
指令檢查兩台繪圖節點的 GPU 狀況,確認 4 個 ParaView server 都有用到 GPU 繪圖。
問題與解決方法
以下是在建置 ParaView 的 MPI 平行繪圖伺服器過程中,所遇到的各種問題與處理方法,因為問題真的很多,只紀錄比較有參考價值的部份。
OpenMPI 啟動延遲 15 秒
在使用 mpirun
執行 ParaView 伺服器時,會出現類似這樣的錯誤訊息:
my.host.com.34522hfi_wait_for_device: The /dev/hfi1_0 device failed to appear after 15.0 seconds: Connection timed out my.host.com.34523hfi_wait_for_device: The /dev/hfi1_0 device failed to appear after 15.0 seconds: Connection timed out Waiting for client... Connection URL: cs://my.host.com:11111 Accepting connection(s): my.host.com:11111
這是一個 OpenMPI 的 bug,目前最新版的 OpenMPI 已經修正了,但是 CentOS 的套件庫尚未更新。
這個問題是由於 OpenMPI 執行時會檢查 PSM2 設備,但若沒有任何 MSM2 設備時,就會浪費 15 秒的時間,但後續程式的執行則不受影響,暫時可忽略這個問題。
伺服器虛擬螢幕解析度問題
一開始我在設定伺服器的 NVIDIA 顯示卡時,沒有注意到虛擬螢幕解析度的問題,導致 ParaView 在視窗放大時會出現類似這樣的空白區塊:
我發現這個異常的空白方塊始終都不會出現在畫面的左上角,我用繪圖軟體把畫面照下來,測量了一下左上角正常的區域,大小剛好是 640×480,這個數字相當敏感,八成就是伺服器解析度的問題。
接著檢查 /var/log/Xorg.0.log
這個紀錄檔,用 640
這個關鍵字去搜尋,果然找到這一段:
[575462.042] (==) NVIDIA(0): No modes were requested; the default mode "nvidia-auto-select" [575462.042] (==) NVIDIA(0): will be used as the requested mode. [575462.042] (==) NVIDIA(0): [575462.042] (--) NVIDIA(0): No enabled display devices found; starting anyway because [575462.042] (--) NVIDIA(0): AllowEmptyInitialConfiguration is enabled [575462.043] (II) NVIDIA(0): Validated MetaModes: [575462.043] (II) NVIDIA(0): "NULL" [575462.043] (II) NVIDIA(0): Virtual screen size determined to be 640 x 480 [575462.043] (WW) NVIDIA(0): Unable to get display device for DPI computation. [575462.043] (==) NVIDIA(0): DPI set to (75, 75); computed from built-in default
因為我的顯示卡都沒有接螢幕,所以能調整的只有虛擬螢幕解大小(virtual screen size),而這裡 NVIDIA 自動將虛擬螢幕解大小設定為 640 x 480
,導致 ParaView 伺服器畫圖時的畫面不夠大,畫不出來。
找到原因之後,再查詢 nvidia-xconfig
的 man page:
man nvidia-xconfig
找到這一個設定虛擬螢幕解大小的參數:
--virtual=WIDTHxHEIGHT, --no-virtual Specify the virtual screen resolution.
加上去之後,問題就解決了,我目前將虛擬螢幕解大小設定為 1600x1200
,這個大小沒有一定的標準,要看 ParaView client 的畫面大小而定,只要不要比 client 畫面還小就可以了。
越過防火牆
由於 ParaView server 與 client 架構需要用到特定的 tcp 連接埠溝通,很容易就會遇到防火牆阻擋的問題而不能運作,最簡單的解決方法就是使用 SSH tunnel,在 client 執行:
ssh -NL 11111:localhost:11111 seal@my.server.com
這樣 ParaView 就可以透過 localhost:11111
連到 my.server.com
的 localhost:11111
。
OpenMPI 與防火牆問題
如果在執行多節點的 MPI 程式時,出現這樣的訊息:
[my.server.com:36639] [[65510,0],1] tcp_peer_send_blocking: send() to socket 9 failed: Broken pipe (32) -------------------------------------------------------------------------- ORTE was unable to reliably start one or more daemons. This usually is caused by: * not finding the required libraries and/or binaries on one or more nodes. Please check your PATH and LD_LIBRARY_PATH settings, or configure OMPI with --enable-orterun-prefix-by-default * lack of authority to execute on one or more specified nodes. Please verify your allocation and authorities. * the inability to write startup files into /tmp (--tmpdir/orte_tmpdir_base). Please check with your sys admin to determine the correct location to use. * compilation of the orted with dynamic libraries when static are required (e.g., on Cray). Please check your configure cmd line and consider using one of the contrib/platform definitions for your system type. * an inability to create a connection back to mpirun due to a lack of common network interfaces and/or no route found between them. Please check network connectivity (including firewalls and network routing requirements). --------------------------------------------------------------------------
這個有可能是系統的防火牆把 OpenMPI 的通訊擋掉了,可以嘗試關閉防火牆來解決。
systemctl stop firewalld
另外如果是沒有設定好預設的 MPI 環境,錯誤訊息也是類似這樣,但可能會多出一行:
bash: orted: command not found
這個問題就是按照上面的描述的方式設定好 OpenMPI 環境即可。
OpenMPI 與虛擬網路卡問題
由於我的兩台伺服器上都有安裝 KVM,其 NAT 網路所使用的 virbr0
虛擬網路卡(IP 位址為 192.168.122.1
),會造成 OpenMPI 在執行時出錯,大部分的狀況是 mpirun
執行之後就卡住沒反應,也有時候會出現這樣的訊息:
[server2][[62439,1],1][btl_tcp_endpoint.c:818:mca_btl_tcp_endpoint_complete_connect] connect() to 192.168.122.1 failed: Connection refused (111) [server1][[62439,1],0][btl_tcp_endpoint.c:818:mca_btl_tcp_endpoint_complete_connect] connect() to 192.168.122.1 failed: Connection refused (111)
通常這個問題的解決方法應該是按照 StackOverflow 的解法,並參考 OpenMPI 的文件,明確指定 OpenMPI 要使用的網路介面或是子網域範圍:
mpirun --mca btl_tcp_if_include eth0 ...
不過由於我的兩台機器網路卡又不一樣,所以乾脆直接把兩台的 virbr0
直接關掉:
sudo ifconfig virbr0 down
這樣就正常了,但這不是個好辦法。
若要直接刪掉這個 KVM 的 NAT 虛擬網路卡介面,可參考 nixCraft 的文件。
無法建立 OpenGL 繪圖視窗
有時候 X Window 執行太久,在 ParaView client 連線至伺服器時,會出現這樣的錯誤:
ERROR: In /work/seal/ParaView-v5.3.0-RC1/VTK/Rendering/OpenGL2/vtkXOpenGLRenderWindow.cxx, line 809 vtkXOpenGLRenderWindow (0x1118940): failed to create offscreen window ERROR: In /work/seal/ParaView-v5.3.0-RC1/VTK/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx, line 721 vtkXOpenGLRenderWindow (0x1118940): GLEW could not be initialized.
遇到這個狀況時,我是將 X Window 重新啟動即可解決。
sudo service gdm restart DISPLAY=:0 sudo xhost +
參考資料:ParaView Wiki、LLNL、surfsara、ParaView on Vis Clusters 簡報檔