Hyppää sisältöön

Docs CSC now features an automatic Finnish translation. Click here for more information.

Warning!

Puhti and Mahti will be decommissioned after Roihu becomes available. Users should clean up unnecessary files and move any required data by the end of August 2026. See the Roihu data preparation instructions for details.

Puhti scratch is very full: keep only active data there and move or delete everything else. No new Puhti scratch quota will be granted.

Julia-eräajojen suorittaminen CSC:n klustereilla

Tämä opas sisältää esimerkkejä erilaisten Julia-eräajojen suorittamisesta Puhdin, Mahdin ja LUMIn klustereilla.

Esimerkit

Nämä esimerkit havainnollistavat Julia-ympäristön käyttöä erilaisissa eräajoissa. Ne on mukautettu yleisistä ohjeista, jotka koskevat ajotöiden suorittamista Puhdissa ja Mahdissa sekä LUMIssa. Huomaa, että emme käytä srun-komentoa prosessien käynnistämiseen eräajokomentosarjassa. Sen sijaan käytämme Juliaa prosessien hallintaan tai kutsumme srun-komentoa Julia-koodin sisältä.

Ennen esimerkkien suorittamista meidän täytyy instansioida Julia-projekti kirjautumissolmulla. Suorita siis seuraava komento siinä hakemistossa, jossa Julia-ympäristösi sijaitsee ja jossa Project.toml-tiedosto on.

module load julia
julia --project=. --threads=1 -e 'using Pkg; Pkg.instantiate()'
module load julia
julia --project=. --threads=1 -e 'using Pkg; Pkg.instantiate()'
module use /appl/local/csc/modulefiles
module load julia
julia --project=. --threads=1 -e 'using Pkg; Pkg.instantiate()'

Voit käyttää useita säikeitä, esimerkiksi --threads=10, mikä nopeuttaa esikäännöstä.

Sarjaohjelma

Käytämme seuraavaa hakemistorakennetta ja oletamme, että se on työhakemistomme.

.
├── Project.toml  # Julia-ympäristö
├── batch.sh      # Slurm-eräajokomentosarja
└── script.jl     # Julia-komentosarja

Esimerkki script.jl-koodista.

println("Hello world!")

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=1000

module load julia
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=interactive
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=1875

module load julia
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=1000

module use /appl/local/csc/modulefiles
module load julia
julia --project=. script.jl

Monisäikeistys yhdellä solmulla

Käytämme seuraavaa hakemistorakennetta ja oletamme, että se on työhakemistomme.

.
├── Project.toml  # Julia-ympäristö
├── batch.sh      # Slurm-eräajokomentosarja
└── script.jl     # Julia-komentosarja

Esimerkki script.jl-koodista.

# Number of threads
n = Threads.nthreads()
println(n)

# Lets fill the id of each thread to the ids array.
ids = zeros(Int, n)
Threads.@threads for i in eachindex(ids)
    ids[i] = Threads.threadid()
end
println(ids)

# Alternatively, we can use the @spawn macro to run task on threads.
ids = zeros(Int, n)
@sync for i in eachindex(ids)
    Threads.@spawn ids[i] = Threads.threadid()
end
println(ids)

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=3
#SBATCH --mem-per-cpu=1000

module load julia
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=medium
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=128
#SBATCH --mem-per-cpu=0

module load julia
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=3
#SBATCH --mem-per-cpu=1000

module use /appl/local/csc/modulefiles
module load julia
julia --project=. script.jl

Moniprosessointi yhdellä solmulla

Käytämme seuraavaa hakemistorakennetta ja oletamme, että se on työhakemistomme.

.
├── Project.toml  # Julia-ympäristö
├── batch.sh      # Slurm-eräajokomentosarja
└── script.jl     # Julia-komentosarja

Esimerkki Project.toml-projektitiedostosta.

[deps]
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"

Esimerkki script.jl-koodista.

using Distributed

# We set one worker process per core.
proc_num = Sys.CPU_THREADS

# Environment variables that we pass to the worker processes.
# We set the thread count to one since each process uses one core.
proc_env = [
    "JULIA_NUM_THREADS"=>"1",
    "JULIA_CPU_THREADS"=>"1",
    "OPENBLAS_NUM_THREADS"=>"1",
]

# We add worker processes to the local node using LocalManager.
addprocs(proc_num; env=proc_env, exeflags="--project=.")

# We use the `@everywhere` macro to include the task function in the worker processes.
# We must call `@everywhere` after adding worker processes; otherwise the code won't be included in the new processes.
@everywhere function task()
    return (worker=myid(), hostname=gethostname(), pid=getpid())
end

# We run the task function in each worker process.
futures = [@spawnat worker task() for worker in workers()]

# Then, we fetch the output from the processes.
outputs = fetch.(futures)

# Remove processes after we are done.
rmprocs.(workers())

# Print the outputs of master and worker processes.
println(task())
println.(outputs)

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=3
#SBATCH --mem-per-cpu=1000

module load julia
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=medium
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=128
#SBATCH --mem-per-cpu=0

module load julia
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=3
#SBATCH --mem-per-cpu=1000

module use /appl/local/csc/modulefiles
module load julia
julia --project=. script.jl

Moniprosessointi usealla solmulla

Käytämme seuraavaa hakemistorakennetta ja oletamme, että se on työhakemistomme.

.
├── Project.toml  # Julia-ympäristö
├── batch.sh      # Slurm-eräajokomentosarja
└── script.jl     # Julia-komentosarja

Esimerkki Project.toml-projektitiedostosta.

[deps]
SlurmClusterManager = "c82cd089-7bf7-41d7-976b-6b5d413cbe0a"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"

Esimerkki script.jl-koodista.

using Distributed
using SlurmClusterManager

# We set one worker process per core.
proc_num = parse(Int, ENV["SLURM_NTASKS"])

# Environment variables that we pass to the worker processes.
# We set the thread count to one since each process uses one core.
n = Threads.nthreads()
proc_env = [
    "JULIA_NUM_THREADS"=>"$n",
    "JULIA_CPU_THREADS"=>"$n",
    "OPENBLAS_NUM_THREADS"=>"$n",
]

# We add worker processes to the local node using SlurmManager
addprocs(SlurmManager())

# We use the `@everywhere` macro to include the task function in the worker processes.
# We must call `@everywhere` after adding worker processes; otherwise the code won't be included in the new processes.
@everywhere function task()
    return (worker=myid(), hostname=gethostname(), pid=getpid())
end

# We run the task function in each worker process.
futures = [@spawnat worker task() for worker in workers()]

# Then, we fetch the output from the processes.
outputs = fetch.(futures)

# Remove processes after we are done.
rmprocs.(workers())

# Print the outputs of master and worker processes.
println(task())
println.(outputs)

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=large
#SBATCH --time=00:15:00
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=2
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=1000

module load julia
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=medium
#SBATCH --time=00:15:00
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=128
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=0

module load julia
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=standard
#SBATCH --time=00:15:00
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=128
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=0

module use /appl/local/csc/modulefiles
module load julia
julia --project=. script.jl

MPI-ohjelma

Käynnistämme MPI-ohjelman Julian mpiexec-käärefunktiolla. Käärefunktio korvaa paikallisista asetuksista oikean komennon mpirun-muuttujaan MPI-ohjelman suorittamista varten. Komento on srun Puhdissa, Mahdissa ja LUMIssa. Kääre mahdollistaa joustavamman koodin kirjoittamisen, esimerkiksi MPI- ja ei-MPI-koodin yhdistämisen, sekä siirrettävämmän koodin, koska MPI-ohjelmien suorituskomento voi vaihdella eri alustoilla. Huomaa, että laajamittaisissa Julia MPI -ajoissa, joissa on tuhansia rankeja, meidän täytyy jakaa depot-hakemisto paikalliseen solmutallennukseen tai muistiin ja muokata depot-polkuja vastaavasti. Muuten pakettien lataamisesta tulee erittäin hidasta.

Käytämme seuraavaa hakemistorakennetta ja oletamme, että se on työhakemistomme.

.
├── Project.toml  # Julia-ympäristö
├── batch.sh      # Slurm-eräajokomentosarja
├── prog.jl       # Julia MPI -ohjelma
└── script.jl     # Julia-komentosarja

Esimerkki Project.toml-projektitiedostosta.

[deps]
MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"

Esimerkki script.jl-koodista.

using MPI
mpiexec(mpirun -> run(`$mpirun julia --project=. prog.jl`))

Esimerkki prog.jl Julia MPI -koodista.

using MPI

MPI.Init()
comm = MPI.COMM_WORLD
rank = MPI.Comm_rank(comm)
size = MPI.Comm_size(comm)
println("Hello from rank $(rank) out of $(size) from host $(gethostname()) and process $(getpid()).")
MPI.Barrier(comm)

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=large
#SBATCH --time=00:15:00
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=2
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=1000

module load julia
module load julia-mpi
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=medium
#SBATCH --time=00:15:00
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=128
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=0

module load julia
module load julia-mpi
julia --project=. script.jl

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=standard
#SBATCH --time=00:15:00
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=128
#SBATCH --cpus-per-task=1
#SBATCH --mem-per-cpu=0

module use /appl/local/csc/modulefiles
module load julia
module load julia-mpi
julia --project=. script.jl

Yksi GPU

Käytämme seuraavaa hakemistorakennetta ja oletamme, että se on työhakemistomme.

.
├── Project.toml  # Julia-ympäristö
├── batch.sh      # Slurm-eräajokomentosarja
└── script.jl     # Julia-komentosarja

Esimerkki Project.toml-projektitiedostosta.

[deps]
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"

[compat]
CUDA = "< 5.9"

Esimerkki script.jl-koodista.

using CUDA

A = rand(2^9, 2^9)
A_d = CuArray(A)
B_d = A_d * A_d

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpu
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=10
#SBATCH --gres=gpu:v100:1
#SBATCH --mem-per-cpu=8000

module load julia
module load julia-cuda
julia --project=. script.jl

Esimerkki Project.toml-projektitiedostosta.

[deps]
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"

[compat]
CUDA = "< 5.9"

Esimerkki script.jl-koodista.

using CUDA

A = rand(2^9, 2^9)
A_d = CuArray(A)
B_d = A_d * A_d

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=gpusmall
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=32
#SBATCH --gres=gpu:a100:1
#

module load julia
module load julia-cuda
julia --project=. script.jl

Esimerkki Project.toml-projektitiedostosta.

[deps]
AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e"

Esimerkki script.jl-koodista.

using AMDGPU

A = rand(2^9, 2^9)
A_d = ROCArray(A)
B_d = A_d * A_d

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --time=00:15:00
#SBATCH --nodes=1
#SBATCH --gpus-per-node=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=8
#SBATCH --mem-per-cpu=1750

module use /appl/local/csc/modulefiles
module load julia
module load julia-amdgpu
julia --project=. script.jl

Useita GPU:ita MPI:n kanssa

Käytämme seuraavaa hakemistorakennetta ja oletamme, että se on työhakemistomme.

.
├── Project.toml  # Julia-ympäristö
├── batch.sh      # Slurm-eräajokomentosarja
├── prog.jl       # Julia GPU-aware MPI -ohjelma
└── script.jl     # Julia-komentosarja

Esimerkki script.jl-koodista.

using MPI
mpiexec(mpirun -> run(`$mpirun julia --project=. prog.jl`))

Esimerkki Project.toml-projektitiedostosta.

[deps]
AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e"
MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"

Esimerkki prog.jl-koodista. (lähde)

using MPI
using AMDGPU
MPI.Init()
comm = MPI.COMM_WORLD
rank = MPI.Comm_rank(comm)
# select device
comm_l = MPI.Comm_split_type(comm, MPI.COMM_TYPE_SHARED, rank)
rank_l = MPI.Comm_rank(comm_l)
device = AMDGPU.device_id!(rank_l+1)
gpu_id = AMDGPU.device_id(AMDGPU.device())
# select device
size = MPI.Comm_size(comm)
dst  = mod(rank+1, size)
src  = mod(rank-1, size)
println("rank=$rank rank_loc=$rank_l (gpu_id=$gpu_id - $device), size=$size, dst=$dst, src=$src")
N = 4
send_mesg = ROCArray{Float64}(undef, N)
recv_mesg = ROCArray{Float64}(undef, N)
AMDGPU.synchronize()
rank==0 && println("start sending...")
MPI.Sendrecv!(send_mesg, dst, 0, recv_mesg, src, 0, comm)
println("recv_mesg on proc $rank: $recv_mesg")
rank==0 && println("done.")

Esimerkki batch.sh-eräajokomentosarjasta.

#!/bin/bash
#SBATCH --account=<project>
#SBATCH --partition=small-g
#SBATCH --time=00:15:00
#SBATCH --nodes=2
#SBATCH --gpus-per-node=8
#SBATCH --ntasks-per-node=8
#SBATCH --cpus-per-task=8
#SBATCH --mem-per-cpu=0

module use /appl/local/csc/modulefiles
module load julia
module load julia-mpi
module load julia-amdgpu
julia --project=. script.jl

Huomioita

Monisäikeistys lineaarialgebrassa

Julia käyttää oletusarvoisesti OpenBLASia LinearAlgebra-taustajärjestelmänä. Ulkoiset lineaarialgebran taustajärjestelmät, kuten OpenBLAS, käyttävät sisäistä säikeistystä. Voimme asettaa niiden säiemäärät ympäristömuuttujilla. julia-moduuli asettaa ne CPU-säikeiden määrään.

export OPENBLAS_NUM_THREADS=$JULIA_CPU_THREADS

Meidän täytyy varoa ylivaraamasta ytimiä, kun käytämme BLAS-operaatioita Julia-säikeiden tai -prosessien sisällä. Voimme muuttaa BLAS-säikeiden määrää ajon aikana BLAS.set_num_threads-funktiolla.

using LinearAlgebra

# Number of threads
n = Threads.nthreads()

# Define a matrix
X = rand(1000, 1000)

# Set the number of threads to one before performing BLAS operations of multiple Julia threads.
BLAS.set_num_threads(1)
Y = zeros(n)
Threads.@threads for i in 1:n  # uses n Julia threads
    Y[i] = sum(X * X)          # uses one BLAS thread
end

# Set the number of threads back to the default when performing BLAS operation on a single Julia Thread.
BLAS.set_num_threads(n)
Z = zeros(n)
for i in 1:n                   # uses one Julia thread
    Z[i] = sum(X * X)          # uses n BLAS threads
end

Vaihtoehtoisesti voimme käyttää MKL-taustajärjestelmää MKL.jl:n kautta lineaarialgebran taustajärjestelmänä. MKL on usein OpenBLASia nopeampi käytettäessä useita säikeitä Intelin CPU:illa, kuten Puhdissa. Voimme asettaa MKL:n säiemäärän seuraavasti.

export MKL_NUM_THREADS=$JULIA_CPU_THREADS

Jos käytämme MKL:ää, se tulisi ladata ennen muita lineaarialgebrakirjastoja.

using MKL
using LinearAlgebra
# your code ...

Eri BLAS-säiemäärien kuin yhden tai kaikkien ytimien käyttämisessä OpenBLASin ja MKL:n kanssa on huomioitavia rajoitteita.

Suomenkielinen tekoälykäännös

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

Klikkaa tästä antaaksesi palautetta