# bst **Repository Path**: bane-dysta/bst ## Basic Information - **Project Name**: bst - **Description**: slurm-tui - **Primary Language**: Unknown - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-18 - **Last Updated**: 2026-09-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # banest — bane scheduler tui `banest`(**bane scheduler tui**)是一个基于 **C++17、FTXUI 和 JsonCpp** 的集群调度器终端交互客户端,支持 Slurm 和 Sun/Grid Engine(SGE)CLI backend。程序使用类型化领域模型、异步后端、snapshot diff、稳定选择和事件驱动 UI,在终端中查看作业状态、历史 accounting 信息、资源和调度器允许的作业操作。 ## 功能概览 - 作业选择绑定 `JobKey`,不依赖列表行号。刷新、排序和过滤不会把选择映射到其他作业。 - Slurm backend 的 ACTIVE 优先使用 `squeue --json`,必要时回退到固定字段的 `squeue` 文本查询;SGE backend 的 ACTIVE 使用 `qstat -r -xml`。HISTORY 分别使用 `sacct --parsable2` 和 `qacct -j`,RESOURCES 分别使用 `sinfo` 和 `qhost -q -xml`。命令输出只在 backend/decoder 边界解析,UI 使用类型化数据。 - JSON normalization layer 统一处理 Slurm JSON 中的标量、数组以及 `number/set/infinite` 包装对象。 - 每次 ACTIVE 刷新都会生成新的 snapshot,并与上一份 snapshot 比较,产生 Added、Removed、StateChanged、ReasonChanged、AllocationChanged、ExpectedStartChanged 等事件。 - 调度器操作由后台 `ActionExecutor` 执行;批量操作不会在 UI 回调中逐项调用外部命令。 - `!` 可在目标作业的工作目录中执行用户输入的 shell 命令,并支持有界并发、超时和取消。 - `o` / `O` 可跟随作业 stdout / stderr;日志进入 FTXUI 前会移除终端控制序列。 - JSON 文件和 replay backend 为只读模式,可在没有 Slurm 环境的机器上测试 parser、状态流、diff 和 UI。 - TUI 主线程不执行调度器 CLI。查询和操作由后台执行,调度器响应较慢时界面可以继续处理输入。 ## 主界面 宽终端使用 master/detail 布局:左侧显示作业表,右侧显示 Inspector。窄终端使用纵向布局。移动光标时 Inspector 会跟随当前作业。 主要按键: | 按键 | 功能 | |---|---| | `↑/↓`, `j/k` | 移动光标 | | `PgUp/PgDn`, `g/G` | 翻页 / 首尾 | | `Space` | 按 `JobKey` 多选 | | `A` | 全选/取消当前可见作业 | | `x` | 清空选择 | | `/` | 本地搜索 / 字段过滤 | | `f` | 状态组过滤 | | `s` / `S` | 切换排序字段 / 反转方向 | | `d` / `Enter` | 打开完整详情查看器 | | `:` / `a` | 打开 Action Palette | | `c` | 取消选中/当前作业(确认后执行) | | `!` | 在选中/当前作业的 WorkDir 中并发执行命令 | | `o` / `O` | 跟随 stdout / stderr | | `H` | 在 ACTIVE 与 HISTORY 页面之间切换 | | `R` | 在 ACTIVE 与 RESOURCES 页面之间切换 | | `Tab` | 按 ACTIVE → HISTORY → RESOURCES 顺序切换页面 | | `E` | 查看 ACTIVE snapshot 事件历史 | | `r` | 刷新当前页面;ACTIVE、HISTORY 和 RESOURCES 使用当前 scheduler backend 对应的查询 | | `p` | 暂停/恢复 ACTIVE 自动刷新 | | `h` / `?` | 帮助 | | `q` | 退出 | 鼠标操作: - 左键点击顶部 `ACTIVE` / `HISTORY` / `RESOURCES` 可切换页面。 - 左键点击作业、queue 或 node 行会移动当前光标;在 ACTIVE 作业行最左侧选择标记区域点击可切换多选。 - 右键点击 ACTIVE 作业行打开 Action Palette;右键点击 HISTORY 作业行打开详情;右键点击 RESOURCES 的 queue 行直接进入节点列表。 - 滚轮可滚动作业/资源列表、详情、Help、事件历史、命令结果和日志;在过滤器/Action Palette 中滚轮移动当前项。 - 状态过滤器和 Action Palette 的条目可直接左键点击;确认框中的确认与返回按钮也可点击。 Action Palette 提供 cancel、hold、release、requeue 和 signal。动作是否可用同时取决于目标作业状态和当前 scheduler backend;例如 SGE backend 不提供任意 signal 操作。 ## ACTIVE 与 HISTORY 程序启动进入 **ACTIVE** 页面。后台 Poller 使用所选 scheduler backend 查询当前作业。Slurm backend 优先使用 `squeue --json`,JSON serializer 不可用时自动切换到固定字段的 `squeue` 文本查询;SGE backend 使用 `qstat -r -xml -u `。 ![](assets/active.png) 按 `H` 或 `Tab` 进入 **HISTORY** 页面。CLI backend 在该页面需要数据时异步读取 scheduler accounting,默认查询最近 7 天。Slurm 使用 `sacct`,SGE 使用 `qacct`。HISTORY 不做周期轮询,按 `r` 手动重新加载。ACTIVE Poller 与 HISTORY loader 相互独立。 ![](assets/history.png) Slurm HISTORY 以 allocation 为单位显示作业,一作业一行,只保留 terminal jobs。查询同时读取 step accounting;`.batch`、`.extern` 和其他 `.` 记录不单独显示,其 `TotalCPU`、`MaxRSS`、`MaxVMSize` 等 utilization 数据会聚合到 parent allocation。SGE HISTORY 直接读取 `qacct -j` 的完成记录,并映射 `cpu`、`ru_maxrss`、`maxvmem`、`failed` 和 `exit_status` 等字段。 HISTORY 默认按结束时间倒序。`s` 可在 ID / NAME / STATE / RUNTIME / WAIT / CPU% / MAXRSS / END / SUBMIT 之间切换排序字段。中宽终端显示 `WAIT`、`CPU%`、`MAXRSS`;宽终端还显示 `TOTALCPU`、CPU 数、partition 和 end time。Inspector / details 展示 requested memory、TRES、eligible time 和 accounting step 数。 HISTORY 为只读页面,可使用搜索、过滤、排序、详情以及 stdout/stderr 路径查看;cancel、hold、release、requeue、signal 和 workdir command 不可用。 历史查询窗口可配置: ```bash ./build/bin/banest --history-days 30 ``` `Esc` 或 `H` 返回 ACTIVE;`E` 打开 ACTIVE snapshot 事件历史。 按 `R` 进入 **RESOURCES** 页面。一级列表只显示 queue 汇总,包括可用状态、最大时限、节点状态分布、CPU `allocated/idle/other/total` 和内存总量。选中 queue 后按 `Enter` 进入节点列表;`Esc` 返回 queue 列表。 节点列表显示 state、CPU 状态、节点内存、OS 报告的空闲内存、GRES 或不可用原因。按 `f` 可按 idle、mixed、allocated、unavailable、other 状态组过滤;`s` 切换排序字段,`S` 反转排序方向。OS 空闲内存只用于观察节点当前内存压力,不代表调度器可立即分配的内存。 RESOURCES 首次进入时异步加载,之后按 `r` 手动刷新,不做周期轮询。cluster 总量按唯一节点统计;节点属于多个 queue 时,会分别计入各 queue 容量,但不会重复计入 cluster 总量。ACTIVE Poller 在 RESOURCES 页面打开期间继续运行。 `Tab` 按 ACTIVE → HISTORY → RESOURCES 顺序循环。HISTORY 按 `Esc` 返回 ACTIVE;RESOURCES 节点列表按 `Esc` 返回 queue 列表,再按一次 `Esc` 返回 ACTIVE。 ## 搜索 `/` 输入框直接操作本地 snapshot,不访问 Slurm。普通文本会匹配常用字段,也支持 `field:value` token,例如: ```text /test2 /state:running /name:coumarin state:pending /partition:qdhcnormal /node:dcu13 /reason:resources /cwd:/work/home /exit:1:0 /maxrss:32 /cpueff:80 /wait:01:20 ``` ## Backend `banest` 启动时读取 `~/.bane/st/banest.conf`。用 `scheduler` 选择 live scheduler: ```ini scheduler=slurm ``` 或: ```ini scheduler=sge ``` 配置文件不存在或没有 `scheduler` 时使用 Slurm。`--scheduler slurm|sge` 可临时覆盖配置文件。 Slurm 环境可以在同一个配置文件中指定 `squeue` 可执行文件。未设置时从 `PATH` 查找 `squeue`: ```ini scheduler=slurm squeue=/software/slurm/bin/squeue ``` `squeue` 的值是可执行文件名或路径,不包含额外参数,也不经过 shell 展开。 ### Slurm CLI backend ```bash mkdir -p ~/.bane/st printf 'scheduler=slurm\n' > ~/.bane/st/banest.conf ./build/bin/banest ./build/bin/banest --user gaus30 --refresh 5 ``` 未配置 `squeue` 时,PATH 中需要提供 `squeue`;此外 PATH 中还需要提供 `sacct`、`sinfo`、`scontrol` 和 `scancel`。 ACTIVE 优先通过 `squeue --json` 查询作业。JSON serializer 不可用时,CLI backend 使用 `squeue --local --array --noheader -o `;字段之间使用 ASCII Unit Separator (`0x1f`) 分隔。文本模式保留作业 ID、名称、状态、reason、用户/账户、partition/QoS、priority、CPU/节点、内存显示值、提交/开始/结束时间、time limit、dependency、WorkDir 和 command。HISTORY 通过固定字段的 `sacct --parsable2` 查询 allocation 和 step accounting,并在 decoder 中聚合为 allocation 级记录。RESOURCES 在 Slurm CLI backend 中使用 `sinfo --local --all --Node --exact --noheader -o ` 查询 queue/node 资源,字段同样使用 ASCII Unit Separator (`0x1f`) 分隔。Slurm 操作使用 argv + `fork/exec`,不通过 shell 拼接命令。 ### SGE CLI backend ```bash mkdir -p ~/.bane/st printf 'scheduler=sge\n' > ~/.bane/st/banest.conf ./build/bin/banest ./build/bin/banest --user sun --refresh 5 ``` 临时切换 scheduler 时可以直接使用 `--scheduler sge` 或 `--scheduler slurm`,命令行值优先于配置文件。 PATH 中需要提供 `qstat`、`qacct`、`qhost`、`qdel`、`qhold`、`qrls` 和 `qmod`。 ACTIVE 使用 `qstat -r -xml -u `。`JB_job_number`、`JB_name`、`JB_owner`、SGE state、`JAT_prio`、slots、提交/启动时间以及 `queue@host` 会映射到统一的 Job model;`hard_request` 中的 memory request 和 `h_rt` 在存在时也会保留。SGE 的小数 priority 会按原值显示和排序。`qw`/`hqw`/`r` 等状态在 decoder 中归一化,同时保留原始 state detail。 HISTORY 使用 `qacct -j -o -b `。queue、host、project、slots、提交/启动/结束时间、`failed`、`exit_status`、`cpu`、`ru_maxrss`、`maxvmem` 和 `category` 会映射到历史作业;`category` 中常见的 memory request 也会显示在 memory 字段。 RESOURCES 使用 `qhost -q -xml`。queue instance 的 slots/used/reserved 用于 queue 和 node 的 CPU 状态,execution host 的 processor/memory 数据用于 cluster 汇总。SGE queue state 非空时会在节点页标为 unavailable,并保留原始 queue state 作为原因。 SGE 作业操作对应为 `qdel`(cancel)、`qhold`(hold)、`qrls`(release)和 `qmod -rj`(requeue/reschedule)。任意 UNIX signal 没有映射到 SGE backend,因此该动作在 Action Palette 中禁用。`qmod -rj` 是否允许普通用户执行由集群权限和 rerun 配置决定,失败信息会直接显示在状态栏。 SGE 的 `qstat -r -xml` 输出不保证包含 WorkDir 或 stdout/stderr 路径。缺少这些字段时,workdir command 和日志跟随不会伪造 Slurm 路径,而是保持不可用。 ### 单 JSON 快照(只读) ```bash ./build/bin/banest --json-file sample.json --paused ``` 该模式用于查看保存的 `squeue --json` 快照并检查 parser、布局、搜索和过滤。Slurm 写操作与 workdir shell 命令均禁用。 ### 生命周期 replay(只读) ```bash ./build/bin/banest --replay tests/fixtures/lifecycle --paused ``` replay 按自然文件名顺序读取快照。按 `r` 前进一帧,可观察 PENDING → RUNNING、RUNNING → COMPLETED、Added 等 snapshot 事件。使用 `--replay-loop` 可循环播放。 ## 构建 FTXUI 和 JsonCpp 位于 `third_party/`,默认构建不需要在线下载依赖: ```bash cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build -j ctest --test-dir build --output-on-failure ./build/bin/banest --replay tests/fixtures/lifecycle --paused ``` 也可以运行: ```bash ./build.sh ``` 如需使用系统安装的依赖: ```bash cmake -S . -B build \ -DSLURM_TUI_USE_BUNDLED_DEPS=OFF \ -DCMAKE_BUILD_TYPE=Release ``` ## 命令执行模型 `!` 是面向用户输入的 shell 功能。命令在每个目标作业可用的工作目录下通过 `$SHELL -lc` 执行。Slurm 和 SGE backend 的调度器命令都使用 argv 执行,不经过 shell。 批量命令使用有界并发,默认并发数为 4;单作业默认超时为 120 秒: ```bash ./build/bin/banest --command-parallel 8 --command-timeout 300 ``` `Esc` 可取消正在执行的 batch。Process 层为子进程建立独立 process group,取消时发送 TERM,并在需要时发送 KILL。子进程 stdin 默认连接 `/dev/null`。 ## JSON 时间语义 Slurm 的 `start_time` 在 PENDING 作业中可表示预计启动时间。Domain model 将实际启动时间和预计启动时间分开表示: - `Job::ActualStart()`:运行态和终态作业的实际开始时间; - `Job::ExpectedStart()`:PENDING / REQUEUED 作业的预计启动时间; - `Job::Elapsed()`:基于 `ActualStart()` 计算运行时间; - `Job::QueueAge()`:基于 submit time 计算排队时间。 相关测试覆盖 PENDING expected-start 与 RUNNING actual-start 的时间语义。 ## 测试 `tests/test_main.cpp` 覆盖: - JsonCpp normalization:标量、数组 state、typed number wrapper; - 7 份生命周期快照解码; - PENDING expected-start 与 RUNNING actual-start 语义; - snapshot diff 的状态变化和新增作业; - `JobKey` selection 在刷新、排序和过滤后的稳定性; - replay 自然排序与当前位置; - process cwd、超时基础路径、stdin 隔离; - 终端控制序列清洗; - bounded command executor; - Slurm array `JobKey` 与 `%A/%a/%j/%x` 日志路径展开; - `sacct --parsable2` 解码,包括 allocation/step 聚合、`TotalCPU`、`MaxRSS`、`ReqMem`、`CANCELLED by `、`code:signal` 与 terminal-state 过滤; - `squeue` 固定字段文本解码、JSON 失败后的自动 fallback,以及 fallback 模式缓存; - scheduler resource 固定字段文本解码、queue 聚合、唯一节点 cluster 总量、state filter、资源排序和 CLI 查询参数; - SGE `qstat -r -xml` 解码,包括 running/pending/held state、queue@host、slots、小数 priority 和 resource request; - SGE `qacct -j` accounting 解码,包括 completed/failed、exit status、CPU、RSS/VM 和 category memory request; - SGE `qhost -q -xml` 资源解码,以及 qstat/qacct/qhost/qmod 的 CLI argv 回归; - HISTORY accounting 排序与字段过滤。 构建与伪终端 smoke test 记录见 [`BUILD_VERIFICATION.md`](BUILD_VERIFICATION.md)。 ## 工程结构 ```text include/slurm_tui/ ├── app/ AppState / snapshot / async runtime / Application ├── domain/ Job, JobKey, JobState ├── process/ fork/exec process runner ├── sge/ qstat/qacct/qhost decoders + SGE CLI backend ├── slurm/ backend interface + squeue JSON/text / sacct accounting decoders ├── ui/ FTXUI dashboard / dialogs / viewers └── util/ src/ ├── app/ ├── domain/ ├── process/ ├── slurm/ ├── ui/ └── util/ tests/ ├── fixtures/lifecycle/ 7 个生命周期快照 ├── fixtures/typed-regression.json └── test_main.cpp ``` 线程模型、状态流和扩展边界见 [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)。