2016/01/12

Raspberry Pi:distcc分散式編譯器系統(4塊Model B+板子)

之前的文章「使用distcc加速編譯(Raspberry Pi+Raspbian)」,把編譯工作分散到2塊Model B板子上,加快建置速度。這一篇只是改成4塊Model B+板子而已,但在pump模式與組態設定檔的部份有些許更新;話說回來,其實應該改用Pi Zero才對。

硬體部分是4塊Raspberry Pi Model B+板子,記憶卡皆是SanDisk Ultra Micro SD 8GB,電源部分採用anidees的產品5 Port USB Charger 25W,然後使用乙太網路線連接到ZyXEL的GS-108B(8埠桌上型超高速乙太網路交換器),這台交換器再接到Wi-Fi無線路由器,連上網路。

左邊乙太網路交換器,中間4塊rpi板子,右邊電源供應器。

作業系統是Raspbian Jessie Lite(2015-11-21),初始設定(區域設置、鍵盤配置、時區、等等)完成後,更新套件清單並升級:
$ sudo apt-get update; sudo apt-get dist-upgrade -y

distcc可把C/C++/Objective-C程式的編譯工作,分散到網路上的別台機器。distcc本身不是編譯器,而是編譯器的前端介面,預設行為是把前置處理完畢的原始程式檔,傳送到給另一台機器進行編譯,因此另一台機器需要安裝適當的編譯器,並且執行distccd,接收編譯要求。

底下皆以gcc為範例,Raspbian預設已安裝:
$ gcc --version
gcc (Raspbian 4.9.2-10) 4.9.2

首先安裝distcc套件,每一台機器都要安裝:
$ sudo apt-get install distcc

安裝後會有指令distcc、指令distccd、以及其他。

$ distcc --version
distcc 3.1 arm-unknown-linux-gnueabihf
  (protocols 1, 2 and 3) (default port 3632)
  built Nov  7 2014 11:06:15
Copyright (C) 2002, 2003, 2004 by Martin Pool.
Includes miniLZO (C) 1996-2002 by Markus Franz Xaver Johannes Oberhumer.
Portions Copyright (C) 2007-2008 Google.

distcc comes with ABSOLUTELY NO WARRANTY.  distcc is free software, and
you may use, modify and redistribute it under the terms of the GNU
General Public License version 2 or later.

Built with Zeroconf support.

Please report bugs to distcc@lists.samba.org

底下先以手動方式進行,之後會記錄在組態設定檔。

首先試試一般編譯需要多少時間,以zlib這套程式庫為測試對象,下載、解壓縮、組態、開始以make建置。此處不安裝,所以不執行指令make install。
$ wget http://zlib.net/zlib-1.2.8.tar.gz
$ tar zxvf zlib-1.2.8.tar.gz
$ cd zlib-1.2.8
$ ./configure
$ time make test

結果如下:
...省略...
zlib version 1.2.8 = 0x1280, compile flags = 0x55
uncompress(): hello, hello!
gzread(): hello, hello!
gzgets() after gzseek:  hello!
inflate(): hello, hello!
large_inflate(): OK
after inflateSync(): hello, hello!
inflate with dictionary: hello, hello!
                *** zlib 64-bit test OK ***

real    2m4.111s
user    1m59.470s
sys     0m2.780s

嗯,花了2分4秒。接下來試試分散編譯,先刪除之前的東西,重新解壓縮,這樣比較準。

以底下指令設定欲接受分散編譯要求的機器,我的每台機器(4塊rpi板子)皆位於同一區域網路內,網址是192.168.1.x,所以如下設定:
$ distccd --daemon --allow 127.0.0.1 --allow 192.168.1.0/24

distccd扮演伺服器的角色,負責接收distcc傳來的編譯要求,以--allow設定可傳進編譯要求的機器。

我把4塊板子的主機名稱(hostname)分別設為rpi_p1、rpi_p2、rpi_p3、rpi_p4。如下以環境變數設定要把編譯要求丟到哪些機器上:

rpi_p1增加環境變數,
$ export DISTCC_HOSTS="rpi_p2 rpi_p3 rpi_p4 localhost"

rpi_p2增加環境變數,
$ export DISTCC_HOSTS="rpi_p3 rpi_p4 rpi_p1 localhost"

rpi_p3增加環境變數,
$ export DISTCC_HOSTS="rpi_p4 rpi_p1 rpi_p2 localhost"

rpi_p4增加環境變數,
$ export DISTCC_HOSTS="rpi_p1 rpi_p2 rpi_p3 localhost"

代表distcc可傳送編譯要求的機器。

然後開始建置zlib,指令如前,但要加上CC=distcc。
$ time make test CC=distcc

咦,居然花了2分8秒,比以前還慢啊!因為指令下錯了,還需要加上-j,因為我有四台機器,所以先試試-j4,
$ time make test -j4 CC=distcc

花了43秒,比之所花時間(2分4秒)的四分之一(31秒)還要多,額外的時間花在分散工作、傳輸等等。我試著改成-j8,花費39秒。

嗯,很不錯,讓我們試著新增或修改組態設定檔吧,不必每次自己手動輸入指令,其實就是把之前的東西寫入檔案,如此而已。首先修改/etc/default/distcc,應含如下內容(其餘東西不變):
STARTDISTCC="true"
ALLOWEDNETS="127.0.0.1 192.168.1.0/24"
LISTENER="0.0.0.0"

STARTDISTCC設為"true"代表開機時會自動執行distccd;ALLOWEDNETS則設定允許哪些機器可傳入編譯要求;LISTENER則代表要聆聽哪個網路介面,"0.0.0.0"代表全部。

接下來是修改/etc/distcc/hosts,此檔是給整台機器用的;若個人帳號有不同設定,則是放在~/.distcc/hosts裡:
rpi_p1的內容:
rpi_p2 rpi_p3 rpi_p4 localhost

rpi_p2的內容:
rpi_p3 rpi_p4 rpi_p1 localhost

rpi_p3的內容:
rpi_p4 rpi_p1 rpi_p2 localhost

rpi_p4的內容:
rpi_p1 rpi_p2 rpi_p3 localhost

搞定,然後重開機,便能以之前介紹的make指令進行編譯。

3.0版的distcc開始支援pump模式,除了編譯工作、也把前置處理工作分散到別台機器,因此別台機器須擁有相同的系統標頭檔,至於應用程式(建置對象)特有的標頭檔,仍由distcc傳輸;另外還有壓縮功能,速度應會更快。先安裝套件distcc-pump,每一台機器都要:
$ sudo apt-get install distcc-pump

rpi_p1修改環境變數,
$ export DISTCC_HOSTS="--randomize localhost rpi_p2,cpp,lzo rpi_p3,cpp,lzo rpi_p4,cpp,lzo"

rpi_p2修改環境變數,
$ export DISTCC_HOSTS="--randomize localhost rpi_p3,cpp,lzo rpi_p4,cpp,lzo rpi_p1,cpp,lzo"

rpi_p3修改環境變數,
$ export DISTCC_HOSTS="--randomize localhost rpi_p4,cpp,lzo rpi_p1,cpp,lzo rpi_p2,cpp,lzo"

rpi_p4修改環境變數,
$ export DISTCC_HOSTS="--randomize localhost rpi_p1,cpp,lzo rpi_p2,cpp,lzo rpi_p3,cpp,lzo"

其中--randomize代表先打亂接受分散編譯要求的機器,cpp代表有pump模式,lzo代表要壓縮。建置指令如下:
$ time distcc-pump make test -j4 CC=distcc

花了42秒,差不多,或許跟測試對象有關,我只有4台機器,效果不明顯吧。同樣的,也可以把此處設定放進/etc/distcc/hosts或~/.distcc/hosts。

在distcc執行時,以指令distccmon-text可得知其狀態:
$ distccmon-text
  3339  Compile     ngx_http_variables.c                          localhost[0]
  3350  Preprocess                                                localhost[2]
  3343  Compile     ngx_http_script.c                                rpi_p3[0]
  3347  Compile     ngx_http_upstream.c                              rpi_p4[0]


我又試著建置nginx(1.9.9版), 只一台機器需要8分鐘,四台機器與pump模式的話,需要4分鐘18秒。

搞定收工,用紙盒幫rpi做個家吧,很簡陋。
割開,露出電源插座。
割開,露出網路插座。

參考資料:

No comments:

Post a Comment