Slurm管理和使用集群节点资源主要分为四个环节:分别是初始化节点资源、更新节点资源、测试节点资源可用、实际分配节点资源。
slurmctld初始化时解析节点配置文件,借助几个全局数据结构(select插件中也有几个数据结构):
node_record_table_ptr |
节点数组,保存所有节点描述符 |
node_hash_table |
节点哈希表,保存所有节点描述符,加快查找 |
node_record_count |
全部节点计数 |
config_list |
节点配置链表,对应配置文件NodeName一条记录,包含相同配置所有节点位图。(节点描述符struct node_record) |
part_list |
分区配置链表,对应配置文件PartitionName一条记录,包含分区所有节点位图。(分区描述符struct part_record) |
last_node_update |
节点信息更新时间戳 |
last_part_update |
分区信息更新时间戳 |
和全局节点位图:
avail_node_bitmap |
bitmap of available nodes |
booting_node_bitmap |
bitmap of booting nodes |
cg_node_bitmap |
bitmap of completing nodes |
future_node_bitmap |
bitmap of FUTURE nodes |
idle_node_bitmap |
bitmap of idle nodes |
power_node_bitmap |
bitmap of powered down node |
share_node_bitmap |
bitmap of sharable nodes |
up_node_bitmap |
bitmap of non-down nodes |
rs_node_bitmap |
bitmap of resuming nodes |
|
|
slurmctld初始化过程中初始化节点配置过程:
main(src\slurmctld\controller.c)
read_slurm_conf(recover, false)
_build_all_nodeline_info//初始化节点配置
build_all_nodeline_info
create_config_record//每个config_record对应于slurm.conf文件中的NodeName一行,通常描述大量节点的配置。添加进全局配置链表config_list
_build_single_nodeline_info//遍历NodeName一行所有节点
create_node_record//(src\common\node_conf.c)初始化单个node_ptr,同时更新全局节点链表node_record_table_ptr和节点哈希表node_hash_table
_build_all_partitionline_info//初始化分区配置
_build_single_partitionline_info
create_part_record//解析PartitionName行数据,逐个初始化分区配置part_record,添加到全局part_list
rehash_node//重建全局节点哈希表node_hash_table
_build_bitmaps_pre_select//设置分区链表和节点配置链表中对应节点位图
select_g_node_init通过资源选择select插件重新/初始化#全局#节点记录数据结构
select_p_node_init(src\plugins\select\cons_res\select_cons_res.c)
cr_init_global_core_data//初始化cpu核心相关全局数据
_build_bitmaps//构建avail_node_bitmap/idle_node_bitmap/share_node_bitmap等全局节点位图
slurmd向slurmctld注册时会更新节点部分数据。
slurmctld_req(src\slurmctld\proc_req.c)
_slurm_rpc_node_registration//MESSAGE_NODE_REGISTRATION_STATUS
validate_node_specs//1.获取节点描述符;2.逐项更新
提交作业时,会调用资源选择select插件,测试能否为作业分配节点但并不实际分配节点。
slurmctld_req(src\slurmctld\proc_req.c)
_slurm_rpc_submit_batch_job//REQUEST_SUBMIT_BATCH_JOB
job_allocate(src\slurmctld\job_mgr.c)
_job_create//创建作业对象
set_job_prio//设置作业优先级
slurm_sched_g_initial_priority//调用调度插件
slurm_sched_p_initial_priority(src\plugins\sched\backfill\backfill_wrapper.c)
priority_g_set//调用优先级插件
priority_p_set(src\plugins\priority\multifactor\priority_multifactor.c)
_get_priority_internal//实际计算作业优先级,输出作业第一条日志
_select_nodes_parts//为作业选定运行节点
select_nodes(test_only为true)//重要,调度过程还会调用该函数
_build_node_list//1.构建节点集
_get_req_features//2.选择最合适节点。可用节点位图由select_bitmap带回来,可用节点数保存在job_ptr→node_cnt_wag
_pick_best_nodes//输出第二条日志
_resolve_shared_status//确定作业是否可以共享节点。返回值1共享0独占
select_g_job_test//初始化select插件,SelectType=select/cons_res
select_p_job_test(src\plugins\select\cons_res\select_cons_res.c,输出第三条日志)
_test_only(三分支mode == SELECT_MODE_TEST_ONLY)
cr_job_test//作业创建时_select_nodes可以返回节点数,但是到这就释放并返回了,其实只是判断了下后面啥也没干。作业调度时会走里面六个步骤。
allocate_nodes//3.实际分配节点,创建作业时由于设置了test_only跳过该步。
sched_debug2
以上可以看出在创建作业过程中测试了可以获得作业可用节点的数量,作业可用节点位图由_get_req_features函数的参数select_bitmap带回来,位图转换成的节点的数量保存在job_ptr→node_cnt_wag。
这个过程中并没有为作业成功分配具体节点。需要继续分析后台调度和backfill调度代码。
作业调度执行时,会具体分配节点。 使用gdb跟踪代码,提交并创建作业结束后,可能执行schedule后台调度代码:
也可能执行backfill回填调度代码,
执行完调度代码后,作业会变成运行状态,说明被调度执行。
从上面三张截图可以看出来,调度的过程中还是会调用select_nodes函数为作业分配节点。
后台调度代码调用过程:
main(src\slurmctld\controller.c)
_slurmctld_background
schedule
_schedule/_sched_agent
select_nodes
_get_req_features
_pick_best_nodes
select_g_job_test
select_p_job_test
_run_now(mode == SELECT_MODE_RUN_NOW)
cr_job_test
回填调度代码调用过程:
init(src\plugins\sched\backfill\backfill_wrapper.c)
slurm_thread_create(&backfill_thread, backfill_agent, NULL);//创建回填调度代理线程
backfill_agent
_attempt_backfill
_try_sched//对应日志 backfill:entering _try_sched for JobId=11901178
select_g_job_test
select_p_job_test
_will_run_test(mode == SELECT_MODE_WILL_RUN)
cr_job_test
_start_job
select_nodes
_get_req_features
_pick_best_nodes//对应日志 _pick_best_nodes: JobId=11901178 idle_nodes 5 share_nodes 1528
select_g_job_test
select_p_job_test
_run_now(mode == SELECT_MODE_RUN_NOW)
cr_job_test
调度作业过程与创建作业过程不同,由于select_mode为false,_pick_best_nodes内部设置select_node为SELECT_MODE_RUN_NOW,select_p_job_test会走三个分支中的_run_now分支,分配成功的节点位图由select_bitmap带回。
在select_nodes函数中select_bitmap被保存在作业结构体的job_ptr->node_bitmap中,然后设置作业状态为RUNNING。之后调用allocate_nodes等函数为作业分配节点,然后继续走调度剩余流程。
作业调度过程中为作业分配节点资源时最终会调用cr_job_test:
cr_job_test
_verify_node_state//作用不大
_select_nodes//第一个是测试用,第二个实际选择资源
_get_res_usage//1.从每个可用节点获取此作业的资源使用情况,cpu_cnt重要
_can_job_run_on_node//返回此节点可以使用的cpu的数量以及可用于分配的资源的位图,问题大概率出在这个函数上
_allocate_cores
_allocate_sc//重要
//2.中间有一步根据_get_res_usage返回结果过滤掉所有资源不足的节点
_choose_nodes//3.为作业选择最佳节点
_eval_nodes(src/plugins/select/cons_res/job_test.c)//分配节点核心步骤
_log_select_maps//该步骤可以保存节点和核心位图到日志
_can_job_run_on_node返回此节点可以使用的cpu的数量以及可用于分配的资源的位图,可以在通过调试,看这个函数返回值。
比如已经为一个作业分配一些节点,并且部分节点占满全部32个核心的情况下,在下一次提交作业并调度执行该作业时会调用_can_job_run_on_node函数,此时可以观察遍历上述占满核心的节点时的返回值是否正常。
PS:
Slurm China社区,群里有很多大牛,感兴趣的同学可以加入。