一种基于双网卡的通信方法 【技术领域】
本发明涉及计算机通信的方法,特别是涉及一种基于Myrinet技术的双网卡通讯的方法。
背景技术
Myrinet是美国Myricom公司设计的一个高性能局域网,由于它具有高带宽、低延迟以及很低的开销,所以非常适合机群系统的通信网络。
Myrinet由网络接口、网络链路和交换器组成。Myrinet交换器采用Cut-through寻径策略,多个交换器组合可构成复杂拓扑结构的互联网络。Myrinet网络接口包括一块称为LANai的可编程控制器、两个DMA引擎和一块静态内存区域SRAM。其中LANai通过执行驻留在其中的网卡控制程序MCP,控制DMA引擎来处理消息收发以及和主机、网络的数据交换。SRAM用于缓存消息数据、存储网卡控制程序。用户可以根据需要灵活设计控制程序以满足特定需求。
图1是Myrinet网络硬件结构和数据通信流图。数据在首先通过DMA方式从用户内存区域(主存)经PCI总线传送到网卡内存区域(SRAM)缓存,此后再由网卡启动DMA引擎将缓存的数据发送到网络上,在接收方进行的数据传送过程则相反。
GM(Glenn’s Message)协议是Myricom公司设计的适用于Myrinet网络的用户态通信协议,它可以为上层通信系统或用户应用程序提供高性能、高可靠的通信服务。GM的设计思想就是要实现一种高带宽、低延迟、主机开销极少的通信方式。GM的高效率除了采用用户层通信机制以外,关键在于充分配合Myrinet在硬件架构上的特性。GM在Myrinet网卡的LANai芯片上运行MCP,承担了大部分的通信处理工作,大大减轻了主机的通信开销。总地来说,GM具有如下特点:
在所有体系结构上,每个数据包只消耗主机大约1μs的处理时间;
可在不可靠网络环境中提供可靠、有序的数据传输服务;
提供高低两种通信优先级以避免通信死锁;
支持超过10000个节点的机群系统;
理论上支持的消息长度可达231-1字节,实际上受限于主机DMA内存大小;
自动映射整个Myrinet网络结构,解决路由问题。
GM由Myrine控制程序MCP、驱动程序DIRVER、GM函数库LIBGM三部分构成。这三部分之间的关系可以用图2来描述。
LIBGM为用户程序提供编程接口,其中最重要的是发送和接收函数。此外,还提供一整套通用函数,如初始化、DMA内存管理、令牌管理、哈希管理、CRC校验等。
DRIVER是GM中的一个重要部分。其最主要的功能是完成MCP的初始化。其次还要将网络接口的内存区域和寄存器映射到用户层和实现一些辅助函数。
MCP是GM最关键的部分,GM的其他功能都是在MCP的基础上构架起来的。MCP运行在Myrinet的网卡的LANai芯片上,它由DRIVER加载到LANai上。MCP借助LANai上的CPU和SRAM承担了大部分的通信处理工作,包括:在主机内存和LANaiSRAM之间的数据DMA传送、数据包的拆分和组装、CRC校验、通信的应答管理、端口和令牌资源的分配、调度管理等。因此,主机方面的通信开销很小。
为了利用GM的高带宽和低延迟,Myricom公司设计了基于GM的MPICH,即MPICH-GM。MPICH-GM的最大带宽是230MB/s左右。
【发明内容】
本发明要解决的技术问题是提出一种基于双网卡的通讯方法,采用本发明所述方法,可提高了大消息通信的带宽,大大降低了大消息通信的延迟。
本发明所述基于双网卡的通讯方法,把两块Myrinet网卡绑定,虚拟成一块网卡;在GM目录中增加两个文件,即用于实现包裹函数的my_gm.c和gm_bond.c;还包括如下步骤:
打开一个数据结构,记录了相应进程所拥有的数据资源和所能访问的内存区域;在包裹函数中调用两次gm_open函数,在两个网卡上分别打开一个通信端口;
申请内存区域:在包裹函数中调用两次存储注册函数,在缓冲区中针对两个网卡分别注册;
发送方发送消息:通过包裹函数调用两次带有回执的发送函数gm_send_with_callback,第一次发送消息的前一半,第二次发送消息的后一半;
接收方接收消息:调用两次提供接收缓冲区函数gm_provide_receive_buffer,分别针对两个网卡提供两个接收令牌,第一个接收令牌与接收缓冲区的前一半相关联,第二个接收令牌与接收缓冲区的后一半相关联;接收到消息的两个分片,产生两个接收事件后,确认一个消息接收成功。
发送/接收方还有不需要用接收令牌的方式:
即采用带有回执的发送函数gm_directed_send_with_callback发送数据,将数据直接发往接收方的指定缓冲区中,在接收方不需要提供接收令牌。这种方式数据接收完成后,在接收方也不产生事件。发送完成后,在发送方要产生事件,数据分片后,发送一个消息产生两个事件。
采用本发明,提高了大消息通信的带宽,使最大带宽从单块网卡的230MB/s提高到330MB/s。大大降低了大消息通信的延迟。
【附图说明】
图1是Myrinet网络硬件结构和数据通信示意图;
图2是用户态通讯协议GM的结构和调用关系示意图;
图3是用户态通讯协议GM发送/接收数据的原理示意图;
图4是本发明双网卡通信方法的发送/接收数据示意图。
【具体实施方式】
图1和图2已经在前面叙述过,故不赘述。
图3给出的是用户态通讯协议GM发送/接收数据的原理示意图;本发明所述方法是在图3的原理基础上,为了提高大消息通信的带宽,降低大消息通信的延迟,而发展起来的。图3的基本原理是这样的:
发送数据时,首先打开一个通信端口,然后申请DMA缓冲区,把数据从DMA缓冲区中传输到网卡缓冲区中,最后把数据从网卡缓冲区中发送到网络上,发送完成后,产生一个事件交给上层应用,应用通过捕捉这个事件来确定发送是否成功。
接收数据时,首先也要打开一个通信端口,然后申请DMA缓冲区,还需要申请接收令牌。有数据到达时,把数据从网卡缓冲区传输到相应的接收令牌所标志的用户缓冲区中,然后产生一个事件来通知应用有新的数据到达。
为了提高通信的带宽,特别是提高大消息的带宽,本发明所述方法的基本思路是,将两块Myrinet网卡绑定,虚拟成一块网卡。在发送数据的时候,把每一个消息分成两片,分别通过两块不同的网卡发送,在接收方则通过不同的网卡接收,这样不仅提高了通信的带宽,而且降低了延迟。
尽管MPICH-GM的带宽已经达到230MB/s,但是随着应用的需求不断提高,可能需要更高带宽的网络。为了满足这种需求,可以把两块Myrinet网卡绑定起来,虚拟成一块网卡,同样,需要把要发送的消息分成两片,分别发送到对方的两个网卡,这样就提高了网络带宽,也降低了延迟。
具体地说,第一是数据分片,在双网卡通信协议中,消息的发送是通过不同的网卡进行的,每一块网卡发送不同的消息分片。这样就需要对消息数据进行分片,但是过于细的粒度的数据分片,会使每一次传输的数据包的长度变小,不利于提高通信的带宽。目前选定的是否分片的界限为16K,即大于16K的消息分成两片,小于16K的消息不分片,这个值也可以由用户自己来指定。
第二个需要解决的问题是数据的同步问题。数据同步是指消息的不同分片如何保证同步到达消息接收方,并组装成完整的消息。由于是GM基于事件机制,消息到达或者消息发送完成都通过事件通知应用。消息分片以后,产生两个消息到达的事件才意味着接收到一个完整的消息;同样,发送方,接收到两个发送完成的事件才算是整个消息发送完成。这需要修改MPI。
第三个问题是如何把接收到的消息放到缓冲区的特定位置。实际上是在哪个网卡上分配相应的接收令牌的问题。利用MPI的三路握手协议可以很巧妙的解决这个问题。对于大于16K的消息,MPI使用三路握手的协议。因为三路握手协议是在接收方先分配好缓冲区和接收令牌后,发送方才开始发送真正的数据。这样我们就可以在向发送方返回应答消息时,在消息里面包含标志接收网卡的顺序的信息。发送方根据这个标志就可以向正确的网卡发送消息。
本发明所述基于双网卡的通信方法,具体地包括两个方面,一是对GM层的修改,主要是通过包裹函数实现的;二是对MPI(Massage Passing Interface)层的修改。
对GM层的修改通过包裹函数实现,所以并不直接修改GM原有的文件,只是增加了两个文件。GM目录中增加两个文件my_gm.c和gm_bond.c。
my_gm.c用来实现了包裹函数,gm_bond.c中主要是用来辅助实现包裹函数的一些辅助的函数。
GM通信在称为“端口”的通信端点之间进行,提供可靠有序的消息传递。
GM通信过程包括:初始化通信端口;申请DMA内存区域;消息发送和接收等几个过程。
进程初始化时,首先打开一个数据结构,记录了相应进程所拥有的数据资源和所能访问的内存区域。由于是通过两个网卡通信,所以在包裹函数中调用两次gm_open函数,在两个网卡上分别打开一个通信端口。
GM要求进程收发消息的缓冲区必须是一块可以用来DMA的内存区域。该区域可以通过直接申请得到(gm_dma_malloc),或将当前已有的用户缓冲区注册得到(gm_register_memory)。MPICH-GM中,小消息用gm_dma_malloc方式,大消息用gm_register_memory方式。本发明所述基于双网卡的通信方法只对大消息起作用,大消息被分成两片经过两个网卡来传送,因此在包裹函数中调用两次gm_register_memory函数,在缓冲区中针对两个网卡分别注册。
图4是本发明基于双网卡的通信方法发送/接收数据示意图。发送时,针对两个网卡,需要在包裹函数里调用两次带有回执的发送函数gm_send_with_callback,第一次发送消息的前一半,第二次发送消息的后一半。用gm_send_with_callback发送数据,每发送一次完成后产生一个事件,用来表示该次发送是否成功,用gm_receive可以接收这个事件,在gm_unknown处调用了callback函数。对gm_receive要针对两个网卡轮询调用。gm_unknown要和gm_receive使用的端口保持一致。
由于GM是基于事件机制,发送成功一个消息,都会产生一个事件来通知应用。消息分成两片以后,每个分片发送成功后都会产生一个事件,相当于发送原来未分片的消息成功以后,产生了两个发送成功的事件。因此需要修改MPICH-GM,使得接收到两个事件后,才算一个消息发送成功,才能处理发送消息成功以后应该做的事情。
本发明所述方法中,接收数据要调用gm_provide_receive_buffer提供接收令牌,接收令牌决定了接收到的数据应该放到哪个缓冲区中。接收数据的缓冲区同样针对两个网卡分别进行注册。修改MPICH-GM,对大消息调用两次接收缓冲区函数gm_provide_receive_buffer,分别针对两个网卡提供两个接收令牌,第一个接收令牌与接收缓冲区的前一半相关联,第二个接收令牌与接收缓冲区的后一半相关联。这样也决定了消息的第一个分片必须发送到第一个接收令牌所对应的网卡,消息的第二个分片必须发送到第二个接收令牌所对应的网卡。由于MPI发送大于16K的消息时,使用三路握手协议。对于大于16K的消息,使用三路握手的协议。发送方首先发送“你准备好了吗”,对方在收到这个消息后,分配相应的接收缓冲区和接收令牌,然后应答“准备好了,现在可以发送了”,最后再发出所有的数据。利用MPI的三路握手协议可以很巧妙的解决这个问题。因为三路握手协议是在接收方先分配好缓冲区和接收令牌后,发送方才开始发送真正的数据。这样接收方就可以在向发送方返回应答消息时,在消息里面包含标志接收网卡的顺序的信息。发送方根据这个标志就可以向正确的网卡发送消息。
接收与发送相似,接收到消息的两个分片以后,才算是一个消息接收成功,但这产生了两个接收成功的事件。因此需要修改MPICH-GM,使得接收到两个事件后,才算一个消息接收成功,才能处理接收消息成功以后应该做的事情。
如果使用gm_directed_send_with_callback函数发送数据,数据会直接被发往接收方的指定缓冲区中,在接收方不需要提供接收令牌。这种方式数据接收完成后,在接收方也不产生事件。发送完成后,在发送方要产生事件,数据分片后,发送一个消息产生两个事件。
在MPICH-GM中,还需要添加一个头文件,使得调用GM的API时,实际上是调用了包裹函数;头文件如下所示。
#define gm_open my_gm_open
#define gm_close my_gm_close
#define gm_send my_gm_send
……
最后所应说明的是:以上实施例仅用以说明而非限制本发明的技术方案,尽管参照上述实施例对本发明进行了详细说明,本领域的普通技术人员应当理解:依然可以对本发明进行修改或者等同替换,而不脱离本发明的精神和范围的任何修改或局部替换,其均应涵盖在本发明的权利要求范围当中。