total descendants::4 total children::1 1 ❤️
|
Uz dlho som chcel zistit, aky velky problem je zintegrovat nejaky relativne novy XCode s distcc (a volitelne ccache), aby bolo mozne build spustit distribuovane bez toho aby projekt potom vyzeral ako kambodzska dzubgla po bombardovani. XCode 3 (a mozno aj 4) tuto funkciu mal out of box, ale potom to Crapple cele odrezal bez nahrady. Kedze XCode 8 zavadza podpisovanie pluginov, tak cestou vytvorenia vlastneho pluginu sa ist nedalo (v skutocnosti nejaka taka vec existuje, ale s relativne novym XCode nefunguje). Tak som na to siel cestou tradicnejsou. Distcc by sa s build systemom mal integrovat tak, ze sa setne premenna CC, pripadne CXX tak, aby spustila distcc namiesto prekladaca. No lenze to by s XCode nebolo tak jednoduche. --- Instalacia --- Ale pekne poporiadku. Ako vobec distcc rozchodit? Alternativa 1 je nainstalovat ho cez homebrew. To konkretne mne nefungovalo, pretoze oficialna konfiguracia na Mac buildy pre nas projekt je XCode 7.3 + masox Sierra. Ze to nikdy nebola podporovana kombinacia nevadi. Funguje to a to je hlavne. Viva la corporashun. Takze srat na homebrew (pretoze ten hned pri starte vypicuje, ze XCode 7 + Siera je nonono) a pojdeme na to pekne rucne strucne. Na kazdej masine, ktora sa ma pouzivat ako build worker treba: 0. Mat nainstalovany XCode. Vzhladom k podstate procesu je prakticky uplne irelevantne, aky operacny system na danom Macu bezi (dokonca by to teoreticky nemusel byt ani Mac a ten system nemusel byt masox), dolezite je len pouzit (v najjednoduchsom pripade = mat) rovnaku verziu prekladaca (XCode-u). 1. Nainstalovat autohell tools. Tu funguje svata trojica (./configure && make && make install) prefixnuta curl a tar -xf, v niektorych pripadoch aj ./autogen.sh. Z webu projektu GNU treba stiahnut autoconf, automake a libtool a skompilovat + nainstalovat v tomto poradi (ten posledny mozno nie je potrebny, ale istota je laserovy kanon). 2. Potom treba stiahnut distcc a naaplikovat nanho tento patch. Ten patch je sice v repozitari, ktory sa tvari ako nejaky fork zdrojakov distcc ale v skutocnosti je to len nejaky cinsky autopatchovaci bordel a okrem toho patchu tam nie je nic uzitocne. Navyse autopatchovaci bordel nefunguje, pretoze obsahuje uz neplatne linky na SVNkove repozitare. 3. Vysledny kod patchnuteho distcc treba skompilovat a nainstalovat. Tu odporucam vsade explicitne zadat do configure.sh --prefix=/usr/local. Istota je laserovy kanon. V tomto momente by mal pokus o skompilovanie nejakeho zdrojaku v takejto podobe: distcc clang -o test test.c dopadnut uspechom. --- Konfiguracia --- Tato cast je dobre pokryta v manpage distcc tak budem strucny. Na masine (nazyvajme ho klient) z ktorej sa bude build spustat treba v subore ~/.distcc/hosts zoznam IP adries hostov, ktore su sucastou clustera. Uvadzat sa mozu trebars vo formate jedna IP na riadok. Specialny vyznam ma slovo "localhost". Okrem zjavneho faktu, ze sa jedna o lokalnu masinu navyse definuje, ze build sa spusti priamo a nebude sa prevolavat distccd (teda sa obide sietovy stack). Takze subor moze vyzerat napr.: 10.10.1.154/12 localhost/1 Tie cisla za lomitkami neurcuju subnet, ale pocet jobov, ktore je dovolene klientovi na ktory worker zadat. Neurcuje to, kolko jobov moze na workerovi bezat celkovo, ale iba to, kolko jobov moze na jednom workerovi paralelne zadat jeden klient. Takto je mozne postavit si vypoctovu (kompilovaciu) farmu, na ktorej bude tasky zadavat viacero klientov paralelne bez toho aby jeden klient vyhulil celu farmu na 100%. Ak sa localhost neuvedie v zozname hostov vobec, *nebudu* sa na lokalny stroj zadavat kompilacne joby vobec. --- Spustenie --- Na kazdom workeri treba spustit distcc daemon, co je proces, ktory pocuva na sietove pripojenia a spusta lokalne build joby. Da sa to elegantne zabalit do plistu, ktory sa potom podhodi launchd, ale ja som lenivy, tak som ho zatial spustal z konzoly: distccd --allow 10.10.1.0/24 --daemon --no-detach --jobs 14 Prepinac --allow urcuje z akeho subnetu su povolene spojenia, takze si na build farme nebude buildovat hocikto hocico. Takychto direktiv je mozne uviest viacero a spravit si tak fine-grain pristupove prava. Prepinace --daemon a --no-detach hovoria, ze distcc bude pocuvat na sieti samo za seba (a nebude pouzivat napr. inetd) a ze sa neodpoji od terminalu (takze ho pojde zakillovat Ctrl-C). To druhe sa pri spustani cez launchd asi celkom nehodi. Posledny prepinac urcuje, kolko paralelnych jobov server dovoli bezat paralelne. Toto cislo sa aplikuje na vsetkych klientov ktori si joby zadaju suhrnne. Ked je hosts file nakonfigurovany a demony spustene, malo by zopakovanie testu s: distcc clang -o test test.c sposobit, ze job sa spusti na niektorom inom stroji (za predpokladu, ze je localhost uvedeny inde ako na prvom mieste). --- Streamlining --- Aby boli dalsie kroky co najjednoduchsie, tak je celkom vhodne vytvorit si 2 symlinky: sudo ln -s `which distcc` /usr/local/bin/clang sudo ln -s `which distcc` /usr/local/bin/clang++ Tato zmena by mala sposobit, ze uz prachsproste spustenie: clang -o test test.c spusti kompilacny job na nejakom inom stroji v clusteri. Well done, to by sme mali, ale je to cele uplne na hovno, pretoze XCode to ma a bude mat v pazi. --- Integracia --- Aby to XCode v pazi nemal, je treba ho donutit nepouzit prekladac priamo, ale cez frontend distcc. A to nie je vobec hracka. Zalezi to hodne od toho, ako sa XCode vola. Vsetky metody maju ale spolocne nasledovne: Niekde na disku (idealne niekde velmi blizko zdrojakom) treba vytvorit subor Volaco.xcconfig. Ofc "Volaco" je volitelny string a ani nemusi mat velke prve pismeno nazvu. Ten subor by mal obsahovat jediny riadok: CC=/usr/local/bin/clang YMMV a mozete potrebovat aj nasledujuci riadok CXX=/usr/local/bin/clang++ Pri mojom projekte stacilo pouzit iba direktivu CC na buildovanie C-ckovych, C++kovych aj Objective-C (pripona .mm?) suborov a build bezal distribuovane. Tento subor potom treba vo finderi dragnut a v XCode dropnut do project browsera v sidebare. A potom ho treba pouzit. To sa robi tak, ze v project browseri sa klikne na topmost entry (modra ikona blueprintu s nazvom projektu), to otvori project settings page. Na tej treba opat vybrat projekt samotny (ja som tam mal automaticky vybraty niektory z targetov - kedze pouzivam CMake, tak ALL_BUILD). Po jeho vybere by malo okno zmenit vizual a mali by ostat len 2 zalozky: "Info" a "Build settings". Treba aktivovat zalozku "Info", V casti Configurations rozkliknut rozbalovaci zoznam projektu a v dropdown selektore namiesto "No configuration" vybrat "Volaco". Vzhladom k tomu, ze Crapple je jednotka v zmene layoutu formularov a prehadzovani nastaveni na miesta, kde by ich nikto nehladal (noaco, 11 z 10 psychologov tvrdi, ze je to intuitivne, tak je to dobre. Nevadi, ze v kazdej verzii je to inde) uvadzam, ze tento postup je platny pre XCode 7.3.1 a v buducnosti sa moze zmenit alebo uplne zmiznut. XCode trocha posroti a nasledne stlacenie Cmd-B by malo spustit distribuovany build. Momentalne ma distribuovany build este tu skvrnku na krase, ze bude bezat iba tolko paralelnych jobov, kolko by bezalo normalne na lokalnej masine (= tolko, kolko ma masina logickych corov). To je celkom nanic, pretoze faktor zrychlenia je limitne blizky 0. Takze, spustime v terminali na klientovi command: defaults write com.apple.dt.Xcode IDEBuildOperationMaxNumberOfConcurrentCompileTasks 24 kde cislo na konci znamena zelany pocet paralelnych jobov, ktore klient posle na cluster. Rozhodne nema zmysel toto cislo nastavovat na hodnotu podstatne vyssiu ako je pocet corov v clusteri celkovo. Mozeme skusit znova spustit build a vidime, ze sa nic nezmenilo. XCode si totiz hodnotu tej premennej (s kratkym, jasnym a lahko zapamatatelnym nazvom) checkuje iba pri spusteni a potom uz na nu kasle. Takze otocime XCode, spustime build a ten bude distribuovany. Hotovo. Tu sa scenar moze lisit podla toho, akym sposobom projekt vznikol. Ak je to standalone projekt, ktory bol od nuly naklikany v XCode, tak je robota hotova. XCode projekt po zmenach automaticky ulozil a toto nastavenie bude platne, kym ho niekto nezmeni. Ak je v subore hosts uvedeny localhost s nejakym rozumnym poctom jobov, nie je nutne distcc vypinat ani ak sa pocitac zoberie zo siete prec. Distcc je inteligentny na to, aby sa nezhaluzil, ak sa mu na worker v clusteri nepodari pripojit. Moze to ale mat nejake performacne penalty. Ak sa projekt generoval nejakym inym sposobom, napr. ako u nas CMake-om, tak po kazdej regeneracii projektu (po kazdej zmene CMakeLists.txt) bude nutne subor .xcconfig drag&dropnut do XCodu a nastavit jeho pouziti znova. No a v extremnom pripade, ktory mame my, ze sa XCode spusta cez wrapper shellscript, ktory zakazdym pred startom XCode regeneruje projekt (spusta sa cmake) je to uplne v riti, pretoze po kazdom spusteni XCode treba subor .xcconfig dragnut a aktivovat, lebo cmake prepise XCode projekt. Ani po troch hodinach googlenia a pozerania zdrojakov CMake-u som neprisiel na to, ako by sa to dalo zautomatizovat. --- Internal info --- Vsimavy citatel si nemohol nevsimnut, ze nikde v postupe sa nespomina kopirovanie zdrojakov na workery v clusteri, nastavovanie SDK, kopirovanie third parties, instalaciu kniznic. A ono to aj napriek tomu funguje. Je to zalozene na principe fungovania distcc v mode, ktory sa pri tomto postupe pouziva. V tomto rezime sa workery v clusteri pouzivaju *iba* na samotne kompilovanie. Preprocessing aj linkovanie sa deju na klientovi. Preprocessing sa na klientovi robi preto, ze: 1. je to relativne lacna a rychla operacia, ktora tradicne trva podstatne kratsie, nez samotna kompilacia (zvlast pri C++kovych zdrojakoch) 2. iba pri preprocessingu su potrebne hlavickove subory z SDK, takze nie je nutne mat vsetky subory, kniznice, 3Ps a ostatny brajgel vykopirovany vsade. Linkovanie sa robi na klientovi jednak preto, ze je k nemu treba kniznice SDKciek a zadruhe preto, ze to je job, ktory nejde dost dobre paralelizovat, takze je jedno, ci sa linkovanie vykona na lokalnom klientovi, alebo niekde na clusteri. Z toho vyplyva jeden velmi podstatny fakt a to ten, ze preprocessing a linking sa *vzdy* vykonava na lokalnom klientovi. To urcuje horny limit na pocet jobov, ktory ma zmysel nastavovat pre jedneho klienta (riadok s dlhym nazvom konfiguracnej volby konciaci cislom 24 trocha vyssie). Pocet jobov, ktore bude jeden klient schopny zadat do clustera je totiz fyzicky limitovany poctom jobov, ktore bude za jednotku casu klient schopny spreprocessovat. Tato schopnost klesa s tym, ako stupa pocet kompilacnych jobov, ktore ma lokalny klient dovolene vykonavat (preto je v mojom ukazkovom configu uvedene "localhost/1"). --- Performance --- Subor ~/.distcc/hosts je mozne za letu kedykolvek (aj pocas beziaceho buildu) upravovat. Nastavenie poctu jobov, ktore budu povolene na jednotlivych workeroch a celkovy pocet kompilacnych jobov zalezi jednak od pouziteho hardware-u a jednak od povahy samotneho software-u. Veci, ktore velmi intenzivne vyuzivaju napr. ciernu magiu z Boost preprocessing modulov asi zvladnu mensi stupen paralelizacie ako projekty, ktore maju includy primitivne. Takisto projekty s modulmi skladajucimi sa z velkeho mnozstva kompilacnych jednotiek na tom budu lepsie ako male moduly, kde sa kazdych par suborov caka na linkovanie. V mojom konkretnom pripade som buildoval projekt o 140 targetoch so 70 000 + subormi. Pri testovani bol klientom Mac Mini 2012 i5 s 32GB RAM a dvojicou SSD v raide. Workerom bol iMac 5K 2012 so 16GB RAM a fusion driveom. Celkovy pocet jobov v XCode som nastavil na 14 (8 corov na iMacu + 4 cory na Mac mini + 2 pre pripad, ze nieco bude visiet na sieti). Standardny cas buildu tohto projektu je cca 6+ hodin pre mac mini a asi 2 a pol hodiny pre iMac. Trvanie kompletneho rebuildu v distribuovanom konfigu este nemam zmerane, pretoze experimentujem so setupom pri ktorom dokazem obe masiny vytazit co najblizsie k 100%. Ak som skusal setup, pri ktorom mal localhost dovolene pustat tolko kompilacnych jobov, kolko mal jadier + musel preprocessovat zdrojaky pre workera, tak sa vytazenie workera pohybovalo okolo 50% a vytazenie klienta bolo pochopitelne na 100%. Ked som znizil pocet lokalnych jobov zo 4 na 2, stuplo vytazenie iMacu na 75+% a ak som znizil pocet lokalnych jobov na 1, obe masiny boli vytazene takmer na 100%. Na prvy pohlad by to mohlo vyzerat tak, ze som v reale dosiahol iba 1/8 zrychlenie, pretoze iMac bezi 8 jobov a Mac mini bezi jeden. V skutocnosti ale mac mini preprocessuje kazdy job (takze iMac uz nemusi, co setri diskove I/O) a ak sa zanedba overhead siete, tak worker za jednotku casu pri 100% vytazeni stihne skompilovat viac modulov, ako by stihol keby bezal build lokalne (pretoze nemusi preprocessovat includy ani nestoji na linkovani). Ako bonus je tam jeden modul, ktory sa kompiluje lokalne. Realne sa mi podarilo do buildovacieho procesu zapojit 12 jadier, co je o 50% viac ako na najvykonnejsej standalone masine, ktoru mam k dispozicii. Ak by som do clustera zapojil viac workerov (ono jeden klient a jeden worker ani velmi cluster nie je), tak by malo zmysel zakazat lokalne joby na klientovi uplne (vyhodit localhost zo suboru hosts uplne) a joby distribuovat iba na workerov. Ak by boli workermi napr. 3 kusy iMacov i7 s 8-jadrovymi procesormi, teda 24 jadier), celkovy vykon pri buildovani by bol aj tak vyssi ako trojnasobny oproti lokalnemu buildu na jednom takom iMacu (pretoze preprocessing by sa vykonaval na klientovi). Limit na pocet paralelnych jobov na klientovi uz nema zmysel navysovat vtedy, ked procesor na klientovi bezi konstantne na 100% a v clusteri este zostavaju nejake nevytazene masiny. To je znakom toho, ze preprocessing a linkovanie na klientovi zhltli vsetok procesorovy cas. Tu nie je mozne dat nejaku striktnu hodnotu a dokonca aj vytazenie clustera pocas buildovania jedneho projektu sa moze menit v zavislosti od toho ako dlho sa bude jedna kompilacna jednotka kompilovat. Ak sa zapnu extenzivne optimalizacie a zdrojak obsahuje vela volani sablon, moze malo vykonny klient vytazit daleko viac workerov, ak je zdrojak relativne primitivny. --- Dodatok --- Pre uplnost dodam este dve veci: 1) distcc ma aj pump mod pri ktorom aj preprocessing prebieha na workeroch v clusteri. Tento ale eliminuje vyhodu v tom, ze workery nemusia mat zdrojove kody projektu, SDK, kniznice ani konfiguraciu. Navyse neviem, ci ho je vobec mozne s XCode rozchodit. 2) nefunguje to 100%tne. Mozu sa najst nejake clang / Objective-C speciality, ktore distcc rozhodia a bud taketo moduly nebude kompilovat distribuovane, alebo ich neskompiluje vobec. Kedze ma to sralo, tak som este reverse engineeringom prisiel aj na to, ako je mozne subor .xcconfig programovo zaclenit do XCode projektu bez nutnosti drag & drop-u. Je to ale perverzne citanie, tak si to necham na niekedy inokedy, hlavne na neskoru nocnu hodinu po 22:00. Shitty life is like radiation. You can sustain it for long time if daily doses are small. |
| |||||||||||||||||||||||||