Тест MPI на кластере - PullRequest
       66

Тест MPI на кластере

4 голосов
/ 31 января 2010

Я изучаю OpenMPI на кластере. Вот мой первый пример. Я ожидаю, что выходные данные будут показывать ответ от разных узлов, но все они отвечают от одного узла node062. Мне просто интересно, почему и как я могу получить отчет от разных узлов, чтобы показать, что MPI фактически распределяет процессы по разным узлам? Спасибо и всего наилучшего!

ex1.c

/* test of MPI */  
#include "mpi.h"  
#include <stdio.h>  
#include <string.h>  

int main(int argc, char **argv)  
{  
char idstr[2232]; char buff[22128];  
char processor_name[MPI_MAX_PROCESSOR_NAME];  
int numprocs; int myid; int i; int namelen;  
MPI_Status stat;  

MPI_Init(&argc,&argv);  
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);  
MPI_Comm_rank(MPI_COMM_WORLD,&myid);  
MPI_Get_processor_name(processor_name, &namelen);  

if(myid == 0)  
{  
  printf("WE have %d processors\n", numprocs);  
  for(i=1;i<numprocs;i++)  
  {  
    sprintf(buff, "Hello %d", i);  
    MPI_Send(buff, 128, MPI_CHAR, i, 0, MPI_COMM_WORLD); }  
    for(i=1;i<numprocs;i++)  
    {  
      MPI_Recv(buff, 128, MPI_CHAR, i, 0, MPI_COMM_WORLD, &stat);  
      printf("%s\n", buff);  
    }  
}  
else  
{   
  MPI_Recv(buff, 128, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &stat);  
  sprintf(idstr, " Processor %d at node %s ", myid, processor_name);  
  strcat(buff, idstr);  
  strcat(buff, "reporting for duty\n");  
  MPI_Send(buff, 128, MPI_CHAR, 0, 0, MPI_COMM_WORLD);  
}  
MPI_Finalize();  

}  

ex1.pbs

#!/bin/sh  
#  
#This is an example script example.sh  
#  
#These commands set up the Grid Environment for your job:  
#PBS -N ex1  
#PBS -l nodes=10:ppn=1,walltime=1:10:00  
#PBS -q dque    

# export OMP_NUM_THREADS=4  

 mpirun -np 10 /home/tim/courses/MPI/examples/ex1  

скомпилируйте и запустите:

[tim@user1 examples]$ mpicc ./ex1.c -o ex1   
[tim@user1 examples]$ qsub ex1.pbs  
35540.mgt  
[tim@user1 examples]$ nano ex1.o35540  
----------------------------------------  
Begin PBS Prologue Sat Jan 30 21:28:03 EST 2010 1264904883  
Job ID:         35540.mgt  
Username:       tim  
Group:          Brown  
Nodes:          node062 node063 node169 node170 node171 node172 node174 node175  
node176 node177  
End PBS Prologue Sat Jan 30 21:28:03 EST 2010 1264904883  
----------------------------------------  
WE have 10 processors  
Hello 1 Processor 1 at node node062 reporting for duty  
Hello 2 Processor 2 at node node062 reporting for duty        
Hello 3 Processor 3 at node node062 reporting for duty        
Hello 4 Processor 4 at node node062 reporting for duty        
Hello 5 Processor 5 at node node062 reporting for duty        
Hello 6 Processor 6 at node node062 reporting for duty        
Hello 7 Processor 7 at node node062 reporting for duty        
Hello 8 Processor 8 at node node062 reporting for duty        
Hello 9 Processor 9 at node node062 reporting for duty  

----------------------------------------  
Begin PBS Epilogue Sat Jan 30 21:28:11 EST 2010 1264904891  
Job ID:         35540.mgt  
Username:       tim  
Group:          Brown  
Job Name:       ex1  
Session:        15533  
Limits:         neednodes=10:ppn=1,nodes=10:ppn=1,walltime=01:10:00  
Resources:      cput=00:00:00,mem=420kb,vmem=8216kb,walltime=00:00:03  
Queue:          dque  
Account:  
Nodes:  node062 node063 node169 node170 node171 node172 node174 node175 node176  
node177  
Killing leftovers...  

End PBS Epilogue Sat Jan 30 21:28:11 EST 2010 1264904891  
----------------------------------------

UPDATE:

Я хотел бы запустить несколько фоновых заданий в одном скрипте PBS, чтобы задания могли выполняться одновременно. например в приведенном выше примере я добавил еще один вызов для запуска ex1 и изменил оба запуска на фоновый в ex1.pbs

#!/bin/sh  
#  
#This is an example script example.sh  
#  
#These commands set up the Grid Environment for your job:  
#PBS -N ex1  
#PBS -l nodes=10:ppn=1,walltime=1:10:00  
#PBS -q dque 

echo "The first job starts!"  
mpirun -np 5 --machinefile /home/tim/courses/MPI/examples/machinefile /home/tim/courses/MPI/examples/ex1 &  
echo "The first job ends!"  
echo "The second job starts!"  
mpirun -np 5 --machinefile /home/tim/courses/MPI/examples/machinefile /home/tim/courses/MPI/examples/ex1 &  
echo "The second job ends!" 

(1) Результат будет хорошим после qsub этого скрипта с предыдущим скомпилированным исполняемым файлом ex1.

The first job starts!  
The first job ends!  
The second job starts!  
The second job ends!  
WE have 5 processors  
WE have 5 processors  
Hello 1 Processor 1 at node node063 reporting for duty        
Hello 2 Processor 2 at node node169 reporting for duty        
Hello 3 Processor 3 at node node170 reporting for duty        
Hello 1 Processor 1 at node node063 reporting for duty        
Hello 4 Processor 4 at node node171 reporting for duty        
Hello 2 Processor 2 at node node169 reporting for duty        
Hello 3 Processor 3 at node node170 reporting for duty        
Hello 4 Processor 4 at node node171 reporting for duty  

(2) Тем не менее, я думаю, что время выполнения ex1 слишком короткое, и, вероятно, у двух фоновых заданий не слишком много времени наложения, что не так, когда я применяю то же самое к моему реальному проекту. Поэтому я добавил sleep (30) в ex1.c, чтобы продлить время выполнения ex1, чтобы два задания, выполняющие ex1 в фоновом режиме, выполнялись одновременно почти все время.

/* test of MPI */  
#include "mpi.h"  
#include <stdio.h>  
#include <string.h>  
#include <unistd.h>

int main(int argc, char **argv)  
{  
char idstr[2232]; char buff[22128];  
char processor_name[MPI_MAX_PROCESSOR_NAME];  
int numprocs; int myid; int i; int namelen;  
MPI_Status stat;  

MPI_Init(&argc,&argv);  
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);  
MPI_Comm_rank(MPI_COMM_WORLD,&myid);  
MPI_Get_processor_name(processor_name, &namelen);  

if(myid == 0)  
{  
  printf("WE have %d processors\n", numprocs);  
  for(i=1;i<numprocs;i++)  
  {  
    sprintf(buff, "Hello %d", i);  
    MPI_Send(buff, 128, MPI_CHAR, i, 0, MPI_COMM_WORLD); }  
    for(i=1;i<numprocs;i++)  
    {  
      MPI_Recv(buff, 128, MPI_CHAR, i, 0, MPI_COMM_WORLD, &stat);  
      printf("%s\n", buff);  
    }  
}  
else  
{   
  MPI_Recv(buff, 128, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &stat);  
  sprintf(idstr, " Processor %d at node %s ", myid, processor_name);  
  strcat(buff, idstr);  
  strcat(buff, "reporting for duty\n");  
  MPI_Send(buff, 128, MPI_CHAR, 0, 0, MPI_COMM_WORLD);  
}  

sleep(30); // new added to extend the running time
MPI_Finalize();  

}  

Но после перекомпиляции и снова qsub результаты, похоже, не все в порядке. Есть процессы прерваны. в ex1.o35571:

The first job starts!  
The first job ends!  
The second job starts!  
The second job ends!  
WE have 5 processors  
WE have 5 processors  
Hello 1 Processor 1 at node node063 reporting for duty  
Hello 2 Processor 2 at node node169 reporting for duty  
Hello 3 Processor 3 at node node170 reporting for duty  
Hello 4 Processor 4 at node node171 reporting for duty  
Hello 1 Processor 1 at node node063 reporting for duty  
Hello 2 Processor 2 at node node169 reporting for duty  
Hello 3 Processor 3 at node node170 reporting for duty  
Hello 4 Processor 4 at node node171 reporting for duty  
4 additional processes aborted (not shown)  
4 additional processes aborted (not shown)  

в ex1.e35571:

mpirun: killing job...  
mpirun noticed that job rank 0 with PID 25376 on node node062 exited on signal 15 (Terminated).  
mpirun: killing job...  
mpirun noticed that job rank 0 with PID 25377 on node node062 exited on signal 15 (Terminated).  

Интересно, почему процессы прерываются? Как правильно выполнить qsub фоновые задания в сценарии PBS?

Ответы [ 4 ]

3 голосов
/ 31 января 2010

пара вещей: вам нужно указать mpi, где запускать процессы, предполагая, что вы используете mpich, посмотрите раздел справки mpiexec и найдите машинный файл или эквивалентное описание. Если машинный файл не предоставлен, он будет работать на одном хосте

PBS автоматически создает файл узлов. Его имя хранится в переменной среды PBS_NODEFILE, доступной в командном файле PBS. Попробуйте следующее:

mpiexec -machinefile $PBS_NODEFILE ...

если вы используете mpich2, у вас есть две загрузки вашей среды исполнения mpi с использованием mpdboot. Я не помню подробности команды, вам придется прочитать справочную страницу. Не забудьте создать секретный файл, иначе mpdboot потерпит неудачу.

Я прочитал ваш пост еще раз, вы будете использовать открытый mpi, вам все равно придется указывать файл машины для команды mpiexec, но вам не нужно связываться с mpdboot

2 голосов
/ 31 января 2010

По умолчанию PBS (я предполагаю, крутящий момент) распределяет узлы в монопольном режиме, так что только одно задание на узел. Это немного отличается, если у вас есть несколько процессоров, скорее всего один процесс на процессор. PBS может быть изменен для распределения узлов в режиме с разделением времени, посмотрите на man-страницу краткого рассказа qmgr.long, скорее всего, у вас не будет перекрывающихся узлов в файле узлов, поскольку файл узлов создается, когда ресурсы доступны, а не во представление.

Целью PBS является управление ресурсами, чаще всего время, распределение узлов (автоматическое).

команды в файле PBS выполняются последовательно. Вы можете поместить процессы в фоновый режим, но это может нанести ущерб цели распределения ресурсов, но я не знаю, какой именно у вас рабочий процесс. Я использовал фоновые процессы в сценариях PBS для копирования данных до параллельного запуска основной программы, используя &. Сценарий PBS на самом деле является просто сценарием оболочки.

Вы можете предположить, что PBS ничего не знает о внутренней работе вашего скрипта. Конечно, вы можете запускать несколько процессов / потоков в скрипте via.Если вы это сделаете, это зависит от вас и вашей операционной системы, чтобы распределять ядра / процессоры сбалансированным образом. Если вы работаете в многопоточной программе, наиболее вероятный подход - запустить один процесс mpi для узла, а затем запустить потоки OpenMP.

Дайте мне знать, если вам нужны разъяснения

1 голос
/ 31 января 2010

В качестве диагностики попробуйте вставить эти операторы сразу после вызова MPI_GET_PROCESSOR_NAME.

printf("Hello, world.  I am %d of %d on %s\n", myid, numprocs, name);
fflush(stdout); 

Если все процессы возвращают один и тот же идентификатор узла, я бы сказал, что вы не совсем понимаете, что происходит в системе управления заданиями и кластере - возможно, это PBS (несмотря на то, что вы, очевидно, говорите это иначе) размещение всех 10 процессов на одном узле (у вас есть 10 ядер в узле?).

Если это приводит к другим результатам, это наводит меня на мысль о том, что с вашим кодом что-то не так, хотя для меня это нормально.

0 голосов
/ 13 марта 2011

В вашем коде есть ошибка, не связанная с mpich, вы повторно использовали i в своих двух циклах.

for(i=1;i<numprocs;i++)  
  {  
    sprintf(buff, "Hello %d", i);  
    MPI_Send(buff, 128, MPI_CHAR, i, 0, MPI_COMM_WORLD); }  
    for(i=1;i<numprocs;i++)  

Второй цикл for все испортит.

...