Slurm 插件 API
概述
Slurm 插件是一个动态链接的代码对象,在运行时由 Slurm 库显式加载。插件提供了与身份验证、互连结构和任务调度等任务相关的明确定义的 API 的自定义实现。
标识
Slurm 插件通过一个短字符字符串来标识自己,该字符串的格式类似于 MIME 类型: <major>/<minor>。主要类型标识插件实现的 API。次要类型通过意图平台或内部算法等方式将插件与实现相同 API 的其他插件唯一区分开。例如,一个与 Maui 调度器接口的插件将其类型指定为 "sched/maui." 它将实现 Slurm 调度器 API。
版本控制
Slurm 插件版本号由主要、次要和微修订号组成。如果主要和/或次要修订号发生变化,这表示 Slurm 功能的重大变化,包括 API、命令选项和插件的变化。这些插件变化可能包括新功能和/或功能参数。如果仅微修订号发生变化,这表明修复了错误并可能进行了小幅增强,这不应对用户产生不利影响。在升级时,建议重新构建和安装所有 Slurm 插件。集群中的所有计算节点不需要同时更新,但计算节点上的所有 Slurm API、命令、插件等应表示相同版本的 Slurm。
数据对象
插件必须定义并导出以下符号:
- char plugin_type[]
一个唯一的、短的、格式化的字符串,用于标识插件的目的,如上所述。一个 "null" 插件(即实现所需 API 的存根)应具有次要类型 "none." - char plugin_name[]
一个自由格式的字符串,用于以人类可读的术语标识插件,例如 "Kerberos 身份验证." Slurm 将使用此字符串向最终用户标识插件。 - const uint32_t plugin_version
标识用于构建此插件的 Slurm 版本,任何尝试从不同版本的 Slurm 加载插件将导致错误。微版本不适用于 SPANK 插件。
所有插件中的 API 函数
int init (void);
描述: 如果存在,此函数在插件加载后立即被调用。这允许插件在任何实际 API 调用之前执行任何全局初始化。
参数: 无。
返回: 如果插件的初始化成功,则返回 SLURM_SUCCESS。任何其他返回值表示 Slurm 应卸载该插件并不使用。
void fini (void);
描述: 如果存在,此函数在插件卸载之前被调用。这允许插件在最后一次插件特定的 API 调用后进行任何最终处理。
参数: 无。
返回: 无。
注意: 这些 init 和 fini 函数与 dlopen (3) 系统库中描述的函数不同。C 运行时系统会占用这些符号进行其自身的初始化。系统的 _init() 在 Slurm 的 init() 之前被调用,而 Slurm 的 fini() 在系统的 _fini() 之前被调用。
这些函数不一定需要出现。插件可以提供 init() 或 fini() 或两者。
线程安全
Slurm 是一个多线程应用程序。Slurm 插件库可能以可重入的方式调用插件函数。插件作者有责任提供必要的互斥和同步,以避免可重入代码的陷阱。
运行时支持
标准系统库可供插件使用。Slurm 库也可用,鼓励插件作者使用它们,而不是开发自己的替代品。插件应使用 Slurm 日志打印错误消息。
插件作者有责任指定任何特定的非标准库,以确保正确操作。如果其依赖库不可用,插件将无法加载,因此安装者的工作是确保指定的库可用。
性能
所有插件函数都应快速执行。如果任何函数涉及延迟(例如与其他系统的事务),则应编写为利用线程来实现该功能。此线程可以由 init() 函数创建,并由 fini() 函数删除。有关如何执行此操作的示例,请参见 plugins/sched/backfill。
数据结构一致性
在某些情况下,Slurm 使用计数器迭代不同的数据结构元素。例如,使用环境变量数组。为了避免缓冲区溢出和其他不希望出现的情况,当插件修改某些元素时,必须相应地更新这些计数器。其他情况可能需要其他类型的更改。
以下建议指示哪些结构具有在修改数据时必须维护的与计数器相关的数组,以及在操作这些结构时需要考虑的其他可能的重要信息。由于代码的不断修改,此列表并不完全详尽,但它是大多数常见情况的起始点和基本指南。完整的结构信息可以在 slurm/slurm.h.in 文件中查看。
slurm_job_info_t (job_info_t) 数据结构
uint32_t env_size; char **environment; uint32_t spank_job_env_size; char **spank_job_env; uint32_t gres_detail_cnt; char **gres_detail_str;
这些数组指针和元素计数对必须保持更新,以避免后续的缓冲区溢出,因此如果您更新数组,必须同时更新相关计数器。
char *nodes; int32_t *node_inx; int32_t *req_node_inx; char *req_nodes;
node_inx 和 req_node_inx 表示在 nodes 和 req_nodes 字段中定义的节点范围的索引对列表。在每种情况下,这两个数组变量的计数必须匹配。
uint32_t het_job_id; char *het_job_id_set;
het_job_id 字段应为 het_job_id_set 数组的第一个元素。
job_step_info_t 数据结构
char *nodes; int32_t *node_inx;
node_inx 表示在 nodes 中定义的节点范围的索引对列表。这两个变量的计数必须匹配节点计数。
priority_factors_object_t 数据结构
uint32_t tres_cnt; char **tres_names; double *tres_weights;
此值必须与系统上配置的 TRES 匹配,否则在迭代 tres_names 或 tres_weights 数组时可能会导致缓冲区溢出。
job_step_pids_t 数据结构
uint32_t pid_cnt; uint32_t *pid;
数组 pid 表示作业步骤的进程 ID 列表,而 pid_cnt 是必须与数组大小匹配的计数器。
slurm_step_layout_t 数据结构
uint32_t node_cnt; char *node_list;
node_list 数组的大小必须与 node_cnt 匹配。
uint16_t *tasks; uint32_t node_cnt; uint32_t task_cnt;
在 tasks 数组中,每个元素是分配给相应节点的任务数,因此其大小必须与 node_cnt 匹配。此外,task_cnt 表示在 tasks 中注册的任务总数。
uint32_t **tids;
tids 是一个长度为 node_cnt 的任务 ID 数组。每个子数组由 tasks 数组中的相应值指定,因此 tasks、tids 和 task_cnt 必须设置为匹配此布局。
slurm_step_launch_params_t 数据结构
uint32_t envc; char **env;
在修改 env 数组中的环境变量时,必须相应地修改 envc 计数器,以防止在后续循环中出现缓冲区溢出。
uint32_t het_job_nnodes; uint32_t het_job_ntasks; uint16_t *het_job_task_cnts; uint32_t **het_job_tids; uint32_t *het_job_node_list;
这些 het_job_* 相关变量必须与当前的异构作业配置匹配。
例如,如果由于某种原因您正在减少异构作业中某个节点的任务数,则至少应从 het_job_tids 中删除该任务 ID,减少 het_job_ntasks 和 het_job_task_cnts,并可能减少异构作业在 het_job_nnodes 和 het_job_node_list 中的节点数。
char **spank_job_env; uint32_t spank_job_env_size;
在修改 spank_job_env 结构时,必须更新 spank_job_env_size 字段,以防止在后续循环中出现缓冲区溢出。
node_info_t 数据结构
char *features; char *features_act;
在包含 Intel KNL 处理器的系统中,features_act 字段由插件设置,以匹配节点上当前运行的模式。在其他系统中,features_act 通常不使用。如果您编写这样的插件,必须确保 features_act 包含 features 的一个子集。
char *reason; time_t reason_time; uint32_t reason_uid;
如果 reason 被修改,则应更新 reason_time 和 reason_uid。
reserve_info_t 数据结构
int32_t *node_inx; uint32_t node_cnt;
node_inx 表示与保留相关的节点范围的索引对列表,其计数必须等于 node_cnt。
partition_info_t 数据结构
没有特别建议。
slurm_step_layout_req_t 数据结构
没有特别建议。
slurm_step_ctx_params_t
没有特别建议。
最后修改于 2022 年 8 月 25 日