Hyppää sisältöön

Welcome to our weekly research support coffee hour on Zoom! Click here for more information.

Warning!

Puhti scratch disk is becoming very full (80+ % ) resulting in performance degradation. Everybody is advised to only keep actively processed data on scratch, all other data should be deleted, transferred to host institute or stored in Lumi-O. No new quota will be granted. Click here for a tool for examining your disk usage.

R:n rinnakkaisten eräajojen esimerkkejä

r-env-moduulia voidaan käyttää rinnakkaislaskentaan useilla tavoilla. Näihin kuuluvat moniydin- ja taulukkotyöt sekä MPI:hin (Message Passing Interface) perustuvat työt, joissa käytetään useita solmuja.

Tällä sivulla annetaan esimerkkejä siitä, miten erilaisia rinnakkaisia R-eräajoja suoritetaan. Aloittaaksesi rinnakkaisen R:n käytön ja saadaksesi lisävinkkejä, katso johdanto rinnakkaisiin R-töihin.

Voit myös tutustua asiaankuuluviin R-pakettien käyttöohjeisiin ja CSC:n Geocomputing-esimerkkeihin, joissa on lisää esimerkkejä rinnakkaislaskennasta raster-paketin avulla.

Huomioita useiden ytimien varaamisesta

Oletuksena R käyttää yhtä ydintä. Useiden ytimien varaaminen sopii tilanteisiin, joissa käytät R-pakettia, joka on rakennettu käyttämään useita ytimiä (piilorinnakkaisuus), tai R-skriptisi on kirjoitettu hyödyntämään useita ytimiä. Jos et ole varma, voiko R-koodisi käyttää useita ytimiä, voit

  • tutustua R-paketin dokumentaatioon
  • käyttää seff-komentoa CPU-käytön tehokkuuden tarkistamiseen
  • tehdä testiajoja eri ydinmäärillä ja vertailla suoritusaikoja
  • tarkistaa prosessien määrän koodin ajon aikana työkaluilla kuten htop
  • ottaa yhteyttä CSC:n Service Deskiin saadaksesi neuvoja

Pelkkä ytimien määrän lisääminen ei välttämättä takaa nopeampaa laskentaa. Mutta jos analyysisi voidaan suorittaa rinnakkain useilla ytimillä, supertietokone voi todella nopeuttaa sitä.

Taulukkotyöt

Taulukkotöitä voidaan käyttää embarrassingly parallel -tehtävien käsittelyyn ja useiden samanaikaisesti suoritettavien Slurm-töiden lähettämiseen. Alla oleva esimerkkiskripti lähettäisi työn, joka sisältää kymmenen toisistaan riippumatonta osatehtävää small-osiolla siten, että kukin vaatii alle 45 minuuttia laskenta-aikaa ja alle 2 Gt muistia.

#!/bin/bash -l
#SBATCH --job-name=r_array
#SBATCH --account=<project>
#SBATCH --output=output_%A_%a.txt
#SBATCH --error=errors_%A_%a.txt
#SBATCH --partition=small
#SBATCH --time=00:45:00
#SBATCH --array=1-10
#SBATCH --ntasks=1
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=2000

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec Rscript --no-save myscript.R $SLURM_ARRAY_TASK_ID
#!/bin/bash -l
#SBATCH --job-name=r_array
#SBATCH --account=<project>
#SBATCH --output=output_%A_%a.txt
#SBATCH --error=errors_%A_%a.txt
#SBATCH --partition=small
#SBATCH --time=00:45:00
#SBATCH --array=1-10
#SBATCH --ntasks=1
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1 # Each core gives 1.875 GB of memory

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec Rscript --no-save myscript.R $SLURM_ARRAY_TASK_ID

Jos haluaisimme käyttää taulukon numeroa $SLURM_ARRAY_TASK_ID R-skriptissämme, voisimme käyttää commandArgs- tai Sys.getenv-funktiota.

arrays <- commandArgs(trailingOnly = TRUE)
# or
arrays <- Sys.getenv("SLURM_ARRAY_TASK_ID")

Taulukon numeroa $SLURM_ARRAY_TASK_ID voitaisiin käyttää esimerkiksi määrittämään, mikä datajoukko tai parametrijoukko analysoidaan kussakin taulukossa.

Taulukkotyöt soveltuvat parhaiten tapauksiin, joissa kukin osatehtävä kestää pidempään kuin noin 30 minuuttia ja osatehtävien määrä on enintään 400. Suurempia taulukkoasetelmia varten, joissa osatehtävät ovat lyhyempiä, katso alla oleva esimerkki laajamittaisista taulukkotöistä GNU parallelin avulla

Moniydintyöt

Seuraava eräajotiedosto näyttää, miten lähetetään työ, joka käyttää useita ytimiä yhdellä solmulla. Työ varaa yhden tehtävän (--ntasks=1), kahdeksan ydintä (--cpus-per-task=8) ja yhteensä 8 Gt muistia (--mem-per-cpu=1000). Ajoaika on rajoitettu viiteen minuuttiin.

#!/bin/bash -l
#SBATCH --job-name=r_multicore
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=small
#SBATCH --time=00:05:00
#SBATCH --ntasks=1
#SBATCH --nodes=1
#SBATCH --cpus-per-task=8
#SBATCH --mem-per-cpu=1000

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec Rscript --no-save myscript.R
#!/bin/bash -l
#SBATCH --job-name=r_multicore
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=small
#SBATCH --time=00:05:00
#SBATCH --ntasks=1
#SBATCH --nodes=1
#SBATCH --cpus-per-task=8 # Each core gives 1.875 GB of memory

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec Rscript --no-save myscript.R

future-pakettiperheen moniydintyöt

future-pakettiperhe tarjoaa monipuolisia tapoja rinnakkaistaa R-töitä vähäisellä valmistelulla. future-paketti tarjoaa kehikon futureja käyttäville R-töille (katso lisätietoja future-paketin CRAN-sivulta). Se, ratkaistaanko futuret peräkkäin vai rinnakkain, määritetään plan()-funktiolla.

Analyyseihin, joissa käytetään useita ytimiä yhdellä solmulla, plan(multisession) ja plan(multicore) ovat sopivia. Ensimmäinen käynnistää useita toisistaan riippumattomia R-prosesseja ja jälkimmäinen haarauttaa olemassa olevan R-prosessin. Huomaa, että plan(multicore) ei toimi RStudiossa. plan(cluster) sopii töihin, joissa käytetään useita solmuja (katso alla).

Lähettääksesi työn, joka käyttää multisession- tai multicore-futureja, tulee määrittää yksi solmu (--nodes=1), yksi tehtävä (--ntasks=1) ja ytimien määrä (--cpus-per-task=x). Oletuksena työntekijöiden määrä on parallelly::availableCores()-funktion palauttama ydinmäärä. Ohjeita eräajotiedostojen suunnitteluun löytyy yllä olevasta moniydineräajoesimerkistä.

Alla olevaa R-skriptiä voitaisiin käyttää analyysiaikojen vertaamiseen sequential-, multisession- ja multicore-strategioilla.

library(future)
library(tictoc)
library(furrr)

# Different future plans (choose one) 
# (Note: three cores and thus three workers were used in this example)

# plan(sequential)
# plan(multisession)
# plan(multicore)

# Analysis timing

tic()
nothingness <- future_map(c(2, 2, 2), ~Sys.sleep(.x))
toc()

# sequential: 6.157 sec
# multisession: 2.463 sec
# multicore: 2.212 sec

Käytännön esimerkkejä future-töistä, joissa käytetään plan(multicore)- ja plan(cluster)-asetuksia (kuten alla kohdassa usean solmun R-työt MPI:n kanssa) rasteridatan kanssa, löytyy CSC:n Geocomputing-esimerkeistä.

Yksi future-paketin etu on, että globaalit muuttujat viedään automaattisesti ja ovat rinnakkaisprosessien käytettävissä. Kun rinnakkaiskäsittelyä rakennetaan parallel- tai snow-paketeilla, voi olla tarpeen ladata paketit uudelleen skriptin siinä osassa, joka suoritetaan rinnakkain, ja käyttää clusterExport-funktiota, jotta globaalissa ympäristössä olevat objektit saadaan rinnakkaisprosessien käyttöön.

Suorituskyvyn parantaminen säikeistyksellä

r-env on käännetty käyttäen Intel® oneAPI Math Kernel Librarya (oneMKL), mikä mahdollistaa data-analyysitehtävien suorittamisen useilla säikeillä. Lisätietoja säikeistyksestä löytyy Intel®-verkkosivustolta.

Oletuksena r-env on yksisäikeinen. Tietyt R-paketit, kuten data.table, mgcv ja ranger, tarjoavat suoran tuen monisäikeistykselle. Myös muuntyyppisiä R-paketteja käyttävät työt voivat hyötyä monisäikeistyksestä analyysistä riippuen. Esimerkiksi monisäikeistys voi nopeuttaa lineaarialgebran rutiineja. Selvittääksesi, hyödyttääkö monisäikeistys tiettyä analyysiä, suosittelemme kokeilemaan eri säiemääriä ja vertailemaan koodisi suorituskykyä pienellä esimerkkiaineistolla sekä esimerkiksi R-paketilla microbenchmark.

Moduuli käyttää OpenMP-säikeistysteknologiaa, ja säikeiden määrää voidaan hallita ympäristömuuttujalla OMP_NUM_THREADS. Käytännössä säikeiden määrä asetetaan vastaamaan työssä käytettyjen ytimien määrää. Koska r-env perustuu Apptainer-säiliöön, OpenMP-säikeiden määrää määritettäessä on käytettävä ympäristömuuttujaa APPTAINERENV_OMP_NUM_THREADS.

Alla on esimerkki eräajokomentosarjasta. Tässä lähetämme työn, joka käyttää kahdeksaa ydintä (ja siten kahdeksaa säiettä) yhdellä solmulla. Huomaa, miten sovitamme säikeiden ja ytimien määrän yhteen käyttämällä APPTAINERENV_OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK. Käyttämällä APPTAINERENV_OMP_PLACES=cores sidomme jokaisen säikeen yhteen ytimeen. Käytämme myös APPTAINERENV_OMP_PROC_BIND=close-asetusta varmistaaksemme, että säikeet sijoitetaan mahdollisimman lähelle toisiaan (jotta säikeiden välinen viestintä olisi nopeampaa). Huomaa, että muitakin vaihtoehtoja säieaffiniteetin hallintaan on saatavilla analyysistäsi riippuen.

#!/bin/bash -l
#SBATCH --job-name=r_multithread
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=small
#SBATCH --time=00:05:00
#SBATCH --ntasks=1
#SBATCH --nodes=1
#SBATCH --cpus-per-task=8
#SBATCH --mem-per-cpu=2000

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Match thread and core numbers
export APPTAINERENV_OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK

# Thread affinity control
export APPTAINERENV_OMP_PLACES=cores
export APPTAINERENV_OMP_PROC_BIND=close

# Run the R script
srun apptainer_wrapper exec Rscript --no-save myscript.R
#!/bin/bash -l
#SBATCH --job-name=r_multithread
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=small
#SBATCH --time=00:05:00
#SBATCH --ntasks=1
#SBATCH --nodes=1
#SBATCH --cpus-per-task=8 # Each core gives 1.875 GB of memory

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Match thread and core numbers
export APPTAINERENV_OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK

# Thread affinity control
export APPTAINERENV_OMP_PLACES=cores

# Run the R script
srun apptainer_wrapper exec Rscript --no-save myscript.R

Moniytimisessä interaktiivisessa työssä säikeiden määrä voidaan sovittaa automaattisesti ytimien määrään suorittamalla monisäikeinen versio start-r- tai start-rstudio-server-komennosta:

start-r-multithread # or
start-rstudio-server-multithread
Selainkäyttöliittymän RStudiossa moniytiminen R-istunto voidaan asettaa käyttämään useita säikeitä valitsemalla Multithreaded-valintaruutu.

Usean solmun R-työt MPI:n kanssa

Jos rinnakkainen R-työ voidaan suorittaa yhden solmun ytimillä, sitä suositellaan aina. Kun tarvitaan enemmän ytimiä, r-env-moduulia voidaan käyttää rinnakkaisten R-töiden suorittamiseen useiden solmujen yli. Useilla solmuilla (eli erillisillä tietokoneilla) suoritettavat rinnakkaistehtävät eivät jaa muistia ja tarvitsevat menetelmän viestintään. CSC:n supertietokoneilla solmujen välinen viestintä hoidetaan MPI:llä (Message Passing Interface). Usean solmun R-töiden on siksi käytettävä R-paketteja, jotka tukevat usean solmun viestintää MPI:n kautta, kuten future, snow, doMPI (käytettynä foreach-paketin kanssa) ja pbdMPI.

Vakiotapa käynnistää MPI-R-työt CSC:n supertietokoneilla on käyttää snow-paketin RMPISNOW-komentoa R:n käynnistämiseen Rscript-komennon sijaan. Huomaa kuitenkin, että alla on myös esimerkkejä MPI-töistä, joissa käytetään muita lähestymistapoja. Useimmat MPI-työt, mukaan lukien snow-paketilla käynnistetyt, perustuvat viestintämalliin, jossa pääprosessi ohjaa muita prosesseja (työntekijöitä). Tämän vuoksi eräajotiedoston on määritettävä yksi tehtävä enemmän kuin suunniteltu työntekijöiden määrä, koska pääprosessi tarvitsee oman tehtävänsä.

Vaikka eräajotiedosto muuten näyttää samalta kuin moniydintyössä, korvaamme --cpus-per-task=x asetuksella --ntasks-per-node=x ja käytämme --nodes-asetusta solmujen määrän määrittämiseen. Työntekijöiden määrä on yleensä ntasks-per-node x nodes - 1. Lisäksi voisimme muokata eräajotiedoston lopussa olevaa srun-komentoa:

srun apptainer_wrapper exec Rscript --no-save --slave myscript.R
srun apptainer_wrapper exec Rscript --no-save --slave myscript.R

--slave-argumentti on valinnainen ja estää muun muassa eri prosesseja tulostamasta tervetuloviestiä.

Lisätietoja löytyy MPI-töiden yleisdokumentaatiosta.

Rmpi-pakettia käyttäville töille käytä snow-pakettia (joka on rakennettu Rmpi:n päälle). Pelkkää Rmpi:tä käyttävät työt eivät ole saatavilla yhteensopivuusongelmien vuoksi.

Usean solmun työt future-paketilla

Jotta usean solmun analyysit voidaan suorittaa future-paketilla, valitsemme plan(cluster) ja käynnistämme R:n snow-paketin RMPISNOW-komennolla Rscript-komennon sijaan. Meidän tulee määrittää riittävästi tehtäviä sekä pää- että työntekijäprosesseille. Esimerkiksi työ, joka tarvitsee mahdollisimman monta työntekijää kahdella solmulla, voitaisiin lähettää future-työnä seuraavasti:

#!/bin/bash -l
#SBATCH --job-name=r_future
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=large
#SBATCH --time=01:00:00
#SBATCH --ntasks-per-node=40
#SBATCH --nodes=2 # 2 x 40 - 1 = 79 workers
#SBATCH --mem-per-cpu=1000

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec RMPISNOW --no-save --slave -f myscript.R
#!/bin/bash -l
#SBATCH --job-name=r_future
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=medium
#SBATCH --time=01:00:00
#SBATCH --ntasks-per-node=128 # 2 x 128 - 1 = 255 workers
#SBATCH --nodes=2

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec RMPISNOW --no-save --slave -f myscript.R

Jotta future toimisi snow-paketin kanssa, myös seuraavat rivit tulisi sisällyttää R-skriptiin:

library(future)

cl <- getMPIcluster()
plan(cluster, workers = cl)

# Analysis here

stopCluster(cl)

Usean solmun työt snow-paketilla

Jotta usean solmun R-työ voitaisiin käynnistää suoraan snow-paketilla siten, että käytetään mahdollisimman monta työntekijää kahdella solmulla, sen voisi lähettää seuraavasti. R käynnistetään RMPISNOW-komennolla, ja meidän on määritettävä yksi tehtävä enemmän kuin suunniteltu snow-työntekijöiden määrä, koska pääprosessi tarvitsee oman tehtävänsä.

#!/bin/bash -l
#SBATCH --job-name=r_snow
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=large
#SBATCH --time=01:00:00
#SBATCH --ntasks-per-node=40
#SBATCH --nodes=2 # 2 x 40 - 1 = 79 workers
#SBATCH --mem-per-cpu=1000

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec RMPISNOW --no-save --slave -f myscript.R
#!/bin/bash -l
#SBATCH --job-name=r_snow
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=medium
#SBATCH --time=01:00:00
#SBATCH --ntasks-per-node=128 # 2 x 128 - 1 = 255 workers
#SBATCH --nodes=2

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec RMPISNOW --no-save --slave -f myscript.R

Vain pääprosessi suorittaa R-skriptin. R-skriptin on sisällettävä kutsu getMPIcluster(), jota käytetään tuottamaan viite klusteriin ja joka voidaan sitten välittää muille funktioille. Analyysin valmistuttua klusteri pysäytetään stopCluster()-funktiolla. Esimerkiksi:

cl <- getMPIcluster()

funtorun <- function(k) {
  system.time(sort(runif(1e7)))
}

system.time(a <- clusterApply(cl, 1:79, funtorun))
a

stopCluster(cl)
cl <- getMPIcluster()

funtorun <- function(k) {
  system.time(sort(runif(1e7)))
}

system.time(a <- clusterApply(cl, 1:255, funtorun))
a

stopCluster(cl)

Työt doMPI-paketilla (foreach-paketin kanssa)

foreach-paketti toteuttaa for-silmukan, joka käyttää iteraattoreita ja mahdollistaa rinnakkaisen suorituksen %dopar%-operaattorilla. Rinnakkaisia foreach-silmukoita on mahdollista suorittaa useilla ytimillä monien eri sovittimien avulla, kuten doParallel sisäänrakennetulle R-paketille parallel ja doFuture future-paketille. Usean solmun ja MPI:n työt foreach-paketin kanssa voidaan suorittaa doMPI-paketin rinnakkaistaustajärjestelmällä.

Toisin kuin snow-pakettia käytettäessä, doMPI-pakettia käyttävät työt käynnistävät yhtä monta R-istuntoa kuin varattuja tehtäviä on, ja kaikki alkavat suorittaa annettua R-skriptiä (tässä kahdeksan). On tärkeää sisällyttää startMPIcluster()-kutsu lähelle R-skriptin alkua, koska kaikki sitä edeltävä suoritetaan kaikissa käytettävissä olevissa prosesseissa (kun taas vain pääprosessi jatkaa sen jälkeen). Valmistuttuaan klusteri suljetaan closeCluster()-funktiolla. Tämän jälkeen mpi.quit()-funktiota voidaan käyttää MPI-suoritusympäristön lopettamiseen ja R:n sulkemiseen:

library(doMPI, quietly = TRUE)
cl <- startMPIcluster()
registerDoMPI(cl)

system.time(a <- foreach(i = 1:7) %dopar% system.time(sort(runif(1e7))))
a

closeCluster(cl)
mpi.quit()

Usean solmun työt pbdMPI-paketilla

Analyyseissä, joissa käytetään pbdMPI-pakettia, jokainen prosessi suorittaa saman kopion ohjelmasta kuin kaikki muutkin prosessit, mutta omalla datallaan. Toisin sanoen erillistä pääprosessia ei ole kuten snow- tai doMPI-paketeissa. Eräajojen suorittaminen pbdMPI-paketilla voidaan tehdä komennolla srun apptainer_wrapper exec Rscript. Esimerkiksi voisimme lähettää työn, joka käyttää kaikkia kahden solmun ytimiä (siten, että puolet tehtävien kokonaismäärästä kohdistetaan kummallekin solmulle):

#!/bin/bash -l
#SBATCH --job-name=r_pbdmpi
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=large
#SBATCH --time=00:05:00
#SBATCH --ntasks-per-node=40
#SBATCH --nodes=2
#SBATCH --mem-per-cpu=2000

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec Rscript --no-save --slave myscript.R
#!/bin/bash -l
#SBATCH --job-name=r_pbdmpi
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=test
#SBATCH --time=00:05:00
#SBATCH --ntasks-per-node=128
#SBATCH --nodes=2

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Run the R script
srun apptainer_wrapper exec Rscript --no-save --slave myscript.R

Esimerkkinä tätä eräajotiedostoa voitaisiin käyttää suorittamaan seuraava "hello world" -skripti (alkuperäinen versio on saatavilla pbdMPI-paketin Github-repositoriosta). init()-funktio alustaa MPI-kommunikaattorit, kun taas finalize()-funktiota käytetään niiden sulkemiseen ja R:stä poistumiseen.

library(pbdMPI, quietly = TRUE)

init()

message <- paste("Hello from rank", comm.rank(), "of", comm.size())
comm.print(message, all.rank = TRUE, quiet = TRUE)

finalize()

OpenMP / MPI -hybridityöt

Sen lisäksi, että monisäikeisiä R-töitä suoritetaan yhdellä solmulla, niitä voidaan suorittaa myös useilla solmuilla. Tällaisissa tapauksissa on määritettävä seuraavien määrä:

  • Solmut (--nodes)

  • MPI-prosessit per solmu (--ntasks-per-node)

  • Kullekin MPI-prosessille käytettävät OpenMP-säikeet (--cpus-per-task)

Kun nämä luetellaan eräajotiedostossa, huomaa, että --ntasks-per-node × --cpus-per-task on oltava pienempi tai yhtä suuri kuin yhdellä solmulla käytettävissä olevien ytimien enimmäismäärä. Suurissa usean solmun töissä pyri käyttämään täysiä solmuja eli kaikkia kunkin solmun ytimiä. Sopivan OpenMP-säiemäärän valinnan lisäksi MPI-prosessien optimaalisen määrän ja jaon tunnistaminen vaatii kokeiluja, koska nämä ovat työkohtaisia.

Esimerkkinä OpenMP / MPI -hybridityöstä alla oleva lähetys käyttäisi yhteensä neljää MPI-prosessia (kaksi tehtävää per solmu ja kaksi varattua solmua), ja kukin prosessi käyttäisi kahdeksaa OpenMP-säiettä. Kokonaisuudessaan työ käyttäisi Puhdissa 32 ydintä (--cpus-per-task × --ntasks-per-node × --nodes). Kuten yhdellä solmulla suoritettavissa monisäikeisissä töissä, säikeiden ja ytimien määrä sovitetaan yhteen käyttämällä APPTAINERENV_OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK. Käytämme myös samoja muuttujia säieaffiniteetin hallintaan.

#!/bin/bash -l
#SBATCH --job-name=r_multithread_multinode
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=test
#SBATCH --time=00:05:00
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=2
#SBATCH --cpus-per-task=8
#SBATCH --mem-per-cpu=2000

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
 sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Match thread and core numbers
export APPTAINERENV_OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK

# Thread affinity control
export APPTAINERENV_OMP_PLACES=cores
export APPTAINERENV_OMP_PROC_BIND=close

# Run the R script
srun apptainer_wrapper exec Rscript --no-save myscript.R
#!/bin/bash -l
#SBATCH --job-name=r_multithread_multinode
#SBATCH --account=<project>
#SBATCH --output=output_%j.txt
#SBATCH --error=errors_%j.txt
#SBATCH --partition=test
#SBATCH --time=00:05:00
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=2 
#SBATCH --cpus-per-task=64 # ntasks-per-node x cpus-per-task should equal 128

# Load r-env
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
 sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Match thread and core numbers
export APPTAINERENV_OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK

# Thread affinity control
export APPTAINERENV_OMP_PLACES=cores

# Run the R script
srun apptainer_wrapper exec Rscript --no-save myscript.R

Laajamittaiset taulukkotyöt GNU parallelin avulla

Suurempia taulukkotöitä varten, joissa on mukana paljon pieniä riippumattomia ajoja, voisimme harkita seuraavaa esimerkkiä. Oletetaan, että meillä on yhteensä 1500 ajoa, jotka haluamme suorittaa loppuun. Meillä on myös lista (mylist.txt), jossa on yksilölliset tunnisteet jokaiselle ajolle ja joita haluamme käyttää osana R-skriptiä oikean analysoitavan datajoukon hakemiseen. Lista on järjestetty riveittäin näin:

set1
set2
set3
(...)
set1500

Jotta analyysi voitaisiin suorittaa tehokkaasti, voisimme hyödyntää GNU parallel -ohjelman sisältävää moduulia ajojen "aikatauluttamiseen" taulukkotyön sisällä. Alla olevassa eräajokomentosarjassa on muutama yksityiskohta, joihin kannattaa kiinnittää huomiota:

  • Tapa, jolla ajot jaetaan taulukoihin, on tapauskohtainen ja vaatii manuaalista laskentaa. Tässä esimerkissä, koska mylist.txt sisältää 1500 tunnistetta ja käytämme 10 taulukkoa, on päätetty kohdistaa 150 ajoa per taulukko.

  • Käytämme -j $SLURM_CPUS_PER_TASK -k kertoaksemme GNU parallelille, että sen tulee pitää 4 sovellusta käynnissä rinnakkain ja samalla varmistaa, että työn tulostusjärjestys vastaa syötejärjestystä. Samanaikaisten rinnakkaisten sovellusten määrä määritetään --cpus-per-task-asetuksella.

  • Todellisessa analyysissä tarvitsisimme todennäköisesti paljon enemmän aikaa ja muistia (sen mukaan, mitä teemme R-skriptissä).

#!/bin/bash -l
#SBATCH --job-name=r_array_gnupara
#SBATCH --account=<project>
#SBATCH --output=output_%j_%a.txt
#SBATCH --error=errors_%j_%a.txt
#SBATCH --partition=small
#SBATCH --time=00:05:00
#SBATCH --array=0-9
#SBATCH --ntasks=1
#SBATCH --nodes=1
#SBATCH --cpus-per-task=4
#SBATCH --mem-per-cpu=2000

# Load parallel and r-env
module load parallel
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Split runs into arrays and run the R script
(( from_run = SLURM_ARRAY_TASK_ID * 150 + 1 ))
(( to_run = SLURM_ARRAY_TASK_ID * 150 + 150 ))

sed -n "${from_run},${to_run}p" mylist.txt | \
    parallel -j $SLURM_CPUS_PER_TASK -k \
        apptainer_wrapper exec Rscript --no-save myscript.R \
                $SLURM_ARRAY_TASK_ID
#!/bin/bash -l
#SBATCH --job-name=r_array_gnupara
#SBATCH --account=<project>
#SBATCH --output=output_%j_%a.txt
#SBATCH --error=errors_%j_%a.txt
#SBATCH --partition=small
#SBATCH --time=00:05:00
#SBATCH --array=0-9
#SBATCH --ntasks=1
#SBATCH --nodes=1
#SBATCH --cpus-per-task=4 # Each core gives 1.875 GB of memory

# Load parallel and r-env
module load parallel
module load r-env

# Clean up .Renviron file in home directory
if test -f ~/.Renviron; then
    sed -i '/TMPDIR/d' ~/.Renviron
fi

# Specify a temporary directory path (replace <project> with your project)
echo "TMPDIR=/scratch/<project>" >> ~/.Renviron

# Split runs into arrays and run the R script
(( from_run = SLURM_ARRAY_TASK_ID * 150 + 1 ))
(( to_run = SLURM_ARRAY_TASK_ID * 150 + 150 ))

sed -n "${from_run},${to_run}p" mylist.txt | \
    parallel -j $SLURM_CPUS_PER_TASK -k \
        apptainer_wrapper exec Rscript --no-save myscript.R \
                $SLURM_ARRAY_TASK_ID

Lisätietoja

Suomenkielinen tekoälykäännös

Sisällössä voi esiintyä virheellistä tietoa tekoälykäännöksestä johtuen.

Klikkaa tästä antaaksesi palautetta