OpenMPI源码剖析3:try_kill_peers 和 ompi_rte_abort 函数
接着上一篇的疑问,我们说道,会执行 try_kill_peers 函数,它的函数定义在 ompi_mpi_abort.c 下:
// 这里注释也说到了,主要是杀死在同一个communicator的进程(不包括自己) /* * Local helper function to build an array of all the procs in a * communicator, excluding this process. * * Killing a just the indicated peers must be implemented for * MPI_Abort() to work according to the standard language for * a 'high-quality' implementation. * * It would be nifty if we could differentiate between the * abort scenarios (but we don't, currently): * - MPI_Abort() * - MPI_ERRORS_ARE_FATAL * - Victim of MPI_Abort() */ // 调用时传入了对应通信子 static void try_kill_peers(ompi_communicator_t *comm, int errcode) { // 1. 第一部分: 给 ompi_process_name_t 指针申请空间,得到进程个数 int nprocs; ompi_process_name_t *procs; nprocs = ompi_comm_size(comm); /* ompi_comm_remote_size() returns 0 if not an intercomm, so this is safe */ nprocs += ompi_comm_remote_size(comm); procs = (ompi_process_name_t*) calloc(nprocs, sizeof(ompi_process_name_t)); if (NULL == procs) { /* quick clean orte and get out */ ompi_rte_abort(errno, "Abort: unable to alloc memory to kill procs"); } // 2. 第二部分: 将进程放入数组中 /* put all the local group procs in the abort list */ int rank, i, count; rank = ompi_comm_rank(comm); //这里可以获取到自己在该 communicator 中的 rank————疑问1 for (count = i = 0; i < ompi_comm_size(comm); ++i) { if (rank == i) { /* Don't include this process in the array */ --nprocs; } else { assert(count <= nprocs); procs[count++] = *OMPI_CAST_RTE_NAME(&ompi_group_get_proc_ptr(comm->c_remote_group, i, true)->super.proc_name); } } // 3. 第三部分: 远程的 group 进程也放入数组中 /* if requested, kill off remote group procs too */ for (i = 0; i < ompi_comm_remote_size(comm); ++i) { assert(count <= nprocs); procs[count++] = *OMPI_CAST_RTE_NAME(&ompi_group_get_proc_ptr(comm->c_remote_group, i, true)->super.proc_name); } // 4. 第四部分: 杀死进程 if (nprocs > 0) { ompi_rte_abort_peers(procs, nprocs, errcode); } /* We could fall through here if ompi_rte_abort_peers() fails, or if (nprocs == 0). Either way, tidy up and let the caller handle it. */ free(procs); }
这个时候,就得去看看 ompi_rte_abort_peers(procs, nprocs, errcode) 函数的定义,
它在 rte_orte.h 中其实是一个宏定义:
#define ompi_rte_abort_peers(a, b, c) orte_errmgr.abort_peers(a, b, c)
orte_errmgr 是一个结构体对象,调用了abort_peers成员函数,最后在 errmgr.h 中找到了 orte_errmgr 对象:
/* * Module Structure */ struct orte_errmgr_base_module_2_3_0_t { /** Initialization Function */ orte_errmgr_base_module_init_fn_t init; /** Finalization Function */ orte_errmgr_base_module_finalize_fn_t finalize; orte_errmgr_base_module_log_fn_t logfn; orte_errmgr_base_module_abort_fn_t abort; orte_errmgr_base_module_abort_peers_fn_t abort_peers; }; typedef struct orte_errmgr_base_module_2_3_0_t orte_errmgr_base_module_2_3_0_t; typedef orte_errmgr_base_module_2_3_0_t orte_errmgr_base_module_t; ORTE_DECLSPEC extern orte_errmgr_base_module_t orte_errmgr; //这是一个导出的extern全局变量
再顺便附上该结构体中的函数的定义,也在 rte_orte.h 头文件中:
/* * Framework Interfaces */ /** * Module initialization function. * * @retval ORTE_SUCCESS The operation completed successfully * @retval ORTE_ERROR An unspecifed error occurred */ typedef int (*orte_errmgr_base_module_init_fn_t)(void); /** * Module finalization function. * * @retval ORTE_SUCCESS The operation completed successfully * @retval ORTE_ERROR An unspecifed error occurred */ typedef int (*orte_errmgr_base_module_finalize_fn_t)(void); /** * This is not part of any module so it can be used at any time! */ typedef void (*orte_errmgr_base_module_log_fn_t)(int error_code, char *filename, int line); /** * Alert - self aborting * This function is called when a process is aborting due to some internal error. * It will finalize the process * itself, and then exit - it takes no other actions. The intent here is to provide * a last-ditch exit procedure that attempts to clean up a little. */ typedef void (*orte_errmgr_base_module_abort_fn_t)(int error_code, char *fmt, ...) __opal_attribute_format_funcptr__(__printf__, 2, 3); /** * Alert - abort peers * This function is called when a process wants to abort one or more peer processes. * For example, MPI_Abort(comm) will use this function to terminate peers in the * communicator group before aborting itself. */ typedef int (*orte_errmgr_base_module_abort_peers_fn_t)(orte_process_name_t *procs, orte_std_cntr_t num_procs, int error_code);
这里呢,对 杀死进程 这一块的探索呢,就先到此了————这里已经知道,接下来的步骤就是遍历数组,杀死进程,
这里留下 疑问2: orte_errmgr 这个 orte_errmgr_base_module_2_3_0_t 对象是在哪里初始化的?它的函数在哪里赋值了?我猜是在初始化MPI_Init()的过程中
上一篇文章,还有一个 ompi_rte_abort 函数,在 rte.h 中的注释说明有提及:
* (d) Error handling objects and operations * 1. void ompi_rte_abort(int err_code, char *fmt, ...) - Abort the current * process with the specified error code and message. * 2. int ompi_rte_abort_peers(ompi_process_name_t *procs, size_t nprocs) - * Abort the specified list of peers * 3. OMPI_ERROR_LOG(rc) - print error message regarding the given return code
也就是说,ompi_rte_abort 这个函数就是 abort 自身进程了。
那么,我们就把这2个函数的大概交代清楚了。 在 rte.h 这个头文件中,我们还找到了一个比较有价值的注释说明。这个将会留在下一篇文章中说明。
重复一下本文留下的疑点:
1. ompi_comm_rank(comm) 这个函数
2. orte_errmgr 这个 orte_errmgr_base_module_2_3_0_t 对象是在哪里初始化的?