OpenMPI源码剖析:网络通信原理(一)
MPI中的网络通信的原理,需要解决以下几个问题:
1. MPI使用什么网络协议进行通信?
2.中央数据库是存储在哪一台机器上?
3.集群中如果有一台机器挂掉了是否会影响其他机器?
参考: https://aosabook.org/en/openmpi.html
根据MCA, 每个框架下的模块是可变的,例如, btl (字节传输层)框架下有N多个网络协议模块:
既然是可变的,但是我们运行的时候都没有传入对应的选择参数,也就是说明有默认值。 官方文档也说了,工程师和科学家尽可能帮我们选择一个合理的默认值,但是对于不同的机器集群会有不同的效果,所以建议我们自己测试最好的参数。
当每个通信域(包括MPI_COMM_WORLD和MPI_COMM_SELF)被创建时,每个可用模块被询问是否需要在新通信域中使用。模块可以拒绝被使用,例如,一个基于共享内存的模块只有当通信域中的所有进程都在相同的物理节点上时,才允许被使用。通信域将会选择最高优先级的模块使用。
当然,这个也是可以让用户更改的
根据 https://aosabook.org/en/openmpi.html中介绍的,用户可以通过传入MCA命令行参数去改变运行时的模块
再看到位于 c/send.c 文件中的Send函数定义:
- #if OMPI_BUILD_MPI_PROFILING
- #if OPAL_HAVE_WEAK_SYMBOLS
- #pragma weak MPI_Send = PMPI_Send
- #endif
- #define MPI_Send PMPI_Send
- #endif
- static const char FUNC_NAME[] = "MPI_Send";
- int MPI_Send(const void *buf, int count, MPI_Datatype type, int dest,
- int tag, MPI_Comm comm)
- {
- int rc = MPI_SUCCESS;
- MEMCHECKER(
- memchecker_datatype(type);
- memchecker_call(&opal_memchecker_base_isdefined, buf, count, type);
- memchecker_comm(comm);
- );
- if ( MPI_PARAM_CHECK ) {
- OMPI_ERR_INIT_FINALIZE(FUNC_NAME);
- if (ompi_comm_invalid(comm)) {
- return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_COMM, FUNC_NAME);
- } else if (count < ) {
- rc = MPI_ERR_COUNT;
- } else if (tag < || tag > mca_pml.pml_max_tag) {
- rc = MPI_ERR_TAG;
- } else if (ompi_comm_peer_invalid(comm, dest) &&
- (MPI_PROC_NULL != dest)) {
- rc = MPI_ERR_RANK;
- } else {
- OMPI_CHECK_DATATYPE_FOR_SEND(rc, type, count);
- OMPI_CHECK_USER_BUFFER(rc, buf, type, count);
- }
- OMPI_ERRHANDLER_CHECK(rc, comm, rc, FUNC_NAME);
- }
- if (MPI_PROC_NULL == dest) {
- return MPI_SUCCESS;
- }
- OPAL_CR_ENTER_LIBRARY();
- rc = MCA_PML_CALL(send(buf, count, type, dest, tag, MCA_PML_BASE_SEND_STANDARD, comm));
- OMPI_ERRHANDLER_RETURN(rc, comm, rc, FUNC_NAME);
- }
前面一堆都是错误检查,会让不合法的操作不会真正的进行 send 这个操作。
最后看到关键的发送代码:
- rc = MCA_PML_CALL(send(buf, count, type, dest, tag, MCA_PML_BASE_SEND_STANDARD, comm));
MCA_PML_CALL 是一个宏,我们在 pml.h 中可以找到它:
#if MCA_ompi_pml_DIRECT_CALL
#include MCA_ompi_pml_DIRECT_CALL_HEADER
#define MCA_PML_CALL_STAMP(a, b) mca_pml_ ## a ## _ ## b
#define MCA_PML_CALL_EXPANDER(a, b) MCA_PML_CALL_STAMP(a,b)
#define MCA_PML_CALL(a) MCA_PML_CALL_EXPANDER(MCA_ompi_pml_DIRECT_CALL_COMPONENT, a)
#else
#define MCA_PML_CALL(a) mca_pml.pml_ ## a
#endif
由于 if 下代码块搜索不到,所以我们直接看 else 中的 mca_pml.pml_ send(buf, count, type, dest, tag, MCA_PML_BASE_SEND_STANDARD, comm)
其实 mca_pm 是一个导出的 mca_pml_base_module_t 变量:
- OMPI_DECLSPEC extern mca_pml_base_module_t mca_pml;
mca_pml_base_module_t 的定义如下:
- struct mca_pml_base_module_1_0_1_t {
- /* downcalls from MCA to PML */
- mca_pml_base_module_add_procs_fn_t pml_add_procs;
- mca_pml_base_module_del_procs_fn_t pml_del_procs;
- mca_pml_base_module_enable_fn_t pml_enable;
- mca_pml_base_module_progress_fn_t pml_progress;
- /* downcalls from MPI to PML */
- mca_pml_base_module_add_comm_fn_t pml_add_comm;
- mca_pml_base_module_del_comm_fn_t pml_del_comm;
- mca_pml_base_module_irecv_init_fn_t pml_irecv_init;
- mca_pml_base_module_irecv_fn_t pml_irecv;
- mca_pml_base_module_recv_fn_t pml_recv;
- mca_pml_base_module_isend_init_fn_t pml_isend_init;
- mca_pml_base_module_isend_fn_t pml_isend;
- mca_pml_base_module_send_fn_t pml_send;
- mca_pml_base_module_iprobe_fn_t pml_iprobe;
- mca_pml_base_module_probe_fn_t pml_probe;
- mca_pml_base_module_start_fn_t pml_start;
- mca_pml_base_module_improbe_fn_t pml_improbe;
- mca_pml_base_module_mprobe_fn_t pml_mprobe;
- mca_pml_base_module_imrecv_fn_t pml_imrecv;
- mca_pml_base_module_mrecv_fn_t pml_mrecv;
- /* diagnostics */
- mca_pml_base_module_dump_fn_t pml_dump;
- /* FT Event */
- mca_pml_base_module_ft_event_fn_t pml_ft_event;
- /* maximum constant sizes */
- uint32_t pml_max_contextid;
- int pml_max_tag;
- int pml_flags;
- };
- typedef struct mca_pml_base_module_1_0_1_t mca_pml_base_module_1_0_1_t;
- typedef mca_pml_base_module_1_0_1_t mca_pml_base_module_t;
哦!!!这下明白了吧!!!我们所有的进行的 send , recv 等点对点 (PML) 的通信函数都封装在了这个结构体 的 函数指针成员里。
为什么要这么做呢?
——之前我们说过它支持不同的通信协议,在用户没有特定输入的时候,默认选择最高优先级的通信协议。如果每个通信协议都对应一套函数,那不是很麻烦???
为了让这个设计简单,可维护,用一个 base 封装起常见的操作,改变函数指针即可以改变使用的协议啦!!
那么下一节,我们就得看看,这个导出的 mca_pml_base_module_t 变量 mca_pm 的 函数指针在哪里初始化?——也就是,我们要看看它如何选择通信协议的!
OpenMPI源码剖析:网络通信原理(一)的更多相关文章
- OpenMPI源码剖析1:MPI_Init初探
OpenMPI的底层实现: 我们知道,OpenMPI应用起来还是比较简单的,但是如果让我自己来实现一个MPI的并行计算,你会怎么设计呢?————这就涉及到比较底层的东西了. 回想起我们最简单的代码,通 ...
- OpenMPI源码剖析:网络通信原理(二) 如何选择网络协议?
因为比较常用的是 TCP 协议,所以在 opal/mca/btl/tcp/btl_tcp.h 头文件中找到对应的 struct mca_btl_tcp_component_t { mca_btl_ba ...
- OpenMPI源码剖析4:rte.h 头文件的说明信息
上一篇文章中说道,我们在 rte.h 中发现了有价值的说明: 我们一块一块来分析,首先看到第一块,关于 Process name Object: * (a) Process name objects ...
- OpenMPI源码剖析3:try_kill_peers 和 ompi_rte_abort 函数
接着上一篇的疑问,我们说道,会执行 try_kill_peers 函数,它的函数定义在 ompi_mpi_abort.c 下: // 这里注释也说到了,主要是杀死在同一个communicator的进程 ...
- OpenMPI源码剖析2:ompi_mpi_errors_are_fatal_comm_handler函数
上一篇文章说道,初始化失败会有一个函数调用: ompi_mpi_errors_are_fatal_comm_handler(NULL, NULL, message); 所以这里简单地进入了 ompi_ ...
- 老李推荐:第14章9节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-遍历控件树查找控件
老李推荐:第14章9节<MonkeyRunner源码剖析> HierarchyViewer实现原理-遍历控件树查找控件 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员 ...
- 老李推荐:第14章5节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-查询ViewServer运行状态
老李推荐:第14章5节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-查询ViewServer运行状态 poptest是国内唯一 ...
- 老李推荐:第14章6节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-启动ViewServer
老李推荐:第14章6节<MonkeyRunner源码剖析> HierarchyViewer实现原理-装备ViewServer-启动ViewServer poptest是国内唯一一家培养 ...
- 老李推荐:第14章3节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-HierarchyViewer实例化
老李推荐:第14章3节<MonkeyRunner源码剖析> HierarchyViewer实现原理-HierarchyViewer实例化 poptest是国内唯一一家培养测试开发工程师的培 ...
随机推荐
- Difference between HashMap and Hashtable | HashMap Vs Hashtable
Both the HashMap and Hashtable implement the interface java.util.Map but there are some slight diffe ...
- [BZOJ 3652]大新闻
[BZOJ 3652] 大新闻 题意 随机从 \([0,n)\) 中选取一个整数 \(x\), 并从 \([0,n)\) 中再选取一个整数 \(y\). 有 \(p\) 的概率选取一个能令 \(x\o ...
- Q矩阵输出
程序启动时: 1.Q矩阵在InitQX中对角阵赋初值为0.25,GPS卫星数6 2.Q矩阵初值在初始化时由GetBL获得,改变Q对角阵 Q初值第0个卫星 10000000000.000 X初值第0个卫 ...
- 【Alpha 冲刺】 7/12
今日任务总结 人员 今日原定任务 完成情况 遇到问题 贡献值 胡武成 建立数据库 已完成 孙浩楷 完成作业列表界面 已完成 胡冰 完成作业展示页面 已完成 练斐弘 完成课件列表页面 未完成 时间不够 ...
- Sqlite的安装和简单使用
Sqlite 1 安装 首先,下载相应的版本: https://sqlite.org/download.html 其次,解压到本地,并添加到环境变量. 然后,打开 CMD 创建,输入 sqlite3 ...
- JSONP方法解决跨域请求
Ajax跨域请求的问题 跨域:跨域名, 一个域名下的文件去请求了和他不一样的域名下的资源文件(注意是请求文件,而不是数据接口),那么就会产生跨域请求,下面来写一个ajax来跨域请求的例子 <!D ...
- HBase概念学习(九)HTablePool为何弃用?
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/jiq408694711/article/details/36526433 转载请注明出处:jiq•钦 ...
- [题目] Luogu P1312 Mayan游戏
题面 题目描述 $ Mayan puzzle $是最近流行起来的一个游戏.游戏界面是一个 \(7行 \times 5列\)的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放 ...
- php排序算法及二分法查找
插入排序 思想:将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表.即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止. 要点:设立 ...
- 使用 rem 作为单位使页面自适应设备宽度
一.新建 rem.js 文件,代码如下: export default function () { document.documentElement.style.fontSize = document ...