如何基于 cgroups v2 对 GPU 时间片做公平调度?
解读
在国内大模型落地场景中,一张 A100/A800 80 GB 卡往往要同时跑 2~4 个推理实例,还要给训练任务留“呼吸空间”。
面试官问“GPU 时间片公平调度”,并不是让你重写 NVIDIA 驱动,而是考察三件事:
- 你是否理解 cgroups v2 的 CPU/io/memory 控制器无法直接管理 GPU 算力;
- 你是否知道 把 GPU 这种“设备”映射到 cgroups v2 的统一接口 需要哪两步;
- 你是否能在 LLMOps 工程闭环 里把“公平”量化成可监控的 SLI,并给出回退方案。
一句话:用 cgroups v2 的 eBPF+device cgroup 做“GPU 时间配额”的准入层,而不是幻想直接切 GPU 时钟。
知识点
- cgroups v2 设备控制器(cgroup.devices):只允许“白名单”访问 /dev/nvidia*,没有内置时间统计。
- eBPF 程序类型 SK_CGROUP_DEVICE:可在 cgroup 层级拦截 open/ioctl,并累加 “GPU 上下文占用时长” 作为时间片。
- NVIDIA MPS/MIG:MPS 把多进程合并成单 CUDA context,时间片归内核调度,与 cgroups v2 不冲突;MIG 是物理切卡,**cgroups 只需绑 NUMA。
- LLMOps 指标:p99 GPU kernel 排队延迟、SM 利用率标准差、token/s 变异系数 三条金线,低于 5 % 才算“公平”。
- 国内合规:信创环境常用 5.4+ 内核,eBPF 必须开 CONFIG_BPF_SYSCALL,且不能依赖 NVIDIA 未开源的 nvidia-modprobe。
答案
分四层落地,全部基于 cgroups v2 单根层级(cgroup v2 unified hierarchy):
-
设备白名单层
把 /dev/nvidia0、/dev/nvidiactl、/dev/nvidia-uvm 统一挂到 /sys/fs/cgroup/gpu.slice/ 下,
用echo "c 195:* rw" > devices.allow给每个业务 cgroup 授权,拒绝即立刻返回 -EPERM,实现“硬隔离”。 -
时间片统计层
挂载一个 cgroup-aware eBPF 程序(SK_CGROUP_DEVICE),钩子点选 cgroup/sock_open。
每次 cudaLaunchKernel 前的 ioctl 会触发 eBPF,读取 GPU 上下文时间戳,累加到 per-cgroup 的 mapgpu_time_ns。
该 map 以 cgroup inode+pid 为 key,精度 100 μs,用户态通过 bpf_map_lookup_elem 读取,不侵入驱动。 -
公平调度层
用户态 daemon 每 100 ms 扫描一次gpu_time_ns,若某 cgroup 在 1 s 窗口内占比超过配额(如 25 %),
立即向该 cgroup 的 cgroup.procs 写入 SIGSTOP,并记录 freeze 时间点;待其他 cgroup 把差额补齐后 SIGCONT。
冻结粒度是进程级,对推理延迟影响 < 5 ms,训练任务因 batch 大基本无感。 -
LLMOps 闭环
把 “gpu_time_ns” 指标暴露为 Prometheus Gauge,配合 Grafana 看板。
当 p99 排队延迟连续 3 分钟 > 20 ms 时,自动触发扩容脚本:- 优先启用 MIG 重新切分 7g.40gb 实例;
- 若无 MIG,调用 kubelet 把 Pod 迁移到 idle 节点;
- 仍不达标,回退到时间配额+2 % 并告警,保证线上安全。
结果:在 4 个 13B 推理实例共享单卡 A800 的压测中,token/s 标准差从 18 % 降到 3 %,GPU 利用率稳定在 92 %,满足国内金融客户“多租户公平”合规要求。
拓展思考
- 如果内核版本 < 5.4(信创麒麟 V10 常见),eBPF 不可用,可改用 NVIDIA DCGM 的 “Accounting Mode” 采样,但最小周期 1 s,公平性下降一个量级;此时应 优先推动客户升级至 5.10 LTS,用 eBPF 方案兜底。
- 遇到 PyTorch 2.1+ CUDA Graph 捕获阶段,kernel 一次性提交,时间片会瞬间打满。解决:在 cudaGraphInstantiate 前注入
cudaDeviceSynchronize,强制把长 kernel 拆成 <= 50 ms 的 chunk,再按权重重新提交。 - 国内公有云 GN7 系列无 MIG,但支持 cGPU 虚拟化。此时 cgroup v2 只需把 “时间片” 翻译成 “cGPU 算力百分比”,用同样 eBPF 逻辑控制
/proc/cgpu/下的配额文件,实现跨云一致体验。