MPI + OpenMP
- При запуске задачи с использованием планировщика PBS надо учитывать, что значение переменной окружения '$OMP_NUM_THREADS' определенно только на одном узле ('Mother Superior'), т.е. остальные узлы по умолчанию не знают, сколько OpenMP потоков было запрошено.
- Пример программы 'hello_mpi_mp.c' на языке C:
#include <mpi.h> #include <omp.h> #include <stdio.h> #include <unistd.h> int main(int argc, char** argv) { int size, rank; int nthreads, tid; MPI_Status status; char host[32]; int i; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&size); MPI_Comm_rank(MPI_COMM_WORLD,&rank); // Environment variable OMP_NUM_THREADS is defined only on the 'Mother Superior' node. // So we need to send it value to other nodes and apply there. if ( rank == 0 ) { #pragma omp parallel { nthreads = omp_get_num_threads(); } for ( i=1; i<size; i++ ) { MPI_Send(&nthreads,1,MPI_INT,i,0,MPI_COMM_WORLD); } } else { MPI_Recv(&nthreads,1,MPI_INT,MPI_ANY_SOURCE,0,MPI_COMM_WORLD, &status); omp_set_num_threads(nthreads); } gethostname(host,32); #pragma omp parallel private(tid,nthreads) { nthreads = omp_get_num_threads(); tid = omp_get_thread_num(); printf("MPI rank %d from %d, host %s. Thread %d from %d.\n",rank,size,host,tid,nthreads); } MPI_Finalize(); return 0; }
- Выберем реализацию MPI:
mpi-selector --set openmpi_gcc-1.4.3
- Перезапустим SSH сессию.
- Откомпилируем в исполняемый файл hello_mpi_mp:
mpicc -fopenmp -o hello_mpi_mp hello_mpi_mp.c
Также для компиляции можно использовать makefile следующего вида:
hello_mpi_mp : hello_mpi_mp.c mpicc -fopenmp -o $@ hello_mpi_mp.c
- Для постановки задачи в очередь создадим скрипт submit.sh следующего вида:
#!/bin/sh #PBS -l walltime=00:00:20 #PBS -l select=3:ncpus=4:mpiprocs=1:ompthreads=4:mem=2000m cd $PBS_O_WORKDIR MPI_NP=$(wc -l $PBS_NODEFILE | awk '{ print $1 }') mpirun -hostfile $PBS_NODEFILE -np $MPI_NP ./hello_mpi_mp
В данном примере запрашивается 3 раза по 4 ядра и будет запущено 3 MPI-процесса, порождающих по 4 OpenMP потока (по одному потоку на ядро). Ограничение на оперативную память (2000MB) применяется к каждому MPI процессу, а не к отдельному OpenMP потоку.
- Поставим задачу в очередь:
qsub submit.sh
- После завершения задачи получим примерно следующее:
MPI rank 1 from 3, host cn03. Thread 3 from 4. MPI rank 1 from 3, host cn03. Thread 2 from 4. MPI rank 1 from 3, host cn03. Thread 1 from 4. MPI rank 1 from 3, host cn03. Thread 0 from 4. MPI rank 0 from 3, host cn01. Thread 2 from 4. MPI rank 0 from 3, host cn01. Thread 3 from 4. MPI rank 0 from 3, host cn01. Thread 1 from 4. MPI rank 0 from 3, host cn01. Thread 0 from 4. MPI rank 2 from 3, host cn05. Thread 0 from 4. MPI rank 2 from 3, host cn05. Thread 1 from 4. MPI rank 2 from 3, host cn05. Thread 2 from 4. MPI rank 2 from 3, host cn05. Thread 3 from 4.