A Raspberry Pi találkozik a felhővel

Bevezető

Gyorsítsuk PC segítségével a programfordítást, avagy elosztott fordítás különböző architektúrák között. A leírás nem csak Raspberry Pi tulajdonosok számára lehet hasznos, hanem bárkinek, aki más hasonló fejlesztői rendszert használ.

Biztosan találkoztatok már a Raspberry Pi névvel. Ha mégsem, akkor ajánlom az ismerkedéshez a témában korábban megjelent Logout.hu írásokat, a PH! fórumát, valamint a hivatalos tudástárat. Emlékeztetőül lássuk az összetéveszthetetlen logót, amely a készülékhez és a mögötte álló alapítványhoz kapcsolódik:

(IMG:/dl/upc/2012-11/02/23987_eubiggxykktjknix_raspi_colour_r_300.png)(/IMG)
“Raspberry Pi is a trademark of the Raspberry Pi Foundation”

Maga a készülék egészen ígéretes azok számára, akik tudják mire használják. Mivel a RasPi ARM architektúrára épül, ezért a rá készített linux disztribúciókon kívülről származó programokat magunknak szükséges lefordítani. Egy összetett program lefordítása még erős asztali gépen is hosszú perceket vagy órákat eltarthat, s ez még inkább igaz ezen a pöttöm masinán.

A következő oldalakon a technológiai áttekintés után megismerkedünk azzal, hogyan lehetséges normál számítógép sebességével megtámogatni a RasPi-n futó programfordítást.

Áttekintés, elosztott fordítás

Elosztott rendszerek

Hirdetés

A számítógépek többsége idejének legnagyobb részét tétlenséggel tölti. Használhatnánk más gépek erőforrásait, amikor arra szükségünk van? Az egyik lehetséges megoldás az Icecream, vagy röviden icecc használata. Bővebb leírást az OpenSuse oldalán találhatunk róla.

A működésének lénye, hogy a gépekre telepítve egy szolgáltatást futtat a háttérben, amely elfogad feladatokat a farm többi tagjától. A farmban résztvevő gépek közti munka elosztását egy koordinátor gép végzi, ami maga is részt vehet a munkában. Ezt elosztott fordításnak is nevezhetjük.
A legismertebb fordítócsomag linux alá a GCC. Amikor fordítást végzünk, akkor a valójában az icecc program indul el és az futtatja az igazi gcc fordítót a farm valamelyik alkalmas gépén.

Mivel általában több szálon egyszerre több programrészletet fordítunk, így hasonlóan rövidülhet a művelet összideje, mintha egy sokmagos gépet használnánk. Mivel a különböző gépek szoftveres szempontból is különbözőek lehetnek, így az icecc használatához egy "toolchain"-t kell készíteni előbb, s ez a fordítócsomag fel fog kerülni automatikusan minden nekünk dolgozó gépre.

Fordítás más architektúrára, cross compile

Felmerül egy másik probléma is a fordítással kapcsolatban. Ahogy már szóba került a RasPi ARM architektúrát használ, ami nem kompatibilis bináris szinten az asztali gépeinkben elterjedt inteltől származó x86 architektúrákkal. Ha több RasPi-vel is rendelkezünk, akkor azokból már összeállítható egy fordító farm, viszont a pécé ebbe még nem tud besegíteni, mert az nem futtathat ARM programot.

Alapvetően a gcc fordító olyan architektúrájú eredményt generál, mint amilyen saját maga. Persze mindenre van okos megoldás. Használjunk olyan cross compiler gcc-t, amely x86 gépen futtatható, de a kimenete ARM bináris. Ebből már készíthetünk olyan toolchain-t az icecc számára, amely pécéken futtatható és mégis megfelelő eredményt ad vissza. Egy ilyen fordítót nem olyan egyszerű létrehozni, aki maga akarja elkészíteni, annak segítséget nyújthat a Crosstool-NG. Szerencsénkre az alapítvány már készített egy számunkra is használható változatot, így lényegesen könnyebben boldogulhatunk a feladattal.

Folytassuk konkrét lépésekkel a kereszt-platform fordítófarmunk felállítását.

Kereszt-platform fordítófarm beállítása: RasPi

A RasPi konfigurálása

A most aktuális 2012-10-28-wheezy-raspbian rendszert vesszük alapul a munkánkhoz, ezt a hivatalos oldalról tölthetjük le. Mivel ez a leírás inkább közép-haladóknak szól, így nem részletezném túlságosan az alapvető lépéseket, azokról részletes információk találhatóak a már linkelt oldalakon.

Ezt a lemezt dd vagy Windows alól a Win32DiskImager programmal írhatjuk memóriakártyára. Végezzük el a szokásos használatba vételi lépéseket: kártyán lévő hely kihasználása, tuning és memória elosztás beállítások.

A rendszerben a 4.6-os gcc az alapértelmezett. Telepítsük fel a 4.7-eset. Erre a lépésre azért van szükség, mert a készen elérhető cross-compiler is 4.7-es.

sudo apt-get update

sudo apt-get install gcc-4.7*

Ezek után következik az icecc telepítése.

sudo apt-get install icecc icecc-monitor

Ha ezzel is megvagyunk, akkor állítsuk be, hogy az alapértelmezett gcc 4.6 helyett a 4.7 és az icecc is használható legyen:

sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 10
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.7 20
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/icecc 30

sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.6 10
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.7 20
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/icecc 30

Ellenőrizzük, hogy az icecc lett-e az alapértelmezett, ha nem az, akkor válasszuk ki őt:

sudo update-alternatives --config gcc
sudo update-alternatives --config g++

A konfigurációs fájlok módosításához valamilyen általunk ismert szerkesztőprogramra is szükség lesz, ha nem vagyunk jártasak a vi vagy a nano programok kezelésében, akkor telepíthetjük az mc-t:

sudo apt-get install mc

Állítsuk be az icecc demon szolgáltatás paramétereit:

sudo mcedit /etc/icecc/icecc.conf

A szerkesztőben a következő paramétereket érdemes megváltoztatni:

ICECC_NETNAME="iceccfarm"
ICECC_MAX_JOBS="1"
ICECC_ALLOW_REMOTE="yes"
ICECC_SCHEDULER_HOST="192.168.0.101"

Ezek lényege, hogy mi legyen a farm neve, 1 feladatot fogadjon egyszerre, távolról kapott feladatokkal is foglalkozhasson, mi a farm koordinátorának címe. A koordinátor gép normál pécén futó linux lesz, ennek beállításáról később lesz szó. Ha valaki más operációs rendszer használ a mindennapokban, az se ijedjen meg, lesz rá megoldás a leírásban.

A változtatás alkalmazásához indítsuk újra az icecc demon-t.

sudo service icecc restart

Ahhoz, hogy jól működjön a fordítás, még néhány környezeti változót is be kell állítani. Ezt érdemes a .bashrc végéhez fűzni, így nem kell állítgatni minden belépés után.

mcedit ~/.bashrc

export ICECC_CC=gcc-4.7
export ICECC_CXX=g++-4.7
export MAKEFLAGS=-j10
export USE_SCHEDULER=192.168.0.101
export ICECC_VERSION="armv6l:/home/pi/arm-native.tar.gz,i686:/home/pi/arm-cross-i386.tar.gz"

A MAKEFLAGS értékéül adott -j10 határozza meg, hogy hány párhuzamos szálon fordítson a gcc. Az ICECC_VERSION azt tartalmazza, hogy melyik platformot használó másik gépre melyik toolchain-t kell küldeni, hogy fordítani tudjon számunkra megfelelő eredményt. Ezeket még nem hoztuk létre, előbb az arm rendszerek számára készítsük el a következő parancs kiadásával:

icecc --build-native

Ez a következőhöz hasonló kimenetet fog mutatni:

adding file /usr/bin/gcc
adding file /usr/lib/arm-linux-gnueabihf/libcofi_rpi.so
adding file /lib/arm-linux-gnueabihf/libc.so.6
adding file /lib/ld-linux-armhf.so.3
adding file /lib/arm-linux-gnueabihf/libm.so.6
adding file /usr/bin/g++
adding file /usr/bin/as
adding file /usr/lib/libopcodes-2.22-system.so
adding file /usr/lib/libbfd-2.22-system.so
adding file /lib/arm-linux-gnueabihf/libdl.so.2
adding file /lib/arm-linux-gnueabihf/libz.so.1
adding file /lib/arm-linux-gnueabihf/libgcc_s.so.1
adding file /usr/bin/cc1=/usr/lib/gcc/arm-linux-gnueabihf/4.7/cc1
adding file /usr/lib/arm-linux-gnueabihf/libmpc.so.2
adding file /usr/lib/arm-linux-gnueabihf/libmpfr.so.4
adding file /usr/lib/arm-linux-gnueabihf/libgmp.so.10
adding file /usr/bin/cc1plus=/usr/lib/gcc/arm-linux-gnueabihf/4.7/cc1plus
adding file /usr/lib/gcc/arm-linux-gnueabihf/4.7/liblto_plugin.so
adding file /etc/ld.so.conf=/tmp/icecc_ld_so_confcEGZSC
creating e0a922d958057f5c638fc358305129a2.tar.gz

A toolchain egy véletlenszerűen generált néven kerül mentésre, ezt nevezzük át:

mv e0a922d958057f5c638fc358305129a2.tar.gz arm-native.tar.gz

Az x86 rendszerek számára normál gépen futó linux alól készítünk toolchaint, ami a most következő lépés lesz. Az ott elkészített toolchaint ne feledjük majd a RasPi-re felmásolni (arm-cross-i368.tar.gz néven).

Kereszt-platform fordítófarm beállítása: Ubuntu

A pécé beállítása

A nemrég megjelent Ubuntu 12.10-es rendszert fogom használni. Több okból esett rá a választás. Egyrészt hasonló Debian alapú rendszer, mint a RasPi számára ajánlott Raspbian. Másrészt alapból a 4.7-es gcc változatot tartalmazza. Azért fontos, hogy 4.7-es legyen, mert a készen elérhető cross-compiler is 4.7-es. Persze használhatunk más verziójú gcc-t is, de akkor magunknak kell biztosítani azt, hogy ugyanaz a verzió fusson mindenütt. Különböző verziójú gcc-k együttesen fura hibaüzeneteket eredményezhetnek. Ubuntuból a 32bit-es változatot használhatjuk toolchain készítésre, mert a kész cross-compiler is 32bit-es. Ha már 64bit-es rendszert használunk, akkor a következő bekezdés erre is jó megoldás lehet. Ha már megvan a toolchain, azt a 64bit-es rendszer is tudja futtatni.

Mielőtt belevágnánk a konfigurálásba, fontos megemlítenem, hogy azok számára is lehetséges az Ubuntu futtatása, akik alapvetően más rendszert használnak a hétköznapokban. Ehhez nem kell újratelepíteni a számítógépet, hanem egy kis virtualizálást vethetünk be. VirtualBox vagy VmWare Player segítségével hozzunk létre egy új virtuális gépet. A processzorok számát érdemes annyinak megadni, mint a fizikai magok száma.

Ha csak elosztott fordításhoz használjuk a virtuális gépet, akkor a konfigurálás után ki is kapcsolhatjuk a grafikus felületét, hogy ne egyen feleslegesen erőforrást. Ezt a grub megfelelő paraméterének átállításával érhetjük el:

sudo mcedit /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="text"

Majd futtassuk

sudo update-grub

Térjünk rá az Ubuntu 12.10 32bit beállítására. Fontos, hogy úgy állítsuk be a hálózatunkat, hogy a pécé, amelyen a koordinátor is fut, mindig azonos ip címet kapjon. Ha routerre kötve használjuk a gépeket, akkor annak a beállító felületén mondhatjuk meg, hogy a (virtuális)gép MAC címéhez mi tartozzon. A virtuális gépeknél érdemes a hálózati kapcsolatot bridge módra venni, hogy teljesen önálló gépként legyen elérhető hálózaton át.

A többi lépés hasonló lesz, mint ahogyan a RasPi esetén tettük. Telepítsük a csomagokat:

sudo apt-get install mc git icecc icecc-monitor

Állítsuk be az icecc demon szolgáltatás paramétereit:

sudo mcedit /etc/icecc/icecc.conf

A szerkesztőben a következő paramétereket érdemes megváltoztatni:

ICECC_NETNAME="iceccfarm"
ICECC_MAX_JOBS="4"
ICECC_ALLOW_REMOTE="yes"
ICECC_SCHEDULER_HOST="192.168.0.101"

Az ICECC_MAX_JOBS értékének a processzormagok számát érdemes megadni. Mivel a gépünk lényegesen erősebb, mint a RasPi, így nyugodtan megadhatjuk akár a dupláját is.

A változtatás alkalmazásához indítsuk újra az icecc demon-t.

sudo service icecc restart

Környezeti változóban megadhatunk néhány paramétert. Ezt a .bashrc-be is betehetjük:

export ICECC_CC=gcc-4.7
export ICECC_CXX=g++-4.7
export USE_SCHEDULER=192.168.0.101

Ha x86-os fordításra is használni szeretnénk több gépet, akkor még néhány változtatásra szükség lehet, ahhoz hasonlóan, mint ahogy a RasPi esetén tettük. Most csak az írás céljához közel álló lépéseket mutatom be.

Hozzunk létre egy x86-os toolchain-t a következő paranccsal:

icecc --build-native

Ennek eredményéül egy véletlenszerűen elnevezett fájlt kapunk - nevezzük most generalt-faj.tar.gz-nek -, amit csomagoljunk ki egy könyvtárba:

mkdir toolchain
cd toolchain
tar -xzvf ../generalt-fajl.tar.gz

Hasonlítsuk össze a RasPi rendszeren generált fájlok listáját az itt kapott fájlok listájával. Az esetemben egy fájllal kevesebb található az x86 toolchain-ben, pótoljuk azt:

cp /lib/i386-linux-gnu/libm.so.6 ~/toolchain/lib/

Már majdnem készen vagyunk, azonban ez még x86-os binárisokat generálna, ami nem túl használható a RasPi számára. Mivel a Raspbian rendszer hardfp, ezért ilyen cross-compiler-t töltünk le az alapítvány tárhelyéről:

git clone https://github.com/raspberrypi/tools ~/tools

cp ~/tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/arm-bcm2708hardfp-linux-gnueabi/bin/ar ~/toolchain/usr/bin/ar

cp ~/tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/arm-bcm2708hardfp-linux-gnueabi/bin/gcc ~/toolchain/usr/bin/gcc

cp ~/tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/arm-bcm2708hardfp-linux-gnueabi/bin/g++ ~/toolchain/usr/bin/g++

cp ~/tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/libexec/gcc/arm-bcm2708hardfp-linux-gnueabi/4.7.1/cc1 ~/toolchain/usr/bin/cc1

cp ~/tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/libexec/gcc/arm-bcm2708hardfp-linux-gnueabi/4.7.1/cc1plus ~/toolchain/usr/bin/cc1plus

Igazítsuk meg a jogosultságokat

chmod 0775 ~/toolchain/usr/bin/*

Csomagoljuk be az eredményt

cd ~/toolchain
tar -czvf arm-cross-i386.tar.gz *

Ezt a fájlt másoljuk a RasPi-re és már majdnem készen állunk a fordításra.

Még el kell indítanunk a koordinátort a pécén:

icecc-scheduler -n iceccfarm -vvv

Ha háttérben szeretnénk futtatni, akkor -d kapcsolót is adhatunk neki. Készen is vagyunk.

Gyakorlati tapasztalatok

Icemon

Látványosan meg is jeleníthetjük a fordítófarmunk állapotát. Ehhez adjuk ki a következő parancsot a pécén:

icemon &

A képen csaltam kicsit, ugyanis valójában nem látható egyszerre minden gép adatlapja, de így jobban bemutatható. Ebben a farmban négy gép vesz részt, Star view:

- Raspberry Pi, Raspbian, armv6l
- Thinkpad T7100 processzorral, 2 maggal, 32bit-es Ubuntu 12.10
- Egy Windows-t futtató, 2 magos T7300 gép, amelyen egy 32bit-es Ubuntu 12.10 fut VirtualBox alatt karakteres módban.
- Desktop gép, 4 magos Phenom2 processzorral, 64bit-es Ubuntu 12.10

A színeket nem tudom mi alapján választja a rendszer, szerintem véletlenszerűen.

Jóval informatívabb a detailed host view:

Ezen a nézeten láthatjuk részletesen, hogy melyik gépen milyen feladatok futnak.

Ha kiesik egy gép a farmról, az sem okoz problémát. Ha a koordinátor leáll, akkor sem szakadna meg a fordítás, csak nem segítenének benne a többiek.

Néhány sebesség adat

Egyik kedvenc programom volt az első tesztalany, a tvheadend stream szerver:

RasPi egymaga: 380 másodperc
RasPi + T7100 noti: 90 másodperc
RasPi + mindent bele: 50 másodperc

Mint látható, egészen komoly gyorsulás tapasztalható fordításkor. Az viszont, hogy nem megy 50 másodperc alá akkor sem, ha még 8 processzormag dolgozik a RasPi alá, azt mutatja, hogy szegény pára nem tudja elég gyorsan etetni feladattal a pécéket. Egy sok segítővel ellátott erős pécé 1 másodperc alatt végez.

Egy másik kevésbé pontos tesztet is futtattam, linux kernel fordítása (script ami leszedi a készüléken futó kernel forrását Raspbian / Debian rendszerhez: [link]) :

RasPi magában: 6 óra
RasPi + mindent bele: 3 óra

Nos, itt már kisebb a különbség. Futás közben látva a gépek tétlenségét valójában 2-4 processzormag is elegendő lenne hozzá, mivel sok olyan része van a fordításnak, amit nem tud kiosztani a RasPi.

A tanulság, hogy megéri a pécénk segítségét igénybe venni, de nem is kell túlzásba vinni. Persze, ha több RasPi dolgozik különböző feladatokon, akkor mindegyik kaphat segítséget.

Más lehetőségek

Létezik olyan cross compile megoldás is amikor csak pécék segítségével végezzük a fordítást. Ilyen fordító elérhető az alap Ubuntu rendszerre is, például az elinux.org oldalán is találni rá példát. Ebben az esetben is van lehetőség icecc farm használatára, csak a megfelelő toolchain összeállítását kell elvégezni, ami nem feltétlen nehéz az itt leírtak alapján. De az már egy másik történet...

Azóta történt

  • Hőmérséklet mérő Pi

    Egy kis bevezető után bemutatom a hőmérséklet mérésének egyszerű megvalósítását Raspberry Pi-al.