Taulukkotyöt
Monissa tapauksissa laskennallinen analyysityö sisältää joukon samankaltaisia, toisistaan riippumattomia osatehtäviä. Käyttäjällä voi olla useita aineistoja, jotka analysoidaan samalla tavalla, tai samaa simulointikoodia suoritetaan useilla eri parametreilla. Tällaisia tehtäviä kutsutaan usein embarrassingly parallel -töiksi tai yhdessä task farming -nimellä, koska ne voidaan periaatteessa jakaa niin monelle prosessorille kuin ajettavia tehtäviä on.
Taulukkotyöt voivat olla sopiva lähestymistapa, jos:
- Kunkin itsenäisen työn suoritusaika on riittävän pitkä, jotta SLURM-eräjärjestelmän
yleiskustannus on merkityksetön.
- Yksittäiset suoritusajat ovat pidempiä kuin noin 30 minuuttia.
- Itsenäisten töiden kokonaismäärä ei ole liian suuri.
- Käyttäjällä voi olla eräjärjestelmässä joko käynnissä tai jonossa enintään 400 työtä.
Muut vaihtoehdot
Kun suoritusajat ovat hyvin lyhyitä tai yksittäisten töiden määrä on erittäin suuri,
suuren läpimenon laskentaan on olemassa sopivampia vaihtoehtoja.
Suositeltu työkalu näihin käyttötapauksiin on HyperQueue.
Vaihtoehtoihin kuuluvat myös
Linuxin xargs-apuohjelma
(katso tämä eräskripti käyttöesimerkkiä varten)
ja GNU Parallel -komentorivityökalu.
Taulukkotyön määrittely
Slurmissa taulukkotyö määritellään valinnalla --array tai -a, esimerkiksi
ei käynnistä vain yhtä erätyötä vaan 100 erätyötä, joissa alityökohtaisen ympäristömuuttujan
$SLURM_ARRAY_TASK_ID arvo vaihtelee välillä 1–100. Tätä muuttujaa voidaan sitten
hyödyntää varsinaisissa työn käynnistyskomennoissa niin, että kukin osatehtävä käsitellään. Kaikki
alityöt käynnistetään eräjärjestelmään kerralla, ja ne suoritetaan käyttäen niin montaa
prosessoria kuin on saatavilla.
Työalueen määrittelyn lisäksi voit antaa myös luettelon työn indeksiarvoista, esimerkiksi
käynnistäisi kolme työtä, joiden $SLURM_ARRAY_TASK_ID-arvot ovat 4, 7 ja 22.
Voit myös sisällyttää askelkoon työalueen määrittelyyn. Taulukkotyön määritys
suorittaisi viisi työtä $SLURM_ARRAY_TASK_ID-arvoilla 1, 21, 41, 61 ja 81.
Joissakin tapauksissa voi olla järkevää rajoittaa samanaikaisesti käynnissä olevien prosessien määrää.
Tämä tehdään merkinnällä %max_number_of_jobs. Esimerkiksi tilanteessa, jossa sinulla on
100 työtä mutta lisenssi vain viidelle samanaikaiselle prosessille, voit varmistaa, että lisenssit
eivät lopu kesken, käyttämällä määritystä
Yksinkertainen esimerkki taulukkotyöstä
Ensimmäisessä taulukkotyöesimerkissä oletetaan, että meillä on 50 aineistoa (data_1.inp, data_2.inp
... data_50.inp), jotka haluamme analysoida ohjelmalla my_prog, jonka syntaksi on
Kukin osatehtävä vaatii alle kaksi tuntia laskenta-aikaa ja alle 4 Gt muistia. Voimme suorittaa kaikki 50 analyysitehtävää seuraavalla erätyöskriptillä:
#!/bin/bash -l
#SBATCH --job-name=array_job
#SBATCH --output=array_job_out_%A_%a.txt
#SBATCH --error=array_job_err_%A_%a.txt
#SBATCH --account=<project>
#SBATCH --partition=small
#SBATCH --time=02:00:00
#SBATCH --ntasks=1
#SBATCH --mem-per-cpu=4000
#SBATCH --array=1-50
# run the analysis command
my_prog data_${SLURM_ARRAY_TASK_ID}.inp data_${SLURM_ARRAY_TASK_ID}.out
Erätyöskriptissä rivi #SBATCH --array=1-50 määrittää, että 50 alityötä lähetetään.
Muut #SBATCH-rivit viittaavat yksittäisiin alitöihin. Tässä tapauksessa yksi alityö käyttää enintään yhtä
prosessoria (--ntasks=1), 4 Gt muistia (--mem-per-cpu=4000) ja voi kestää enintään kaksi tuntia
(--time=02:00:00). Kaikkien 50 tehtävän käsittelyyn tarvittavaa kokonaisseinäkelloaikaa ei kuitenkaan
rajoiteta.
Työn suorituskomennoissa skripti käyttää $SLURM_ARRAY_TASK_ID-muuttujaa
syöte- ja tulostetiedostojen määrittelyssä niin, että ensimmäinen alityö suorittaa komennon
toinen suorittaa komennon
ja niin edelleen.
Työ voidaan nyt käynnistää komennolla
Tyypillisesti kaikkia töitä ei suoriteta kerralla. Jonkin ajan kuluttua suuri määrä töitä voi kuitenkin
olla käynnissä samanaikaisesti. Kun erätyö on valmis, hakemisto data_dir sisältää 50
tulostetiedostoa.
Taulukkotyön lähettämisen jälkeen komento
paljastaa, että sinulla on yksi odottava työ ja mahdollisesti useita muita töitä käynnissä eräjärjestelmässä.
Kaikilla näillä töillä on jobid, joka sisältää kaksi osaa: taulukkotyön jobid-numeron ja alityön numeron.
Kunkin alityön tulosteen ohjaamista erilliseen tiedostoon suositellaan, koska tiedostojärjestelmä voi epäonnistua,
jos useat kymmenet prosessit yrittävät kirjoittaa samaan tiedostoon samaan aikaan. Jos tulostetiedostot
täytyy yhdistää yhdeksi tiedostoksi, se voidaan usein tehdä helposti taulukkotyön valmistuttua.
Esimerkiksi yllä olevassa tapauksessa voisimme kerätä tulokset yhteen tiedostoon komennolla
Vakiotulosteen ja virhetiedostojen tapauksessa, jotka on määritelty #SBATCH-riveillä, voit käyttää
määreitä %A ja %a antaaksesi yksilölliset nimet kunkin alityön tulostetiedostoille. Tiedostonimissä
%A korvataan taulukkotyön tunnuksella ja %a korvataan
$SLURM_ARRAY_TASK_ID:llä.
Tiedostonimiluettelon käyttäminen taulukkotyössä
Yllä olevassa esimerkissä pystyimme käyttämään $SLURM_ARRAY_TASK_ID:tä viittaamaan syötetiedostojen
järjestysnumeroihin. Jos tällainen lähestymistapa ei ole mahdollinen, voidaan käyttää ennen erätyön
lähettämistä luotua tiedosto- tai komentoluetteloa. Oletetaan, että meillä on yllä määritellyn kaltainen tehtävä,
mutta tiedostonimet eivät sisällä numeroita vaan ovat muodossa data_aa.inp,
data_ab.inp, data_ac.inp ja niin edelleen. Nyt meidän täytyy ensin tehdä luettelo analysoitavista
tiedostoista. Tässä tapauksessa voisimme kerätä tiedostonimet tiedostoon namelist komennolla
Komento
lukee tietyn rivin nimiluettelotiedostosta. Tässä tapauksessa varsinainen komentokomentoskripti voisi olla
#!/bin/bash -l
#SBATCH --job-name=array_job
#SBATCH --output=array_job_out_%A_%a.txt
#SBATCH --error=array_job_err_%A_%a.txt
#SBATCH --account=<project>
#SBATCH --partition=small
#SBATCH --time=02:00:00
#SBATCH --ntasks=1
#SBATCH --mem-per-cpu=4000
#SBATCH --array=1-50
# set the input file to process
name=$(sed -n ${SLURM_ARRAY_TASK_ID}p namelist)
# run the analysis
my_prog ${name} ${name}.out
Tämä esimerkki on muuten samanlainen kuin ensimmäinen, paitsi että se lukee analysoitavan tiedoston nimen
tiedostosta namelist. Tämä arvo tallennetaan muuttujaan ${name}, jota käytetään työn suorituskomennossa.
Koska luettava rivinumero määritellään $SLURM_ARRAY_TASK_ID:llä,
jokainen tiedostossa namelist lueteltu datatiedosto käsitellään eri alityönä. Huomaa, että koska
käytämme nyt myös ${name}-muuttujaa tulosteen määrittelyssä, tulostetiedoston nimi on muodossa
data_aa.inp.out, data_ab.inp.out, data_ac.inp.out ja niin edelleen.
Taulukkotöiden käyttäminen työnkuluissa komennolla sbatch_commandlist
sbatch-hq
Tehokkaampi vaihtoehto sbatch_commandlist-komennolle on CSC:n apuohjelma sbatch-hq,
joka on käytännössä HyperQueue:n ympärille tehty wrapperi. sbatch-hq
mahdollistaa samankaltaisten, toisistaan riippumattomien ei-MPI-rinnakkaistehtävien joukon lähettämisen
komentoluettelosta eli tiedostosta, jossa kukin rivi vastaa yksittäistä suoritettavaa osatehtävää.
Katso lisätietoja HyperQueue-sivulta.
Puhdissa voit käyttää komentoa sbatch_commandlist suorittaaksesi komentoluettelon
taulukkotyönä. Tämä komento ottaa syötteekseen tekstitiedoston. Komentoluettelo jaetaan useisiin
osiin, jotka suoritetaan taulukkoerätyön itsenäisinä osatehtävinä, ja jotka sbatch_commandlist
luo automaattisesti. Näin yksi taulukkotyön osatehtävä voi käsitellä useita
komentoluettelon komentoja.
Tämän komennon syntaksi on:
Valintoja -t ja -mem voidaan käyttää alitöiden aika- ja muistivarauksen muuttamiseen
(oletus 12 h, 8 Gt). Oletuksena laskutusprojekti asetetaan sen scratch-hakemiston nimen perusteella,
jossa tämä komento suoritetaan, mutta tarvittaessa se voidaan määrittää valinnalla
-project. Komentoluettelo jaetaan enintään 200 osatehtävään. Jos yksittäiset tehtävät ovat
hyvin lyhyitä, voit käyttää valintaa --max_jobs pienentääksesi jakoa niin, että kukin taulukkotyön
tehtävä kestäisi käsitellä vähintään noin puoli tuntia.
Taulukkotyön lähettämisen jälkeen sbatch_commandlist alkaa seurata työn etenemistä.
Jos käytät sbatch_commandlist-komentoa vuorovaikutteisesti kirjautumissolmuilla, et yleensä
halua pitää seurantaa käynnissä tuntikausia. Näissä tapauksissa voit vain sulkea seurantaprosessin
painamalla Ctrl-c. Varsinaista taulukkotyötä ei poisteta, vaan se pysyy aktiivisena
eräjärjestelmässä, ja voit hallita sitä tavallisilla Slurm-komennoilla.
Vuorovaikutteisen käytön lisäksi sbatch_commandlist-komentoa voidaan hyödyntää erätöissä ja
automaattisissa työnkuluissa, joissa vain tietyt työnkulun vaiheet voivat hyödyntää taulukkotöihin perustuvaa
rinnakkaislaskentaa. Esimerkkinä oletetaan, että meillä on gzip-pakattu tar-arkistotiedosto
my_data.tgz, joka sisältää hakemiston, jossa on suuri määrä tiedostoja. Luodaksemme uuden pakatun
arkiston, joka sisältää myös md5-tarkistussummatiedoston jokaiselle tiedostolle, meidän täytyisi:
- purkaa ja avata
my_data.tgz - suorittaa
md5sumjokaiselle tiedostolle ja lopuksi - pakata ja tiivistää
my_data-hakemisto uudelleen.
Työnkulun toinen vaihe voitaisiin suorittaa for-silmukalla, mutta voisimme myös käyttää
silmukkaa vain md5sum-komentojen luettelon luomiseen, joka voidaan käsitellä sbatch_commandlist-komennolla.
#!/bin/bash -l
#SBATCH --job-name=workfow
#SBATCH --output=workflow_out_%j.txt
#SBATCH --error=workflow_err_%j.txt
#SBATCH --account=<project>
#SBATCH --time=12:00:00
#SBATCH --mem=4000
#SBATCH --ntasks=1
#SBATCH --partition=small
#open the tgz file
tar zxf my_data.tgz
cd my_data
#generate a list of md5sum commands
for my_file in *
do
echo "md5sum $my_file > $my_file.md5" >> md5commands.txt
done
#execute the md5commands as an array job
sbatch_commandlist -commands md5commands.txt
#remove the command file and compress the directory
rm -f md5commands.txt
cd ..
tar zcf my_data_with_md5.tgz my_data
rm -rf my_data
Huomaa, että yllä oleva erätyöskripti ei ole taulukkotyö, vaan se käynnistää toisen erätyön, joka on taulukkotyö.