-
GNU Parallel -työvuo monille pienille, riippumattomille ajoille
GNU Parallel -työvuo monille pienille, riippumattomille ajoille
Tavoitteena on työvuo, joka on
- yksinkertainen ymmärtää,
- sopii hyvin eräjono-järjestelmään, ja
- ei kuormita rinnakkaista tiedostojärjestelmää.
Työvuo-työkaluja on runsaasti. Riippumatta siitä, minkä työkalun valitsee, se ei todennäköisesti sellaisenaan sovi juuri kyseiseen työnkulkuun ja taustalla olevaan laskenta-alustaan. Useimmissa tapauksissa tarvitaan jonkin verran ohjelmointia. Aiheeseen läheisesti liittyvä keskustelu löytyy Taulukkotyöt -luvusta osoitteessa https://docs.csc.fi.
GNU Parallelin vahvuudet
- Ei vaadi tietokantaa tai pysyvää hallintaprosessia
- Skaalautuu helposti suureen määrään tehtäviä/solmuja
- Ajastimen resurssien tehokas käyttö
GNU Parallelin haitat
- Käyttäjän on organisoitava syöte- ja tulostiedostot huolellisesti
- Skaalaaminen vaatii järjestelmän I/O-suorituskyvyn huomioimista
- Bash-skriptauksen perusteiden tuntemus on suositeltavaa
- Vain sarjallisia alitehtäviä
- Ei tukea riippuvuuksille tai virheistä palautumiselle
Yhteenveto järjestelmän rajoista
Kunkin käyttäjän kuukaudessa lähettämien töiden enimmäismäärä tulisi pitää alle tuhannessa. Liian suuri määrä eräajoja tuottaa ylimääräistä lokidataa ja hidastaa työnajastinta. Taulukkotyöt ovat käytännössä vain lyhennysmerkintä, joten yksi 100 jäsenen taulukkotyö lasketaan eräjono-järjestelmän näkökulmasta samaksi kuin 100 yksittäistä työtä.
Työn enimmäiskestoa rajoittavat jonon parametrit. Vähimmäiskestoa ei ole rajoitettu, mutta jos työ on liian lyhyt, se aiheuttaa vain suhteettoman suuren ajastusylikuorman eräjärjestelmään.
Tip
Hyvä tavoite on kirjoittaa eräajot niin, että ne valmistuvat jossain kahden tunnin ja kahden päivän välillä.
Rinnakkaiset tiedostojärjestelmät toimivat huonosti, kun yksi asiakas (sovellusohjelma) yrittää tehdä liian paljon tiedosto-operaatioita. Tällaisia tapauksia voivat olla esimerkiksi Conda-paketinhallinnalla suoraan jaettuun tiedostojärjestelmään asennetut sovellukset. Yksi miniconda-ympäristö sisältää helposti yli 20 000 tiedostoa, ja Anaconda-jakelu on vielä paljon pahempi. Monet näistä tiedostoista täytyy avata aina, kun Conda-sovellus käynnistetään. Kun ajetaan paljon suhteellisen lyhyitä töitä, vältä Condalla asennettujen sovellusten käyttöä. Jos sovelluksesi kuitenkin vaatii monimutkaisen ympäristön, käytä Singularity-kontteihin pakattuja sovelluksia, jotka ovat tiedostojärjestelmän näkökulmasta yksittäisiä tiedostoja. Jos haluat kontittaa Conda-ympäristön helposti, katso Tykky-konttikääretyökalu
"Myös "liikaa tiedostoja" -ongelmat ovat yleisiä työvuoissa, jotka koostuvat
tuhansista pienistä ajoista. Yleisohjeena pidä tiedostojen määrä yhdessä
hakemistossa selvästi alle tuhannen ja järjestä data useisiin
hakemistoihin. Käytä myös komentoa csc-workspaces seurataksesi, että projektiesi
tiedostojen kokonaismäärä pysyy selvästi rajojen alapuolella. Jos suurin osa tiedostoista on
väliaikaisia tai niitä on yksinkertaisesti liikaa, nopeiden paikallisten SSD-levyjen käyttö
I/O-solmuissa
voi ratkaista ongelman. Voit pakata pieniä tiedostoja suuremmaksi arkistotiedostoksi
komennolla tar. Tärkeintä on, että jos tulostiedostoja syntyy, joita et tarvitse,
selvitä, miten niiden kirjoittaminen voidaan estää jo alun perin.
Ota yhteyttä osoitteeseen servicedesk@csc.fi, jos työvuosi tarvitsee apua yllä annettuihin rajoihin sovittamisessa.
Esimerkkitapaus: 80000 riippumatonta ajoa
Yleisesti ottaen työvuon suunnitteluun tarvitaan kolme syötettä:
- Kuinka monta ajoa on yhteensä?
- Kuinka kauan yksi ajo kestää?
- Kuinka monta tiedostoa syntyy?
Kaksi ensimmäistä määräävät, miten ajot ryhmitellään eräajoiksi, ja viimeinen määrittää hakemistohierarkian.
Tarkastellaan esimerkkiä, jossa meillä on 80000 riippumatonta, ei-rinnakkaista yhden ytimen ajoa, joista kukin kestää 0:sta 30 minuuttiin, keskimäärin 15 minuuttia. Pahimmassa tapauksessa kaikki eräajon ajot kestävät enimmäisajan eli 30 minuuttia. Näemme, että yksi 40 tunnin eräajo riittää vähintään 80 ajolle yhdellä ytimellä ja 3200 ajolle kaikilla 40 ytimellä yhdessä täydellisessä laskentasolmussa. Näin ollen kaikkien 80000 ajon pitäisi mahtua 25:een 40 tunnin eräajoon, joista kukin varaa yhden kokonaisen laskentasolmun.
Oletetaan, että sovelluksemme on todellinen levytilasyöppö, ja yhden säilytettävän syötetiedoston ja yhden säilytettävän tulostiedoston lisäksi se luo myös 100 väliaikaistiedostoa nykyiseen hakemistoon. Yhdessä hakemistossa voi olla enintään noin 400 syöte- ja tulostiedostoa, ja väliaikaistiedostoille voidaan käyttää I/O-solmujen nopeaa paikallista levyä. Näin 80000 ajolle saadaan 200 hakemistoa, joissa kussakin on 400 ajoa.
Lisähuomioita tarvitaan, jos yksittäiset ajot ovat rinnakkaisia tai niiden välillä on riippuvuuksia, mutta se on jo toinen tarina.
Katsotaan esimerkkitapauksemme työskriptiä:
#!/bin/bash
#SBATCH --partition=small
#SBATCH --account=<project>
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=40
#SBATCH --time=40:00:00
#SBATCH --mem=160G
#SBATCH --gres=nvme:3600
#SBATCH --array=0-24
module load parallel
cd /scratch/${SLURM_JOB_ACCOUNT}/many
(( from_dir_index = SLURM_ARRAY_TASK_ID * 8 + 1 ))
(( to_dir_index = SLURM_ARRAY_TASK_ID * 8 + 8 ))
job_dirs=$(printf "%dir-%03d " $(seq $from_dir_index $to_dir_index))
find $job_dirs -name 'input-*' | \
parallel -j $SLURM_CPUS_PER_TASK bash wrapper.sh {}
Eräajo varaa kokonaisen solmun 40 tunniksi. Solmussa käynnistyy yksi tehtävä,
jolla on käytössään kaikki solmun 40 CPU-ydintä. Koska varaamme kaikki
ytimet, voimme samalla varata kaiken muistin ja kaiken paikallisen levyn, ei
ole tarvetta kitsastella tässä. Viimeinen rivi, #SBATCH --array=0,24, kertoo eräjärjestelmälle, että se suorittaa tästä työstä 25 kopiota, joista kukin tunnistetaan yksilöllisellä numerolla ympäristömuuttujassa SLURM_ARRAY_TASK_ID. Jonotilanteesta riippuen
monet näistä töistä voivat olla käynnissä rinnakkain.
Seuraavaksi lataamme moduulin, joka tarjoaa GNU parallel. Käytämme tätä työkalua solmun sisällä "ajastamaan" kaikki työn 3200 ajoa niin, että koko ajan kaikki 40 ydintä ovat käytössä mutta eivät ylikuormitettuina.
Seuraavat rivit laskevat, mitkä hakemistot kuuluvat nykyiseen taulukkotyöhön käyttäen
SLURM_ARRAY_TASK_ID-ympäristömuuttujaa.
Skriptin pää-"silmukka" on toteutettu GNU parallel -komennolla
parallel. Valinnalla -j $SLURM_CPUS_PER_TASK kerromme GNU parallelille, että sen tulee
pitää käynnissä 40 komentoa (sovellusta) rinnakkain. Koska meidän täytyy kopioida
tiedostoja paikalliselle SSD:lle ja sieltä pois jokaisessa ajossa, käärimme sovelluksemme
pieneen komentotulkkiskriptiin wrapper.sh, joka ottaa syötetiedoston nimen
argumenttina. Syötetiedostojen nimet syötetään GNU parallelille putken kautta,
ja GNU parallel jatkaa komennon bash wrapper.sh <syötetiedosto> suorittamista niin kauan
kuin putkessa on argumentteja.
Käärinskriptin erottaminen eräajon skriptistä mahdollistaa sen, että molempia voidaan kehittää ja testata erikseen. Yleisesti kannattaa käyttää pieniä testiaineistoja työvuota kehitettäessä, eikä kannata odottaa saavansa sitä täydelliseksi ensimmäisellä yrittämällä. Voit tutkia ja testata pientä versiota esimerkkitapauksesta komennolla
export SBATCH_ACCOUNT=<your project>
wget -c https://a3s.fi/docs-files/support/tutorials/many.tar.gz -O - | tar xz
cd many
bash create_inputs.sh
tree /scratch/${SBATCH_ACCOUNT}/many
sbatch job.sh
Note
Useiden erillisten töiden ajaminen suuremman varauksen sisällä voi johtaa käyttämättömiin resursseihin. Varmista, että tällaisessa työssä on paljon nopeasti valmistuvia töitä ajettavana, jotta viimeisenä käynnissä oleva työ ei pidä koko varausta pitkään voimassa. Alityön keston tulisi siis olla paljon lyhyempi kuin varauksen kesto, ja alitöiden määrän paljon suurempi kuin yhdessä tehtävässä pyydettyjen ytimien määrä.
Voit käyttää seff -työkalua selvittääksesi, kuinka kauan aiemmat työt ovat kestäneet.