Uso de MPI no SDumont com Slurm¶
Este roteiro mostra como preparar o ambiente, compilar um programa MPI, solicitar recursos e conferir onde cada processo executou no SDumont.
Os exemplos foram adaptados dos comandos e da consulta à partição fornecidos para a aula.
Entendendo os papéis de MPI e Slurm¶
O MPI permite que processos troquem mensagens. O Slurm recebe o pedido de recursos, coloca o job na fila e organiza sua execução nos nós de computação.
| Conceito | Significado | Exemplo |
|---|---|---|
| Nó | Um computador do cluster | Um nó escolhido pelo Slurm |
| Processo MPI | Uma instância do programa com memória própria | Uma execução de hello |
| Rank | Identificador do processo no comunicador | 0 e 1 em uma execução com dois processos |
| Tarefa Slurm | Unidade de execução solicitada ao escalonador | Neste roteiro, uma tarefa para cada processo MPI |
| CPU por tarefa | Recurso de CPU solicitado para cada tarefa | --cpus-per-task=1 |
| Partição | Conjunto de recursos e regras de execução | sequana_cpu_dev |
| Job | Pedido de recursos submetido ao Slurm | Um job identificado por um número |
Dois processos podem executar no mesmo nó. Portanto, pedir dois processos não significa automaticamente pedir dois computadores: a distribuição depende também das opções de nós e tarefas por nó.
Após conectar via VPN e SSH no Santos Dumont, acesse a sua pasta scratch:
cd /scratch/insperhpc/seu_usuario/
Como o SDumont é um ambiente compartilhado com vários usuários e várias necessidades de ferramentas diferentes, as bilbiotecas ficam instaladas mas não ficam disponíveis automaticamente para não gerar conflito entre os projetos. Para utilizar uma ferramenta ou biblioteca específica, é preciso carregar o modulo. Para verificar modulos disponpiveis no sistema utilize:
module avail
Para filtrar alguma biblioteca especifica e verificar as versões disponíveis, utilize:
module avail mpi
Para carregar o módulo, utilize:
module load openmpi/gnu/4.1.8_sequana
Para verificar os módulos carregados no seu ambiente, utilize
module list
hello.cpp
#include <mpi.h>
#include <iostream>
#include <sstream>
using namespace std;
int main(int argc, char** argv) {
MPI_Init(&argc, &argv);
int rank, total, tamanho;
char nome[MPI_MAX_PROCESSOR_NAME];
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &total);
MPI_Get_processor_name(nome, &tamanho);
// Cada processo faz uma computação simples para identificar sua tarefa.
int resultado = rank * rank;
// Monta o registro de cada processo antes de imprimi-lo.
ostringstream mensagem;
mensagem << "Rank " << rank << " de " << total
<< " | Nó: " << nome
<< " | Quadrado do rank: " << resultado << '\n';
cout << mensagem.str() << flush;
MPI_Finalize();
return 0;
}
O código demo mostra o rank, o tamanho do comunicador, o nó e o resultado local. A ordem das linhas pode variar porque os processos executam concorrentemente. Montar uma mensagem antes de imprimir reduz a fragmentação dos prints, mas não estabelece uma ordem global.
Para compilar:
mpic++ -O3 hello.cpp -o hello
hello.cpp, recompile antes de executar novamente.
Após carregar o módulo e compilar:
srun --partition=sequana_cpu_dev --mem=1G \
--nodes=2 --ntasks=2 --ntasks-per-node=1 \
--cpus-per-task=1 --time=00:01:00 ./hello
Uma saída possível seria:
srun: job 11618883 queued and waiting for resources
srun: job 11618883 has been allocated resources
Rank 1 | Nó: sdumont6237
: Minha computação é = 1
Rank 0 | Nó: sdumont6237
Tarefa: calcular o quadrado de cada ID.
Temos 2 nós.
Rank 1 | Nó: sdumont6238
: Minha computação é = 1
Rank 0 | Nó: sdumont6238
Tarefa: calcular o quadrado de cada ID.
Temos 2 nós.
Por que não usamos --mpi=pmix?
A forma de integração depende de como o módulo MPI e o Slurm foram configurados. MPICH pode usar diferentes interfaces de inicialização. Por isso os comandos no Santos Dumont e no Franky tem algumas diferenças.
Para submeter um job com sbatch:
run.slurm
#!/bin/bash
#SBATCH --job-name=hello-mpi
#SBATCH --partition=sequana_cpu_dev
#SBATCH --nodes=4
#SBATCH --ntasks=4
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --mem=1G
#SBATCH --time=00:01:00
#SBATCH --output=mpi-%j.out
echo "Job: $SLURM_JOB_ID"
echo "Nós alocados: $SLURM_JOB_NODELIST"
echo "Tarefas: $SLURM_NTASKS"
# Inicia a mesma quantidade de processos solicitada ao Slurm.
mpiexec -np "$SLURM_NTASKS" ./hello
Submeta com o comando:
sbatch run.slurm
Para monitorar a fila:
squeue -u "$USER"
Para um job de exemplo com ID 11618863:
cat mpi-11618863.out
Substitua o número pelo ID da sua submissão. Para cancelar um job seu que não é mais necessário:
scancel 11618863