Kääntäjäympäristö Louhessa ja Murskassa
CSC:n tärkeimmät laskentapalvelimet Louhi ja Murska tarjoavat käyttäjilleen monipuolisen ja tehokkaan ohjelmointiympäristön usean kaupallisen ja ei-kaupallisen ohjelmistokääntäjän vetämänä. Tehokäyttäjä etsiikin itselleen ja ohjelmalleen näistä tehokkaimman vaihtoehdon sekä kiinnittää huomiota myös kääntäjäoptioiden käyttöön.
Yleistä
Suurteholaskijan yksi tärkeimmistä työkaluista on optimoiva kääntäjä. CSC:n laskentapalvelimet tarjoavat mahdollisuuden käyttää Portland Groupin (PGI), Pathscalen ja Intelin toimittamia kaupallisia Fortran- ja C/C++-kääntäjiä sekä vapaan lähdekoodin GNU-kääntäjäympäristöä. Ennen intensiivisiä tuotantoajoja on syytä käyttää aikaa parhaan – tehokkaimman oikeita tuloksia tuottavan - kääntäjän ja sen optioiden löytämiseen. Toisinaan myös kääntäjäversiolla on vaikutusta – toisella versionumerolla jokin tietty optimointi saattaa toimia mutta toisessa rikkoa koodin. Pääsääntö on kuitenkin, että tuoreempi kääntäjäversio on todennäköisesti myös parempi.
Pieni vaiva maksaa itsensä takaisin projektin kuluessa sekä mahdollistaa efektiivisemmän CSC:n resurssien hyödyntämisen. Esimerkiksi kohtalaisen hyvillä kääntäjävalitsimilla käännetyn ja ilman valitsimia käännetyn koodin välillä voi helposti olla parinkin kymmenen prosentin ero suorituskyvyssä – toisinaan rutkasti suurempikin. Tämä vastaisi jo yhdessä vuorokauden mittaisessa 1024 ytimen Louhi-ajossa liki viittä tuhatta turhaan haaskattua CPU-tuntia, yli puolta CPU-vuotta siis!
Oletuskääntäjä molemmissa koneissa on PGI. Ohjelmointiympäristö vaihdetaan toiseen kääntäjään komennolla module swap,esimerkiksi Pathscale-kääntäjään kuten
module swap PrgEnv-pgi PrgEnv-pathscale
Perusoptimointi
Peruslähtökohta kääntäjäoptimointiin ovat kaikissa CSC:n ohjelmointiympäristön kääntäjissä –On-vivut, missä n saa arvon nollan ja kolmen välillä, nollan tarkoittaessa kaikkien optimointien poisjättämistä ja kolmen suurinta joukkoa perustemppuja. Nollatasoa kannattaa käyttää vain ohjelmointivirheitä etsittäessä. Taso 2 on yleensä turvallinen taso kaikilla kääntäjillä, ja mahdollista lisäsuorituskykyä voidaan koettaa hakea sitten O3-tasolta. Intelin kääntäjä on parhaimmillaan yhtiön omissa prosessoreissa, mutta tuottaa kelpo koodia myös AMD:n valmistamissa prosessoreissa, joilla CSC:n nykyiset supertietokoneet pyörivät. Intelin kääntäjää CSC:n ympäristössä käytettäessä tulisi kuitenkin välttää aggressiivista optimointia, sillä se vaikuttaa hidastavan ohjelmistoja. Optimointitasona –O2 on maksimi, samoin prosessorikohtaisia optimointeja ei ole tarjolla AMD:n ytimille.
Muista kääntäjistä PGI tekee prosessoririippuvaisia valintoja optiolla –tp ja Pathscale ja GNU optiolla –march. Valitsimelle syötetään myös prosessorin nimi, joka on Louhessa barcelona-64 (PGI) tai barcelona (Pathscale ja GNU) ja Murskassa amd64 (PGI) tai opteron (Pathscale ja GNU). Nämä optiot ovat sisällytetty osaan CSC:n kääntäjäwrappereista.
Kääntäjissä on myös erilaisia makroja, joilla suoritetaan yhdellä komennolla useimmiten hyvää suorituskykyä tarjoavat optimointiratkaisut. PGI:ssa tämä on –fastsse ja Pathscalessa –Ofast. Intel-kääntäjän –fast-makro ei toimi oikein AMD:n prosessoreissa. Kunkin kääntäjän dokumentaatio ja man-sivustot kertovat tarkemmin näiden makrojen sisällöstä. Näitä kannattaa käyttää lähtökohtana kääntäjäoptimoinnissa, ja kokeilla makroon tehtyjen karsimisten, lisäysten sekä parametrimuutosten vaikutusta ohjelman suorituskykyyn ja tuloksiin. Kääntäjät noudattavat käytäntöä, jossa valitsinlistauksessa oikealla oleva korvaa aikaisemman valitsimen, jos ne ovat keskenään ristiriidassa. Esimerkiksi PGI:n –fastsse sisältää valitsimen –O2, mutta kirjoitettaessa –fastsse –O3 kääntäjä optimoikin tasolla 3 tason 2 sijaan.
Ohjelman tarvitsemien kirjastojen linkitys ns. staattisesti on ainoa vaihtoehto Louhessa, mutta Murska tukee myös dynaamista linkitystä. Dynaamisesti linkitetty binääri on selvästi pienempi, mutta usein staattisesti linkitetty ohjelma on suorituskyvyltään parempi, ja sitä kannattaa käyttää jos binääri pysyy järkevän suuruisena. Tämä tapahtuu optiolla –Bstatic PGI:lla sekä valitsimella –static muilla kääntäjissä.
Liukuluvut
Ohjelmakoodin vektorointi, eli kahden SSE-rekisterin hyödyntäminen samassa kellosyklissä liukuluvuilla laskettaessa, on tärkeä tekijä suorituskyvyn kannalta. Louhen uudemmat Barcelona-prosessorit osaavat hyödyntää näitä konekielen käskyjä myös tuplatarkkuuden luvulla, siinä missä Murskan prosessorit tekevät sen vain yksinkertaisen tarkkuuden muuttujissa. Yleensä vektorointi kuitenkin kannattaa, molemmissa koneissa. Kääntäjä tuottaa SSE-käskykantaa hyödyntävää konekielilistausta sopivissa silmukoissa. Kääntäjät eivät vektoroi pyytämättä, PGI:ssa tämä tapahtuu käännösoptiolla –Mvect=sse, Pathscalessa –LNO:simd=n (n=1 tai 2, joista ensimmäinen on varovaisempi, jälkimmäinen aggressiivisempi vektoroinnissa), Intelin kääntäjissä vektorointi tulee mukaan optimointitasolla –O2 (-O3:ssa aggressiivisemmin). PGI:n –fastsse-makro sisältää vektoroinnin. GNU-kääntäjä ei osaa vektoroida yhtä hyvin erilaisia rakenteita kuin muut käsitellyt kääntäjät, mutta valitsinta –ftree-vectorize kannattaa silti koettaa. Louhessa Barcelona-prosessorin tukemaa SSE4a-käskykantaa voi koettaa hyödyntää Pathscalen valitsimella –msse4a.
Liukuluvuilla laskettaessa jokainen desimaali on edellistä raskaampi laskea. Usein kannattaa kokeilla tinkimistä hieman tarkkuudesta – tällä ei ole yleensä merkittävää vaikutusta tulosten oikeellisuuteen, mutta tuottaa suorituskykyetua. Rennompaa liukulukutarkkuutta saadaan hyödynnettyä PGI-kääntäjällä valitsemella –Mfprelaxed, Pathscalella kuten –OPT:fast-math=ON, Intelin kääntäjällä –no-prec-sqrt ja –no-prec-div ja GNU-kääntäjällä –ffast-math.
Interproseduaalinen ja profiiliperustainen optimointi
Interproseduaalisella optimoinnilla tarkoitetaan kääntäjän analyysia datan virtaamisesta eri rutiinien välillä ja funktiokutsujen rakenteesta ja sen pohjalta tehtävää optimointia. PGI-kääntäjän interproseduaalianalyysilippu on –Mipa, jolle annetaan =-merkin välityksellä lisämääreitä. Esimerkiksi valitsin –Mipa=inline siirtää pienet funktiot osaksi kutsuvaa rutiinia, mikä mahdollistaa jatko-optimoinnin. Lisämääre fast laittaa kääntäjän kokeilemaan joukkoa tuntemiaan tempuista. Yhdistelmä –Mipa=fast,inline antaa melko varmasti suorituskykyhyötyä, mutta johtaa toisaalta pitkähköön käännösaikaan. Pathscalessa valitsin –ipa tuottaa standardijoukon optimointeja, joita voi hienosäätää –IPA:-konstruktioilla. Intelin kääntäjän interproseduaalikäsittely ei tunnu toimivan oikein AMD-alustalla, vaan ennemminkin hidastavan ohjelmaa, eli sen lippua –ipo ei kannattane käyttää lainkaan. GNU-kääntäjä suorittaa funktioiden sisällyttämisen –finline-functions-valitsimella ja pointterien analysoinnin rutiinien välillä valitsimella –fipa-pta. GNU-kääntäjien versiosta 4.3 alkaen myös muita interproseduaalisen analyysin välineitä on käytössä.
Kääntäjät pyrkivät arvaamaan, mitä ohjelma tekee ajon aikana, ja perustaa optimointivalintansa tähän logiikkaan. Se on kuitenkin huomattavasti viisaampi saadessaan informaatiota varsinaista ajoaikaista tietoa mm. loogisten rakenteiden käyttäytymisestä ja muuttuvanpituisten silmukoiden tyypillisistä pituuksista. Tätä kutsutaan profiiliperustaiseksi optimoinniksi, jonka perusteella kääntäjä osaa tehdä korjauksia ensimmäiseen optimointiyritykseensä. Koodi käännetään siis ensin profiiliperustaisen optimoinnin aloittavan valitsimen kanssa, ajetaan ja käännetään uudelleen sitä hyödyntävän valitsimen kanssa. PGI:ssa nämä ovat –Mpfi ja –Mpfo (vastaavasti), Pathscalessa –fb-create ja –fb-opt, Intel-kääntäjässä –prof-gen ja –prof-use ja GNU-kääntäjässä –fprofile-generate ja –fprofile-use.
Tietoa kannen alta
Kääntäjä antaa informaatiota suorittamistaan ja suorittamatta jättämistään optimoinneista. Tämä tieto, etenkin jälkimmäinen, on usein hyödyllistä muokattaessa lähdekoodia ohjelman suorituskyvyn parantamiseksi. PGI:ssa nämä tapahtuvat valitsimella –Minfo=all sekä –Mneginfo=all. Pathscalessa tärkeimmät kääntäjäoptimointiin liittyvät ilmoitukset saadaan näkyviin valitsimilla –LNO:simd_verbose=ON sekä –LNO:prefetch_verbose=ON. Intel-kääntäjä kertoo tekemistään optimoinneista erikseen pyytämättä; kerrotun tiedon määrää voi lisätä valitsimilla -vec-report=n sekä -opt-report=m, missä arvot n=5 ja n=3 tuottavat maksimimäärän tietoa, oletusten ollessa n=1 ja m=2. GNU-kääntäjällä koodin oikeellisuuden varmistamiseksi optimoimatta jätettävät silmukat saadaan tietoon valitsimella -Wunsafe-loop-optimizations ja suoritetuista vektoroinneista saa tietoa asettamalla -ftree-vectorizer-verbose=7.
Jaetun muistin rinnakkaistaminen
Vaikka Louhi on tarkoitettu massiivisisesti rinnakkaisten MPI-ohjelmien alustaksi, joskus saattaa olla hyödyllistä rinnakkaistaa ohjelma kahdella tasolla: solmujen sisällä rinnakkaistus hoidetaan jaetun muistin tasolla ja vasta solmujen välillä kommunikoidaan viestinvälityksellä. Rinnakkaistöiden lisäksi myös perättäistöiden alustaksi tarkoitetussa Murskassa jaetun muistin strategialla rinnakkaistettuja ohjelmistoja voidaan hyödyntää sellaisenaan. PGI-kääntäjän saa yrittämään automaattista jaetun muistin rinnakkaistusta vivulla –Mconcur=nonuma, mutta valitettavasti useinmiten tuloksena on tehokkuudeltaan varsin vaatimaton rinnakkaistus. Jaetun muistin rinnakkaistus onkin syytä toistaiseksi tehdä käsin OpenMP-kirjastolla tai Louhen SHMEM-kirjastolla. OpenMP-kirjasto otetaan käyttöön kääntäjävalitsemella –mp. Siihen lisätyt määreet –mp=nonuma,align voivat parantaa OpenMP-ohjelman suorituskykyä. Muilla kääntäjillä OpenMP-kirjastokutsut huomioidaan lisäämällä valitsin –openmp (Intel) tai –fopenmp (Pathscale ja GNU).
Paras säikeiden lukumäärä on liki poikkeuksetta sama kuin yhden solmun laskentaydinten lukumäärä, siis neljä Louhessa ja kaksi Murskassa. Säikeiden lukumäärä kerrotaan ohjelmalle ympäristömuuttujan OMP_NUM_THREADS arvon kautta. Ympäristömuuttujalla MP_BIND voidaan säikeet sitoa sijaitsemaan aina samassa ytimessä. Kääntäjän rinnakkaistamia ohjelmia ajetaan eräajojärjestelmässä kuin OpenMP-ohjelmia. Koneiden käyttöoppaissa on lisätietoja aiheesta.
Lopuksi
Modernit kääntäjät ovat erittäin monimutkaisia ja monipuolisia ohjelmistoja. Niiden tarjoamiin lukuisiin käännösoptioihin kannattaa tutustua niiden dokumentaatiossa, jota pääsee tarkastelemaan esimerkiksi komennoilla man pgf90 (tai pgcc) PGI-kääntäjien, man eko Pathscalen, ifort –help (tai
icc –help) Intelin ja man gcc GNU-kääntäjien tapauksessa.
Jokaisen mahdollisen lipun päälle- tai poiskytkemistä tai yhdistämistä ei kannata ryhtyä kokeilemaan, vaan tässä artikkelissa esitetyillä perusresepteillä pääsee pitkälle. Aina pitäisi kuitenkin varmistaa, että ohjelma laskee oikein myös kääntäjäoptimointien lisäämisen jälkeen.
Pekka Manninen
Pekka.Manninen at csc.fi