Введение в использование MPI

  • MPI - аббревиатура 'Message Passing Interface'. Предоставляет интерфейс обмена данными между процессами, в том числе работающими на разных серверах.
  • Использование MPI в программах на языке Python описано на этой странице.
  • На вычислительном комплексе установлено несколько реализаций MPI, каждая включает свой набор библиотек и утилит. Просмотреть их список можно следующей командой:
    mpi-selector --list
  • Основные используемые у нас реализации MPI (каждая имеет несколько версий):
    • intel_mpi - версия от Intel;
    • openmpi_gcc - Open Source версия OpenMPI, собранная компилятором GCC;
    • openmpi_intel - OpenMPI, собранная компилятором от Intel.
  • Возможные параметры утилиты 'mpi-selector' можно узнать, запустив её без параметров, либо следующей командой:
    man mpi-selector


  • Чтобы выбрать определённую реализацию MPI, которая будет использоваться, нужно выполнить команду:
    mpi-selector --set <название>

    :!: Внимание: данная команда повлияет только на те сессии SSH, которые будут открыты после её выполнения. В текущей сессии используемая реализация не изменится, хотя команда

    mpi-selector --query

    будет отображать уже новое значение.

  • После этого для компиляции программ на языке 'C' используется команда mpicc, для языка 'C++' - команды mpicxx, mpiCC или mpic++, для языка 'Fortran' - mpif77 или mpif90. Обратите внимание, что эти команды - не сами компиляторы, а скрипты, вызывающие настоящие компиляторы. Например, даже при выборе реализации MPI от Intel, по умолчанию используются компиляторы GCC. Компилятор при необходимости можно сменить через переменные окружения, более подробное описание для Intel MPI находится на этой странице.


  • :!: Обращаем внимание, что использование 'mpi-selector' накладывает ограничение: каждый пользователь в каждый момент времени может использовать только какую-то одну реализацию MPI. Т.е. с помощью этой утилиты нельзя сделать так, чтобы одни задачи работали с одной реализацией MPI, а другие - с другой реализацией.
  • Создадим файл hello_mpi_world.c, содержащий программу на языке C:
    #include <mpi.h>
    #include <stdio.h>
    #include <unistd.h>
    
    int main(int argc, char** argv)
    {
        int  size, rank;
        char host[32];
    
        MPI_Init(&argc,&argv);
        MPI_Comm_size(MPI_COMM_WORLD,&size);
        MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    
        gethostname(host,32);
        printf("Hello, MPI world! I'm number %d from %d and I run on host %s.\n",rank,size,host);
    
        MPI_Finalize();
        return 0;
    }
  • Процедура MPI_Init инициализирует параллельную часть приложения
  • MPI_Finalize - завершает
  • Все остальные процедуры MPI могут использоваться только между этими двумя вызовами.
  • Процедуры MPI_Comm_size и MPI_Comm_rank возвращают количество параллельных процессов и индивидуальный номер конкретного процесса соответственно.


  • Выберем реализацию MPI:
    mpi-selector --set openmpi_gcc-1.4.3
  • Перезапустим SSH сессию и проверим, какой файл будет использоваться в качестве компилятора:
    which mpicc
    /opt/shared/openmpi/1.4.3-gcc/bin/mpicc
  • Версию компилятора можно узнать с помощью ключа '-v':
    mpicc -v
    gcc version 4.3.2 [gcc-4_3-branch revision 141291] (SUSE Linux)


  • Откомпилируем в исполняемый файл hello_mpi_world.a:
    mpicc hello_mpi_world.c -o hello_mpi_world.a


  • Создадим в той же директории определяющий параметры задачи скрипт submit.sh следующего вида:
    #!/bin/bash
    
    #PBS -l walltime=00:01:00
    #PBS -l select=2:ncpus=4:mpiprocs=4:mem=2000m,place=free
    #PBS -m n
    
    cd $PBS_O_WORKDIR
    
    MPI_NP=$(wc -l $PBS_NODEFILE | awk '{ print $1 }')
    echo "Number of MPI process: $MPI_NP"
    
    echo 'File $PBS_NODEFILE:'
    cat  $PBS_NODEFILE
    echo 
    
    mpirun -hostfile $PBS_NODEFILE -np $MPI_NP ./hello_mpi_world.a
  • Запуск программы производится командой mpirun, которая узнаёт выделенные задаче узлы из файла, на который указывает переменная окружения $PBS_NODEFILE.
  • Для intel_mpi ключ '-hostfile' необходимо заменить на '-machinefile'
  • :!: Если каждый MPI-процесс способен загрузить на 100% только одно процессорное ядро (т.е. не используется ещё какой-то способ распараллеливания, например, OpenMP), значения ncpus и mpiprocs в select должны совпадать.
  • :!: Некоторые реализации MPI запускают некорректное количество MPI-процессов, если не указать его команде 'mpirun' с помощью параметра '-np'
  • :!: Одна из самых распространённых у нас ошибок при использовании MPI заключается в указании разного количества потоков в select и в mpirun. В результате или часть процессорных ядер простаивает или наоборот, задача пытается использовать больше ядер, чем было запрошено. Поэтому настоятельно рекомендуется не указывать mpirun количество потоков в виде числа ('-np 8'), а делать так, как в примере выше - вычислять количество потоков на основании созданного планировщиком файла '$PBS_NODEFILE' и передавать это значение mpirun. При таком подходе будет достаточно изменять параметры 'select', а mpirun автоматически будет получать корректное значение количества потоков.


  • Командой qsub поставим задачу в очередь:
    qsub submit.sh
    13485.hpc-suvir1.hpc

    '13485' - идентификатор нашей задачи.


  • После завершения работы задачи в текущей директории появлятся файлы submit.sh.e13485 (должен быть нулевого размера, если программа отработала без ошибок) и submit.sh.o13485, содержащий примерно следущее:
    Number of MPI process: 8
    File $PBS_NODEFILE:
    cn04
    cn04
    cn04
    cn04
    cn39
    cn39
    cn39
    cn39
    
    Hello, MPI world! I'm number 1 from 8 and I run on host cn04.
    Hello, MPI world! I'm number 0 from 8 and I run on host cn04.
    Hello, MPI world! I'm number 3 from 8 and I run on host cn04.
    Hello, MPI world! I'm number 5 from 8 and I run on host cn39.
    Hello, MPI world! I'm number 6 from 8 and I run on host cn39.
    Hello, MPI world! I'm number 7 from 8 and I run on host cn39.
    Hello, MPI world! I'm number 2 from 8 and I run on host cn04.
    Hello, MPI world! I'm number 4 from 8 and I run on host cn39.