Open MPI的目标、概念及实现

  目前,许多可用的MPI实现只关注HPC(高性能计算)的部分方面或是专注于解决某个具体问题,这导致了这些MPI实现不兼容、如果独立安装组合来获取它们的特有功能。Open MPI是在LAM/MPI,LA-MPI, and FT-MPI的基础上的一种全新的基于构件概念的MPI实现,提供了以前MPI实现无法实现的独特的组合方法。Open MPI的基于构件的体系结构不仅为第三方研究提供了稳定的平台,也使得独立软件附件能够在运行时组合。本文从总体上介绍了Open MPI的目标、概念、设计及实现。

一、Open MPI的目标
  Open MPI并不是LAM/MPI, LA-MPI和FT-MPI的简单组合,而是一种全新的MPI实现,其完全实现了MPI-1.2和MPI-2规约,并且完全支持并发和多线程应用(也就是MPI_THREAD_MULTIPLE)。
  为了有效有效支持大范围的并行机,开发了高性能驱动程序,其中包括TCP/IP, shared memory, Myrinet, Quadrics, and Infiniband,更多的机器支持可能会基于用户、市场和研究需要而增加。对于网络传输错误,Open MPI提供了一种可选的特性来检测数据的完整性。通过使用报文分段和拆分到多个网络设计,Open MPI不仅可以达到可用带宽的最大值,而且当节点使用多台网络设备的时候,可以动态处理网络设备的数据丢失。
  Open MPI的运行时环境提供了启动和管理并行应用的基本服务。

二、Open MPI的体系结构
  Open MPI的设计以MPI构件架构(MPI Component Architecture, MCA)为中心。虽然构件编程已被工业界广泛应用,但在HPC领域中应用却没有很长时间。Open MPI由三个主要的功能域组成,如图1所示。

 

 

 

图1 Open MPI体系结构

  • MPI构件架构(MPI Component Architecture, MCA),是Open MPI的核心,为所有其它层次提供管理服务的基础组件结构;
  • 构件框架(Component frameworks),存在于每个主要的功能域中,以管理模块;
  • 模块(Modules),是自包含的软件单元,带有已定义好的接口,可以在运行时和其它模块进行配置组合。

  MCA管理构件框架并为它们提供服务,如接收高层抽象的运行时参数,并通过构件框架向下传递到模块。MCA也能寻找构造时的构件,并调用相关的hooks以配置、构造和安装这些构件。

  每个构件框架致力于单独的任务,例如提供并行任务控制或执行MPI集合操作。一旦需要,构件框架会发现、加载、使用、卸载模块。每个构件框架有不同的机制和使用场景,有些在一个时刻只用一个模块,而有些会同时用到所有模块。
  模块是自我包含的软件单位,可以自我配置、自我构造和自我安装。模块包含在构件框架中,以接口的形式为高层抽象或MPI的其它部分提供需要的服务。

  下面是Open MPI构件框架的部分列表(包含MPI功能,不包含运行时环境构件):

  • 点到点传递层(Point-to-point Transport Layer, PTL):一个PTL模块相当于一个专用的网络协议和设备,主要负责MPI进程间字节传递的“有线协议”。PTL模块需要识别MPI的语义,多个PTL模块可以在一个进程中使用,同时允许多个网络的使用。PTL模块支持TCP/IP, shared memory, Quadrics elan4, Infiniband和Myrinet。
  • 点到点管理层(Point-to-point Management Layer, PML):PML的主要功能是为MPI层和所有可用的PTL模块之间提供报文分段、调度和重新装配服务。
  • 聚合通信(Collective Communication, COLL):是MPI聚合操作的后端,支持组内通信域和组间通信域间功能。
  • 进程拓扑(Process Topology, TOPO):提供组内通信夫域的笛卡尔和图的映射功能。基于集群和风格的计算可能受益于此拓扑意识的通信域,允许MPI基于位置来优化通信域。
  • 约简操作(Reduction Operations):MPI固有的约简操作的后端功能(例如MPI_SUM)。模块可以利用平台专用的指令集来优化在目标平台上的性能。
  • 并行IO(Parallel I/O):IO模块实现并行文件和设备的存取。

  Open MPI框架类型的多样性使得第三方开发者可以使用Open MPI作为一个研究平台、一个商业产品的开发工具、甚至是不同算法和技术的比较机制。
  Open MPI的构件架构为终端用户和库开发者提供了许多优势:1)它允许一个MPI进程内使用多个构件。例如,一个进程可以同时使用多个网络设备驱动;2)为第三方软件的使用提供了方便,支持源码和二进制版本;3)提供了细粒度的、运行时、用户可控的构件选择机制。

2.1模块生命周期
  虽然每个框架是不同的,但我们可以用MPI进程中的COLL框架为示例来说明模块的使用和生命周期:
  1)在MPI_INIT阶段,COLL框架寻找所有可用的模块。模块可能是静态链接到MPI库,或是在已知位置共享的库模块。
  2)所有的COLL模块被询问它们是否需要在进程中运行,模块可以选择不运行。例如,一个基于Infiniband的模块,如果没有可用的Infiniband NICs可以选择不运行。所有选择运行的模块将会组成一个可运行的模块清单。
  3)当每个通信域(包括MPI_COMM_WORLD和MPI_COMM_SELF)被创建时,每个可用模块被询问是否需要在新通信域中使用。模块可以拒绝被使用,例如,一个基于共享内存的模块只有当通信域中的所有进程都在相同的物理节点上时,才允许被使用。通信域将会选择最高优先级的模块使用。
  4)一旦模块被选中,将会被初始化。给模块分配资源,当聚合操作被调用时,其潜在的预计算信息将会被使用。
  5)当MPI的聚合操作在那个通信域被调用,这个模块相关的后端功能被调用去执行这个操作。
6)COLL模块生命周期的最后阶段发生在通信域被销毁的时候,主要是释放资源和与通信域关联的预计算信息。

三、实现细节
  主要讨论Open MPI设计的两个方面:它的面向对象方法和模块管理机制。

3.1面向对象方法
  Open MPI使用简单C语言面向对象系统实现,使用基于单一继承和引用计数的retain/release内存管理模型。一个object由一个结构体和单一实例化的class标识符组成。结构体的首个元素一个是指定父类结构体的指针。
  宏指令会对C++类似的语义(如new, construct, destruct, delete)产生影响。因为C++项目的丰富经验和某些平台编译方面的问题,使得在开发Open MPI使用了面向对象方法,而不是直接使用C++。
  一旦构造,对象引用计数被设置为1。当对象retain,计数递增,当对象release,计数递减。当计数到达0,会运行对象的析构器并释放内存。
3.2模块发觉和管理
  Open MPI提供了三种不同机制,将模块添加到MPI库中:

  • 在Open MPI配置阶段,一个脚本会遍历构造树,并生成一个模块发觉列表。这些模块会被配置、编译并静态链接到MPI库中。
  • 与上面方法类似,在配置阶段发觉的模块也可以被编译成共享库,并安装、在运行时被重新发觉。
  • 对于不想提供源代码和第三方库开发者,可以独自配置和编译他们的模块并以二进制的形式生成共享库。用户可以安装这些模块到合适的目录下,以便Open MPI可以在运行时发觉这些模块。

  在运行时,Open MPI首先发觉静态链接到MPI库的所有模块,然后搜索多个目录(如$HOME/ompi/, ${INSTALLDIR}/lib/ompi/),找到所有可用的模块,并按照框架类型排序。为了简化运行时发觉,共享库模块有其专用的命名制式来指定它们的MCA构件框架类型和它们的模块名。

  模块通过它们的名字和版本号指定。这使得MCA可以管理相同构件的不同版本,也确保在一个MPI进程中使用的模块是相同的,即名字和版本号都一致。为了提高灵活性,Open MPI提供了多种机制来选择指定模块,或传递运行时参数到模块,或传递命令行参数到mpirun、环境变量、文本文件和MPI属性。

四、总结
  Open MPI是MPI的一种全新实现,支持MPI-2、多个并发用户线程、处理进程和网络故障的多种选择等。

五、参考资料

[1]. Gabriel, E., et al., Open MPI: Goals, concept, and design of a next generation MPI implementation. Recent Advances in Parallel Virtual Machine and Message Passing Interface, 2004: p. 353-377.

posted @ 2012-03-04 16:08 程序员姜小白 阅读(...) 评论(...) 编辑 收藏