-
GNU xargs ja rinnakkaiset työnkulut monille pienille, itsenäisille ajoille
GNU xargs ja rinnakkaiset työnkulut monille pienille, itsenäisille ajoille
Yleiskatsaus
Tämä opas esittelee yhden lähestymistavan suuren läpimenon laskentaan, jossa suuri määrä samankaltaisia, itsenäisiä tehtäviä pakataan pieneen määrään Slurm- töitä sen sijaan, että ne lähetettäisiin yksittäisinä töinä.
Sekä xargs että
GNU Parallel ovat komentorivikäyttöliittymätyökaluja
suuren tehtävämäärän rinnakkaiseen suorittamiseen, ja ne toimivat tässä
tarkoituksessa melko samalla tavalla. Tässä oppaassa käytämme xargs-työkalua,
koska se on yksinkertainen, kevyt ja yleensä käyttöjärjestelmän perusasennukseen
kuuluva, mutta sama työnkulku voidaan toteuttaa myös GNU Parallelin parallel-
komennolla. Tässä käytämme työkalua yhden Slurm-varauksen sisällä, jotta kaikki
varatut ytimet pysyvät käytössä: syötetiedostojen nimet välitetään xargs-
työkalulle, joka jatkaa tehtävien suorittamista, kunnes ne kaikki ovat
valmiita, käynnistäen uuden tehtävän heti kun yksi ydin vapautuu.
xargs sopii tähän tarkoitukseen hyvin, koska se ei vaadi tietokantaa tai
pysyvää hallintaprosessia, se käyttää ajastimen resursseja tehokkaasti ja
skaalautuu helposti suureen määrään tehtäviä ja solmuja. Toisaalta se suorittaa
vain sarjallisia alitehtäviä eikä tue tehtävien välisiä riippuvuuksia tai
virheistä palautumista. Se myös edellyttää, että järjestät syöte- ja
tulostiedostot huolellisesti, ja skaalauksen yhteydessä sinun on huomioitava
järjestelmän I/O-suorituskyky. Bash-skriptauksen perusteiden tuntemus on
suositeltavaa.
Jos tehtävilläsi on riippuvuuksia, tarvitset virheistä palautumista tai haluat tutustua työkaluihin, katso sivu suuren läpimenon laskenta ja työnkulut.
Esimerkki: 80000 itsenäisen yhden ytimen tehtävän suorittaminen
Yleisesti työnkulun suunnitteluun tarvitaan kolme syötettä:
- Kuinka monta ajoa on yhteensä?
- Kuinka kauan yksi ajo kestää?
- Kuinka monta tiedostoa luodaan?
Kaksi ensimmäistä määrittävät, miten ajot ryhmitellään eräajoiksi, ja viimeinen määrittää hakemistorakenteen.
Tarkastellaan esimerkkiä, jossa meillä on 80000 itsenäistä, ei-rinnakkaista yhden ytimen ajoa, joista kukin kestää 0–30 minuuttia, keskimäärin 15 minuuttia. Pahimmassa tapauksessa kaikki eräajon ajot kestävät enimmäisajan eli 30 minuuttia. Voimme nähdä, että yksi 40 tunnin eräajo riittää vähintään 80 ajolle yhdellä ytimellä ja 3200 ajolle kaikilla 40 ytimellä täydellä laskentasolmulla. Näin ollen kaikkien 80000 ajon pitäisi mahtua 25:een 40 tunnin eräajoon, joista kukin varaa yhden kokonaisen laskentasolmun.
Oletetaan, että sovelluksemme käyttää levyä erittäin paljon, ja yhden säilytettävän syötetiedoston ja yhden 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 toinen tarina.
Katsotaanpa 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
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-*' | \
xargs -n 1 -P $SLURM_CPUS_PER_TASK bash wrapper.sh {}
Eräajo varaa kokonaisen solmun 40 tunniksi. Solmussa käynnistyy yksi tehtävä,
jolla on pääsy kaikkiin solmun 40 CPU-ytimeen. Koska varaamme kaikki ytimet,
voimme samalla varata kaiken muistin ja kaiken paikallisen levyn, tässä ei
tarvitse kitsastella. Viimeinen rivi, #SBATCH --array=0,24, kertoo
eräajojärjestelmälle, että tästä työstä suoritetaan 25 kopiota, joista kukin
yksilöidään ympäristömuuttujassa SLURM_ARRAY_TASK_ID olevalla numerolla.
Jonotustilanteesta riippuen moni näistä töistä voi olla käynnissä rinnakkain.
xargs-komento kuuluu yleensä käyttöjärjestelmän perusasennukseen. HPC-järjestelmissä
vastaavan GNU Parallelin parallel-komennon käyttö voi usein edellyttää moduulin
lataamista. Käytämme xargs-komentoa (tai GNU Parallelia)
solmun sisällä kaikkien 3200 ajon "ajastamiseen" työssä niin, että
kaikki 40 ydintä ovat koko ajan 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 xargs-komennolla (tai GNU Parallelin parallel-komennolla).
Valinnalla -P $SLURM_CPUS_PER_TASK kerromme xargs-työkalulle, että sen tulee
pitää 40 komentoa (sovellusta) käynnissä rinnakkain. Koska meidän täytyy kopioida
tiedostoja paikalliselle SSD-levylle ja sieltä pois jokaisessa ajossa, käärimme sovelluksemme
pieneen komentotulkkiskriptiin wrapper.sh, joka ottaa syötetiedoston nimen
argumenttina. Syötetiedostojen nimet välitetään xargs-työkalulle putken kautta,
ja xargs jatkaa komennon bash wrapper.sh <syötetiedosto> suorittamista niin
kauan kuin putkessa on argumentteja.
Kun wrapper-skripti erotetaan eräajon työskriptistä, kumpaakin voidaan kehittää ja testata erikseen. Yleisesti kannattaa käyttää pieniä testiaineistoja työnkulkua kehitettäessä eikä odottaa, että kaikki onnistuu täydellisesti ensimmäisellä yrittämällä. Voit tutkia ja testata esimerkkitapauksen pientä versiota seuraavasti:
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 suorittaminen suuremman varauksen sisällä voi johtaa käyttämättömiin resursseihin. Varmista, että tällaisessa työssä on paljon nopeasti suoritettavia töitä, 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.