MPICH2 Hydra进程管理框架分析

        MPICH2是由Argonne国家实验室维护的开源MPI库,是高性能计算领域使用最为广泛的MPI库之一。本文主要对其中Hydra进程管理框架进行了简要分析,希望可以为相关领域的学者提供帮助。在阅读本文前,读者可以首先参考其官方介绍:http://wiki.mpich.org/mpich/index.php/Hydra_Process_Management_Framework

        Hydra构建了进程管理框架,MPI进程需要经常与该框架进行交互,其交互的语言就是PMI标准,即进程管理接口(Process Management Interface)。因此要全面掌握该框架需要同时了解Hydra和客户端MPI进程两个部分,下面将分别从两个部分展开分析。需要注意的是,文中涉及的内容均以发稿前最新的mpich3.1为准,且使用PMI-1接口。

1. Hydra 进程管理框架

        下图是mpich wiki给出的Hydra结构图:

        从进程拓扑上看,Hydra由一个运行在服务器上的作业加载程序JLE(Job Launching Executable)和多个运行在不同计算节点上的进程管理代理PMP(Process Manager Proxy)组成。之所以称为PMP是因为它基本上具备了PM(Proxy Manager)的所有功能,代理PM并运行在计算节点上负责具体维护本节点上所有进程的状态。换言之,包括MPI进程在内系统进程拓扑是一个倒树状结构,JLE处于树根,负责在各计算节点上创建进程PMP;PMP在本节点上创建一个或多个MPI进程。JLE对应的执行程序就是我们经常使用的作业加载程序mpiexec.hydra;PMP为hydra_pmi_proxy。

        在介绍进程拓扑结构后,我们来看看上图中主要功能模块的作用,按照自底向上的顺序:

      1、I/O Demux Engine

        Demux的字面意思是“解复用器”。顾名思义,Demux 本质上一个消息管理系统,可以监听多个文件描述符的状态,当文件描述符接收到消息后,回调注册的处理函数。

Demux相关的代码位于src\pm\hydra\tools\demux目录下;其主要函数如下所示:

        1)HYDT_dmx_init:根据用户选项指定wait_for_event为HYDT_dmxu_poll_wait_for_event或HYDT_dmxu_select_wait_for_event。

        2) HYDT_dmx_register_fd(int num_fds, int *fd, HYD_event_t events, void *userp, HYD_status(*callback) (int fd, HYD_event_t events, void *userp)):注册描述符处理函数,根据描述符数量“num_fds”,描述符队列指针“fd”,事件类型“events”,回调函数“callback”,将处理函数添加进HYDT_dmxu_cb_list。
        3) HYDT_dmx_deregister_fd:注销函数。
        4) HYDT_dmx_wait_for_event:等待事件并调用事件处理函数,可以为HYDT_dmxu_poll_wait_for_event或HYDT_dmxu_select_wait_for_event。
        5) HYDT_dmx_query_fd_registration:查询指定描述符是否已经被注册。
        6) HYDT_dmx_finalize:结束函数,释放HYDT_dmxu_cb_list结构。
        7) HYDT_dmxi_stdin_valid:检查输入是否有效,使用read函数并设置长度为0判断函数返回值是否为0。
        8) HYDT_dmx_stdin_valid:获得输入有效标志。

      2、Bootstrap

        BSCI-BootStrap Control Interface,即引导控制接口,负责程序的加载和状态的维护,该模块定义在hydra\tools\bootstrap目录下。主要包含两个数据结构:struct HYDT_bsci_info 定义主要状态信息;struct HYDT_bsci_fns 定义主要核心函数,这里主要介绍其中有关启动作业的函数

        HYD_status(*launch_procs) (char **args, struct HYD_proxy * proxy_list, int *control_fd);

        在我们的实验平台中默认使用ssh启动进程,其launsh回调函数指定为HYDT_bscd_common_launch_procs。该函数的主要功能是准备待运行程序的参数,如果发现目标机器为本地节点,则通过fork启动进程;否则通过ssh远程启动进程。两种方式的启动过程均是调用函数HYDU_create_process,差别在于传递该函数的参数不同。例如,在本地创建进程时,参数为:

        ./examples/hellow  

即直接传递MPI程序名称,直接通过fork创建子进程执行程序;

在远程创建进程时,参数为:

         /home/wgb/mpich-3.1/install/bin/hydra_pmi_proxy --control-port server:50687 --rmk user --launcher ssh --demux poll --pgid 0 --retries 10 --usize -2 --proxy-id 1

即通过ssh在远程创建进程管理代理hydra_pmi_proxy,参数为本地地址/端口等信息;待执行MPI程序的信息将在后续通知PMP。

        BootStrap向外提供下列API接口,可以看出所有函数名均以HYDT_bsci开头:

1)HYD_status HYDT_bsci_init(const char *rmk, const char *launcher, const char *launcher_exec, int enablex, int debug);

2)HYD_status HYDT_bsci_launch_procs(char **args, struct HYD_proxy *proxy_list, int *control_fd);
3)HYD_status HYDT_bsci_finalize(void);
4)HYD_status HYDT_bsci_wait_for_completion(int timeout);
5)HYD_status HYDT_bsci_query_node_list(struct HYD_node **node_list);
6)HYD_status HYDT_bsci_query_proxy_id(int *proxy_id);
7)HYD_status HYDT_bsci_query_native_int(int *ret);

8)HYD_status HYDT_bsci_launcher_XXX_init(void);

      3、Process Binding

        用于进程与CPU或Memory绑定的模块,貌似是使用Open MPI的hwloc(Portable Hardware Locality)子模块实现的。

      4、PM和PMP

        PM和PMP完成进程管理的相关功能,PMP执行在计算节点上,完成JLE和MPI进程间的“上传下达”功能。PMP维护了上行通路(upstream)和下行通路(downstream),分别连接了JLE进程和MPI进程。在完成相关初始化后,PMP通过Demux模块等待来自JLE进程和MPI进程的消息。PMP和PM的主要逻辑和数据结构相似。其中enum HYD_pmcd_cmd是两者共用的核心数据结构之一,定义了进程管理需要处理的所有消息类型。

enum HYD_pmcd_cmd {

        INVALID_CMD = 0,        /* for sanity testing */

        /* UI to proxy commands */

        PROC_INFO,  CKPOINT, PMI_RESPONSE,  SIGNAL, STDIN,

        /* Proxy to UI commands */

        PID_LIST,  EXIT_STATUS, PMI_CMD,  STDOUT, STDERR, PROCESS_TERMINATED

    } cmd;

          如注释所示,PROC_INFO至STDIN为JLE向PMP发送的消息类型;PID_LIST至PROCESS_TERMINATED为PMP向JLE发送的消息类型。

         PMP的消息处理函数为HYD_pmcd_pmip_control_cmd_cb(pmip_cb.c):

        PROC_INFO:完成application进程创建过程。首先为应用进程配置环境变量等准备工作,而后调用HYDU_create_process创建进程。

        CKPOINT:检查点功能。

        PMI_RESPONSE:处理来自服务器端的请求或相应,根据消息类型调用HYD_pmcd_pmip_pmi_handle中的回调函数,回调函数列表定义在pmi_v1_handle_fns_foo(pmip_pmi_v1.c)中。

        SIGNAL:向application进程发送进行killpg或kill。

        STDIN:转发来自服务器端的输入数据到MPI进程。

        JLE的消息处理函数为control_cb(pmiserv_cb.c)。

        PID_LIST:接受并保存PMP发送的MPI进程号列表

        EXIT_STATUS:保存MPI进程的退出状态,并清理PMP

        PMI_CMD:调用handle_pmi_cmd处理各类消息,回调函数列表定义在pmi_v1_handle_fns_foo。

        STDOUT、STDERR:处理标准输出流和错误流

        PROCESS_TERMINATED:处理MPI进程退出

      5、User Interface

        UI定义了mpiexec.hydra的入口函数,其所有代码定义在hydra/ui目录下。

2. MPICH PMI接口及其实现

        MPI应用程序通过PMI接口与PMP交互,PMI-1的接口实现均定义在src/pmi/simple目录下。下面简要介绍其中的主要函数:

PMI_Init:初始化PMI相关变量,例如,PMI_fd,PMI_rank等,PMI_fd用于与PMP通信的描述符,PMI_rank即为MPI进程的rank。

PMI_Get_appnum:获得App序号,从0开始。

PMI_Barrier:同步操作,直至等到JLE返回"barrier_out"消息为止。

PMI_KVS_Get_my_name:从JLB获得进程组标识。

PMI_KVS_Put:发布键-值对。

PMI_KVS_Get:获得键相应的值。

3.PMI交互过程实例

        我们一个MPI的发送过程介绍MPI进程通过PMI与PMP和JLB的交互过程。
        实验平台有两个节点一个是服务节点server,一个是计算节点cn0。测试程序会在cn0上派生一个进程P0;在server派生两个进程P1和P2,P0会分别向P1和P2发送一条消息。
        1、MPI进程会向PMP请求进程组标识,格式如下:
              cmd= get_my_kvsname
        2、PMP将返回进程组标识:
              cmd= my_kvsname kvsname= kvs_53934_0// kvs_53934_0是PMIServer设置的进程组的标识,也可以认为是该作业的标识
        3、MPI进程以上述标识为头继续后续操作,之后询问进程映射关系:
              cmd= get kvsname= kvs_53934_0 key= PMI_process_mapping
        4、MPIProxy返回进程映射关系:
              content:cmd= get_result rc= 0msg= success value= (vector,(0,1,1),(1,1,2))
        5、MPI进程会主动向PMP报告进程地址,以P1为例:
               kvsname= kvs_53934_0 key= P1-businesscard value= description#server$port#42070$ifname#192.168.43.10$
        6、PMP负责将本节点所有进程的地址上传到JLE:
              cmd= put P2-businesscard=description#server$port#45975$ifname#192.168.43.10$ P1-businesscard=description#server$port#42070$ifname#192.168.43.10$
        7、这样JLE可以获得所有进程的地址信息,然后再向下广播这些信息,以便各节点进程可以获得其他节点进程的地址:
              cmd= keyval_cache P0-businesscard=description#cn0$port#45884$ifname#192.168.43.20$ P2-businesscard=description#server$port#45975$ifname#192.168.43.10$ P1-businesscard=description#server$port#42070$ifname#192.168.43.10$ 
        8、当MPI进程需要进行通信操作前,会请求本节点的PMP目标进程的地址,以P0->P1为例,P0会发出如下消息:
              cmd= get kvsname= kvs_53934_0key= P1-businesscard
        9、PMP返回结果:

              cmd=get_resultrc=0 msg=success value=description#server$port#42070$ifname#192.168.43.10$

        这样P0获得了P1的机器名(server)和端口号(42070)和IP地址(192.168.43.10),可以启动发送过程。





  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wgbljl

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值