使用Slurm运行任务#
上一节中 pre_data2grib2 任务在 ecFlow 服务所在的登录节点运行。 登录节点不适合运行大量的任务,本节中我们将使用 slurm 运行 pre_data2grib2 任务。
本节将介绍如何在 HPC2023 的串行节点上运行 ecFlow 任务,介绍 ecFlow 通过何种方式实现与 HPC 队列调度系统 Slurm 的对接。
修改工作流定义#
更新 ${TUTORIAL_HOME}/def 中的工作流定义文件 cma_gfs_post.py:
1import os
2
3import ecflow
4
5
6def slurm_serial(class_name, wckey):
7 variables = {
8 "ECF_JOB_CMD": "slsubmit6 %ECF_JOB% %ECF_NAME% %ECF_TRIES% %ECF_TRYNO% %ECF_HOST% %ECF_PORT%",
9 "ECF_KILL_CMD": "slcancel4 %ECF_RID% %ECF_NAME% %ECF_HOST% %ECF_PORT%",
10 "CLASS": class_name,
11 "WCKEY": wckey,
12 }
13 return variables
14
15
16current_path = os.path.dirname(__file__)
17tutorial_base = os.path.abspath(os.path.join(current_path, "../"))
18def_path = os.path.join(tutorial_base, "def")
19ecfout_path = os.path.join(tutorial_base, "ecfout")
20program_base_dir = os.path.join(tutorial_base, "program/cma-gfs-post-program")
21run_base_dir = os.path.join(tutorial_base, "workdir")
22
23defs = ecflow.Defs()
24
25with defs.add_suite("cma_gfs_post") as suite:
26 suite.add_variable("PROGRAM_BASE_DIR", program_base_dir)
27 suite.add_variable("RUN_BASE_DIR", run_base_dir)
28
29 suite.add_variable("ECF_INCLUDE", os.path.join(def_path, "include"))
30 suite.add_variable("ECF_FILES", os.path.join(def_path, "ecffiles"))
31
32 suite.add_variable("ECF_DATE", "20230806")
33 suite.add_variable("HH", "00")
34
35 with suite.add_task("pre_data2grib2") as tk_pre_data2grib2:
36 tk_pre_data2grib2.add_variable(slurm_serial("serial", "105-09"))
37
38print(defs)
39def_output_path = str(os.path.join(def_path, "cma_gfs_post.def"))
40defs.save_as_defs(def_output_path)
新增代码说明:
- 6-13 行:定义函数
slurm_serial,定义了提交 SLURM 串行作业需要的一些 ecFlow 变量: ECF_JOB_CMD:提交作业脚本的命令ECF_KILL_CMD:终止作业脚本运行的命令CLASS:队列名,会在 include 头文件中使用WCKEY:wckey,会在 include 头文件中使用
- 6-13 行:定义函数
35-36 行:修改 pre_data2grib2 提交方式
运行 cma_gfs_post.py 脚本,生成新的 cma_gfs_post.def 文件:
python3 cma_gfs_post.py
新 cma_gfs_post.def 文件如下:
#5.10.0
suite cma_gfs_post
edit PROGRAM_BASE_DIR '/g7/JOB_TMP/wangdp/tutorial/ecflow/program/cma-gfs-post-program'
edit RUN_BASE_DIR '/g7/JOB_TMP/wangdp/tutorial/ecflow/workdir'
edit ECF_INCLUDE '/g7/JOB_TMP/wangdp/tutorial/ecflow/def/include'
edit ECF_FILES '/g7/JOB_TMP/wangdp/tutorial/ecflow/def/ecffiles'
edit ECF_DATE '20230806'
edit HH '00'
task pre_data2grib2
edit ECF_JOB_CMD 'slsubmit6 %ECF_JOB% %ECF_NAME% %ECF_TRIES% %ECF_TRYNO% %ECF_HOST% %ECF_PORT%'
edit ECF_KILL_CMD 'slcancel4 %ECF_RID% %ECF_NAME% %ECF_HOST% %ECF_PORT%'
edit CLASS 'serial'
edit WCKEY '105-09'
endsuite
# enddef
更新工作流#
运行 cma_gfs_post.py 生成新的 def 文件不会自动更新 ecFlow 服务里的工作流,需要手动将 def 文件加载到 ecFlow 服务中。
当我们直接使用 ecflow_client 加载 def 文件时,会报错:
cd ${TUTORIAL_HOME}/def
ecflow_client --host login_a13 --port 43083 --load cma_gfs_post.def
报错信息如下:
Error: request( --load=cma_gfs_post.def ) failed! Server reply: Add Suite failed: A Suite of name 'cma_gfs_post' already exist
提示已经存在名为 cma_gfs_post 的 suite,无法加载 def 文件。
这种情况下,我们可以使用 replace 命令替换 ecFlow 服务中已加载的工作流。
ecflow_client --host login_a13 --port 43083 --replace /cma_gfs_post cma_gfs_post.def
重新加载工作流定义后,suite 会立即运行,但 pre_data2grib2 运行报错:
这是因为没有为 pre_data2grib2 任务添加 Slurm 需要的注解设置,所以 Slurm 无法运行脚本。
备注
如果不希望重新加载工作流后任务自动运行,可以将 suite 节点 cma_gfs_post 挂起 (suspend)。 处于挂起状态下的工作流不会自动运行任务。
右键单击 cma_gfs_post,选择 Suspend。
创建头文件#
为使用串行队列的任务创建一个头文件,包含提交串行作业需要的 Slurm 指令。
在 ${TUTORIAL_HOME}/def/include 中创建头文件 slurm_client.h:
## This is a head file for Slurm serial job.
#SBATCH -J GRAPES
#SBATCH -p %CLASS%
#SBATCH -o %ECF_JOBOUT%
#SBATCH -e %ECF_JOBOUT%.err
#SBATCH --comment=GRAPES
#SBATCH -t 00:60:00
#SBATCH --no-requeue
#SBATCH --wckey=%WCKEY%
修改任务脚本#
在 ${TUTORIAL_HOME}/def/ecffiles 中修改 ecf 脚本 pre_data2grib2.ecf:
1#!/bin/ksh
2%include <slurm_serial.h>
3%include <head.h>
4%include <configure.h>
5
6date
7
8#=======================
9forecast_hour=024
10
11#=======================
12# ...skip...
在 ecFlowUI 上查看运行结果:
可以看到任务被提交到 Slurm 队列中,ECF_RID 变量保存 Slurm 作业号。