代码之家  ›  专栏  ›  技术社区  ›  Tim unnamed eng

在群集上测试MPI

  •  4
  • Tim unnamed eng  · 技术社区  · 15 年前

    我正在集群上学习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  
    ----------------------------------------
    

    更新:

    我想在一个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)将此脚本与以前编译的可执行文件ex1进行qsub后,结果良好。

    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的运行时间太快了,可能两个后台作业没有太多的运行时间重叠,这不是我用同样的方式应用到实际项目中的情况。所以我在ex1.c中添加了sleep(30),以延长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.O3551:

    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).  
    

    我想知道为什么有进程被中止?如何在PBS脚本中正确地进行qsub后台作业?

    4 回复  |  直到 12 年前
        1
  •  3
  •   Anycorn    15 年前

    两件事: 您需要告诉MPI在哪里启动进程, 假设您使用的是MPICH,请查看mpiexec帮助部分并查找计算机文件或等效描述。除非提供了计算机文件,否则它将在一台主机上运行

    PBS自动创建节点文件。它的名称存储在PBS命令文件中提供的PBS节点文件环境变量中。尝试以下操作:

    mpiexec -machinefile $PBS_NODEFILE ...
    

    如果您使用的是MPICH2,那么您有两个使用MPDBOOT引导MPI运行时。我不记得命令的细节,你将不得不阅读手册页。记住创建机密文件,否则mpdboot将失败。

    我又看了你的帖子,你会用open-mpi,你还是要提供机器文件到mpiexec命令,但你不必乱用mpdboot。

        2
  •  2
  •   Anycorn    15 年前

    默认情况下,PBS(我假设Torque)以独占模式分配节点,这样每个节点只有一个作业。如果您有多个处理器,这有点不同,很可能每个CPU有一个进程。PBS可以更改为在分时模式下分配节点,请查看qmgr.long story short的手册页,很可能节点文件中没有重叠的节点,因为节点文件是在资源可用时创建的,而不是在提交时创建的。

    PBS的目的是资源控制,最常见的是时间,节点分配(自动)。

    PBS文件中的命令按顺序执行。您可以将进程置于后台,但这可能会破坏资源分配的目的,但我不知道您的确切工作流。我使用pbs脚本中的后台进程在主程序并行运行之前复制数据,使用&。PBS脚本实际上只是一个shell脚本。

    您可以假设PBS对脚本的内部工作一无所知。您当然可以在via脚本中运行多个进程/线程。如果这样做,则由您和您的操作系统以平衡的方式分配核心/处理器。如果您使用的是多线程程序,最有可能的方法是为节点运行一个MPI进程,然后生成OpenMP线程。

    如果你需要澄清请告诉我

        3
  •  1
  •   user229044    12 年前

    作为诊断,请尝试在调用mpi_get_processor_name后立即插入这些语句。

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

    如果所有进程都返回相同的节点ID,那么它会建议我您不太了解作业管理系统和集群上的情况——也许PBS(尽管您显然告诉它其他情况)将所有10个进程放在一个节点上(您在一个节点中有10个核心吗?).

    如果这会产生不同的结果,这就意味着你的代码有问题,尽管对我来说没问题。

        4
  •  0
  •   Martlark    14 年前

    您的代码中有一个与MPICH无关的bug,您已经在两个循环中重用了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循环将把事情搞砸。

    推荐文章