Skip to content

Work: SAC/MuJoCo 单卡 collector CPU 利用率仅 ~48%——BatchEnvPool 默认 2×CPU 线程超订 + 串行 host 相占 1/3 墙钟 #1328

Description

@TATP-233

Work type: benchmark / perf Area: mujoco 规模预估: Small(选项 A:1–2 文件,≤50 行手写)

1. 一句话问题

单卡 sac + g1_motion_tracking + mujocoalgo.num_envs=4096 稳态训练时整机 CPU 占用只有 ~48%:MuJoCo BatchEnvPool 默认起 2×cpu_count 个 worker(本机 64 线程 / 16 物理核),物理相在 ~16–20 核即被内存带宽饱和,同时每个 collector cycle 约 1/3 墙钟花在只用 1–4 核的串行 host 相(update_state / reset_done / replay 写入 / 等 learner 动作),两者叠加把平均利用率结构性拉到 50% 以下。

2. 为什么现在做(实测证据)

机器:Xeon w5-3435X(16 物理 / 32 逻辑核)+ RTX 6000 Ada;commit f734cabe(基线分支 dev/issue-1304-motion-numba-body-state)。
复现:uv run train --algo sac --task g1_motion_tracking --sim mujoco algo.num_envs=4096(诊断时加 training.trace_enabled=true)。

稳态训练(400 iter,cycle 77.2ms,26540 steps/s):

证据 数值
/proc/stat 整机 CPU 47.5–49.2%
collector 进程 ~14.3 核(102 线程)
learner 进程 ~0.5 核;每 iter 等 collector 数据 43.2ms,自身更新 38.0ms(与 collector env step 重叠)
collector cycle 构成 env_step 72.7ms(94%)+ 等 learner 动作 7.7ms + replay 写入 2.0ms

env.step 分相归因(独立进程,4096 envs,随机动作 → reset 偏重,150 步均值;绝对值与真实训练不同,看比例与核数):

配置 backend_step update_state reset_done 整步
默认 64 线程 78.5ms @ 20.6 核 20.7ms @ 1.8 核 11.8ms @ 4.1 核 113.2ms @ 15.0 核
32 线程(cpu_ids=0–31) 59.5ms @ 27.2 核 12.3ms @ 1.9 核 9.1ms @ 3.7 核 82.2ms @ 20.4 核,steps/s +38%

pool 裸测(G1 scene_flat.xml,4096 envs × 3 substeps,无 env 语义):

nthread 64 默认不绑定 32 不绑定 32 pinned 24 pinned 16 pinned 8 pinned
ms/step 77.6 69.9 69.7 72.9 73.2 141.7
实占核 25.1 29.9 30.3 23.6 15.8 8.0

结论:

  • 收益来自线程数而非绑定(32 不绑定 ≈ 32 pinned);64 线程比 32 慢 11%,超订纯亏。
  • 物理吞吐在 ~16 物理核饱和(16→32 线程仅 +5% wall):CPU% 上不去首先是内存带宽瓶颈,其次是串行 host 相摊薄。追“100% CPU”不是本 issue 目标。
  • 代码事实:src/unilab/base/backend/mujoco/backend.py:355 默认 nthread = min(num_envs, 2*cpu_count)(沿用早期 rollout 惯例;曾经的 UNILAB_MUJOCO_STEP_THREADS 旋钮在 ab9614fa 被移除,未见调优依据);EnvCfg.cpu_ids 仅由多卡 DP 路径注入(src/unilab/ipc/dp_launcher.py:128 单卡返回 None),单卡用户没有配置入口。

诊断脚本(可复现以上各表):见评论区链接的分支 scripts/benchmark/env/ 下两个新脚本。

3. 最小交付结果

把单卡(cpu_ids=None)默认 pool 线程数从 2×cpu_count 收敛到有效 CPU 数(建议 len(os.sched_getaffinity(0)),尊重 taskset/cgroup),本机该 task 物理相预期提速 ~10%(独立 env 基准整步 +38%,真实训练受串行 host 相稀释会更低)。两个真实候选:

  • A(推荐):改默认 sizing 一行 + 更新受影响单测。规模 Small,长期维护成本为零。
  • B:扩展 chunk_tuner 做 (nthread, chunk_size) 联合 autotune(沿用 adaptive_chunk_size 的 cache 机制),逐机自适应;但要动 tuner,规模升 Standard,留作后续。

4. In scope

  • src/unilab/base/backend/mujoco/backend.py 默认 _n_threads sizing 规则(仅 cpu_ids is None 路径)。
  • 受影响既有单测更新 + 一条 sizing 规则单测。
  • 用复现命令在同机验证稳态 steps/s 与 CPU 占用前后对比。

5. Non-goals

6. Owner 与预计改动

  • Owner layer:src/unilab/base/backend/mujoco(backend 适配层)。
  • 预计 1–2 文件、≤50 行手写(选项 A),1 个 PR;执行 owner 待 maintainer 指派。

7. Acceptance criteria

  • 单卡默认 nthread == min(num_envs, 有效 CPU 数);显式 cpu_ids 时仍为 len(cpu_ids)
  • make check 与受影响单测通过;chunk tuner 因 cache key 含 nthread 自动重调,无脏 cache。
  • 同机复现命令稳态 steps/s 提升(预期 ≥5%),issue/PR 中记录前后对比数据。

8. Stop conditions

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:benchmarkBenchmark recording and evaluation workflowarea:mujocoMuJoCo related workenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions