Skip to content

perf: UniSim 1.4.0→1.5.1 后 MuJoCo collector 吞吐下降 36%–43%,定位并优化状态更新开销 #1602

Description

@TATP-233

问题与目标

在相同 UniLab 代码、任务和依赖环境下,将 unisim-core1.4.0 切换到 1.5.1,本机 Linux/Ryzen 的 MuJoCo collector 活跃窗口吞吐在三个任务均下降:Go2 36.47%–42.57%、G1 平地 18.84%–21.60%、G1 motion tracking 18.93%–20.56%。主要耗时增量出现在状态更新阶段;需要定位具体调用、重复工作及串行成本,并在保留新版状态正确性的前提下优化。

本 issue 跟踪性能回退的归因与修复。依赖更新和初始 Go2 测量由 #1601 提供;M2 下游消费另见 #1599。这里没有混入 M2 消费代码,也没有使用 1.5.0 作为性能基线。

本机三任务合并实测(Linux / Ryzen)

参考 macOS / Apple M5 Max 三任务独立复测,现补充本机 flashsac/g1_walk_flat/mujocosac/g1_motion_tracking/mujoco,与原 Go2 合并成六行表。本表全部是本机 Linux 数据,不混入 Mac 数值。 Mac 与 Linux 的绝对吞吐不能直接横比;只有各自同机 A/B 的相对变化有效。

测量使用同一 UniLab 84a00d049eeac9292bbd58c25fcd06a4b64cd712 的既有 scripts/benchmark/rl/benchmark_offpolicy_collector_active.py。两版只切换 UniSim,逐次核对其余 133 个包版本完全一致;原 Go2 与补测 G1 的 benchmark 文件 hash 也一致。原 Go2 12 次与本轮 G1 24 次分批执行,合计 36 次,并非同一连续测量会话。

吞吐

单位为 环境 transition/s,每格是三次独立进程运行的中位数及最小—最大范围;不是 physics substep/s 或训练端到端吞吐。

任务 环境数 UniSim 1.4.0 UniSim 1.5.1 中位数变化
go2_joystick_flat (flashsac) 1024 138,780(131,699–141,773) 88,167(82,537–89,607) -36.47%
go2_joystick_flat (flashsac) 4096 209,773(206,357–209,957) 120,476(117,284–120,949) -42.57%
g1_walk_flat (flashsac) 1024 42,775(42,736–43,039) 34,715(34,260–34,738) -18.84%
g1_walk_flat (flashsac) 4096 50,655(50,534–50,934) 39,716(39,661–39,957) -21.60%
g1_motion_tracking (sac) 1024 41,053(40,906–41,306) 33,282(32,692–33,612) -18.93%
g1_motion_tracking (sac) 4096 47,819(47,754–48,112) 37,987(37,978–38,086) -20.56%

三个任务的全部 18 组配对均下降,无丢弃计时样本;本轮两个 G1 任务的 12 组配对也全部下降。

分项

每次运行的 vector-step 阶段均值再取三次运行中位数,单位 ms/vector step;各列独立取中位数,不保证可直接相加。

任务 环境数 Physics,旧→新 Update state,旧→新 Replay,旧→新
go2_joystick_flat 1024 5.743 → 6.306 1.012 → 4.443 0.524 → 0.581
go2_joystick_flat 4096 16.344 → 16.811 2.482 → 15.994 0.465 → 0.941
g1_walk_flat 1024 20.568 → 20.646 1.015 → 6.378 0.412 → 0.405
g1_walk_flat 4096 72.713 → 73.232 2.675 → 24.114 1.100 → 1.084
g1_motion_tracking 1024 20.740 → 20.852 2.124 → 7.591 0.591 → 0.577
g1_motion_tracking 4096 73.607 → 73.915 7.219 → 28.697 1.244 → 1.310

Reset 计数与语义边界

下表是每次计量窗口内 reset 的环境行数总和;同任务、同规模、同版本的三次运行计数完全一致,因此只列一个数。不是 reset API 调用次数。

任务 环境数 UniSim 1.4.0 UniSim 1.5.1
go2_joystick_flat 1024 0 0
go2_joystick_flat 4096 0 0
g1_walk_flat 1024 6,158 6,163
g1_walk_flat 4096 24,496 24,672
g1_motion_tracking 1024 9,652 9,947
g1_motion_tracking 4096 39,143 40,039

Go2 的 12 次计量窗口 reset 全为零,原结论不变;两个 G1 任务存在 reset,所以 G1 吞吐不隔离 reset 路径。跨版本同 seed 下 reset 总数不同,说明轨迹/终止发生分叉,不能把旧版较高吞吐当作完全等价正确语义的上限。

G1 仍以 update state 为主要增量:4096 环境下平地从 2.675 → 24.114 ms,motion tracking 从 7.219 → 28.697 ms;对应 physics 仅为 72.713 → 73.232 ms73.607 → 73.915 ms。reset_done 阶段均值中位数分别为平地 3.798 → 4.068 ms、tracking 2.742 → 2.967 ms,不足以解释主要增量。此为分项观察,尚非具体函数的因果消融。

复现条件

  • Linux;AMD Ryzen 9 9950X3D2,固定进程及 MuJoCo worker 使用 CPU 0–7,共 8 个不同物理核;Torch、OpenMP、BLAS、Numba 线程均为 8。
  • Python 3.13.14、MuJoCo 3.11.0、mjbatch-uni 0.2.1、NumPy 2.4.4、Torch 2.8.0+cu128、unilab-rl 1.2.1。仿真及 replay 均在 CPU;本轮只测 MuJoCo。
  • algo.seed=1env.seed=1;全零动作;预热 30、计量 300 个 vector steps;replay 容量为 64 个 vector steps。
  • 每个任务、每个规模、每个版本三次全新进程串行执行。1024 顺序 A/B、B/A、A/B;4096 顺序 B/A、A/B、B/A,A=1.4.0、B=1.5.1。G1 两任务分别启动进程,无共享运行中的 env。
  • 指标为 N × 300 / Σ(env_step + replay + bookkeeping),包括环境、奖励/终止处理和 replay 写入;不含策略推理、learner 等待、跨进程 IPC、初始化或完整进程墙钟时间。
  • CPU affinity 不等于独占 CPU,后台负载、频率和温度未隔离。结论限于这些任务、规模和机器,不推广为所有任务的训练吞吐。
任务 Actor obs Critic obs Action
go2_joystick_flat 49 52 12
g1_walk_flat 98 101 29
g1_motion_tracking 160 289 29

G1 资产准备及此前失败的更新

此前在本机 1.4.0 预检发生过 G1 sensor XML 物化的 mesh 路径错误,原正文因此未列 G1。本次使用新的 detached 84a00d04 worktree 和独立 venv,经官方 asset hub 完成 G1 mesh/texture 与 motion 文件准备后,两任务的原版 1.4.0 均正常构造并完成全部正式运行。未修改 UniSim 包、任务 XML、physics 参数或热路径代码。

此前失败在本轮未复现,故以本轮实测补齐表格;尚未对先前失败原因做独立因果验证,不能据此宣称修复了 importer。Motion 文件为 motions/g1/dance1_subject2_part.npz,测量前后逐次核对资产 hash。

在隔离 checkout/venv 中使用上述 UniLab 提交与锁定的其余依赖,分别设置版本、任务、环境数及不同输出文件,按上述顺序重复:

uv sync --locked --extra mujoco
uv run unilab-pull-assets --robot g1
uv run python -c "from unilab.assets.hub import resolve_motion_files; print(resolve_motion_files('motions/g1/dance1_subject2_part.npz'))"
UNISIM_BENCH_VERSION=1.4.0
uv pip install --python .venv/bin/python --no-deps "unisim-core==$UNISIM_BENCH_VERSION"
taskset -c 0-7 env \
  UNILAB_COLLECTOR_TORCH_THREADS=8 OMP_NUM_THREADS=8 \
  OPENBLAS_NUM_THREADS=8 MKL_NUM_THREADS=8 NUMBA_NUM_THREADS=8 \
  CUDA_VISIBLE_DEVICES= MUJOCO_GL=disable \
  uv run --no-sync python scripts/benchmark/rl/benchmark_offpolicy_collector_active.py \
  --cases flashsac/g1_walk_flat/mujoco --num-envs 1024 \
  --warmup-steps 30 --measure-steps 300 --replay-capacity-steps 64 \
  --override algo.seed=1 --override '++env.seed=1' \
  --override '++env.cpu_ids=[0,1,2,3,4,5,6,7]' \
  --out-json /tmp/g1-walk-140-n1024-r1.json
# 第二任务改为 --cases sac/g1_motion_tracking/mujoco;另测 --num-envs 4096。
# 每版本每规模重复三次,使用不同输出文件。
uv sync --locked --extra mujoco

历史 1.4.0 不满足当前 manifest,故实验显式使用 --no-sync,结束后恢复隔离环境依赖;原有开发工作树及其环境未改变。

原始证据

原 Go2 12 次结果固定在 #1601 的提交 a9b8244e842ccdee63a7053ccaf8fc46429288af

本轮 G1 的 24 个 JSON、日志、精确命令、完整包版本和资产 hash 保存在本机 /home/user/ws/unilabsim/UniLab-1602-retest/scripts/benchmark/outputs/issue1602_g1_retest/runs.json 包含全部原始 payload,summary.json 为三任务合并统计。独立子代理核对了逐文件 SHA256、每次 300 个样本、样本均值和吞吐公式;所有检查通过。以下内嵌逐次吞吐和 reset 可直接复核正文的中位数/范围,不要求访问本机文件。

完整 G1 原始归档 g1_retest.raw.json.gz SHA256:b498fbcc74e1fd6895a2ccf524e7ce61e6d68fea7bb2af16328a805cfd7be817。Benchmark SHA256:317c91948a834cbd38795d9513c220334ef9b342432576b53cebdd331ae89d20

G1 24 次逐次吞吐、reset 与原始 JSON 校验值
任务 N 版本 重复 transition/s Reset 行数 JSON SHA256
g1_walk_flat 1024 1.4.0 1 42736.005277 6158 076fa4dac80389416e64f4c1a20031320eb284d96e7338c80d7f48550352d2b3
g1_walk_flat 1024 1.5.1 1 34714.837695 6163 4a241f0e24e956db952318d3badc3fbb6dce0163c765e9eb5d705e5371cc0c36
g1_walk_flat 1024 1.5.1 2 34259.803138 6163 621922c13ba7f489cc37e2a3379d459855e253f3fcd703a09d3bbb1e332fdd0b
g1_walk_flat 1024 1.4.0 2 43039.439821 6158 97806a64f34cb35fb1cc914f6a1e954d27dc96276bb5be965df56d8dc139eaff
g1_walk_flat 1024 1.4.0 3 42775.416628 6158 dd3c9c1bca730f2e3bc3a767e40cfd7d84ec8f97e6601371be6c78d09758c17f
g1_walk_flat 1024 1.5.1 3 34738.152077 6163 a15bfe94e9be8a2db9bcf70e1a81306b7150ec6dc5f24e2bbed4ff758cad98df
g1_walk_flat 4096 1.5.1 1 39956.962896 24672 6d1cfb3ebe83ec2c38294075685d321b9703b70dac7c3a08d47e4836387966d8
g1_walk_flat 4096 1.4.0 1 50655.150825 24496 1699de55b7fc65ad069127699941ce049a7f4f0f94d7049578afa0f7076d21b4
g1_walk_flat 4096 1.4.0 2 50934.410032 24496 db74f2d080ab2cec6ae812e0670fbc2642920ea3e474d333e7432a47e7d2b442
g1_walk_flat 4096 1.5.1 2 39715.998574 24672 de5af6ecc8107dff4c692c32c92b86374a7e8c3aa9c16d880bbde91efc139181
g1_walk_flat 4096 1.5.1 3 39661.126147 24672 833ef169fca783557c621fd96c4c8ae6d72cda2882503f2df2b380316806ee57
g1_walk_flat 4096 1.4.0 3 50533.818397 24496 686ba1720158d7713bb973d97ed39aa81f44c02cd153bcfee537b95e6495f097
g1_motion_tracking 1024 1.4.0 1 41053.237145 9652 aeb8cde2db4f8179b9027d37820cf6439171d84189a791fb153a161e6ca62174
g1_motion_tracking 1024 1.5.1 1 33281.549946 9947 c641f8e9ea3b7e2423cb1633f57422266b3b795962c667a7925f973e71a3dc68
g1_motion_tracking 1024 1.5.1 2 32691.520157 9947 b11efc0879f58ba88b4f434b987ed37d54e31f0d4d3ae7450dfca4ef972e6650
g1_motion_tracking 1024 1.4.0 2 41305.833860 9652 d7dd9c989897a205e51f1b6ec746deb381b263019cf14dbc2bd8c442c82d72c0
g1_motion_tracking 1024 1.4.0 3 40906.178672 9652 88d4cbb3aaa46300f3462259d494e1ad052385b7d1d06ebb61194aaa0f07a5f4
g1_motion_tracking 1024 1.5.1 3 33612.121268 9947 815a12622987ca12fe6924da4fb0e24d998a75561be460783c4397ffba32c197
g1_motion_tracking 4096 1.5.1 1 37977.540066 40039 302204095f5f43c587dd938c1fb475aa47e77e6e3464ad3b49e0ccaa0bd45a78
g1_motion_tracking 4096 1.4.0 1 47753.849639 39143 4c33717b6048eaf9c3e150c89f4c8587efd6002d9e692e23d9d5c2a63754c45c
g1_motion_tracking 4096 1.4.0 2 47819.411941 39143 72f0a67b9791e9073e2c88dcad22496824d3f808f48fa5a97794c1b28a74aa0e
g1_motion_tracking 4096 1.5.1 2 37987.164840 40039 c9f5b205831e69526bdef05f0c13c2eae7105e37983ef63d607bd223fa17d4fb
g1_motion_tracking 4096 1.5.1 3 38086.119789 40039 7d16ec93cb13bf0520da2cd9ea49f76b1230939333afceb3bf0ccb0936256de6
g1_motion_tracking 4096 1.4.0 3 48111.642216 39143 55a4bf87e09c117c35fcf695874e532bc55bf7009e4b1a93904ce5f99e29179c

初步定位:候选解释,尚非因果结论

已有后续评论将路径级 profile 与优化方案提交至上游 unilabsim/unisim#142。该归因证据与本轮三任务吞吐补测分开记录;本次没有运行该 cProfile,也没有实现性能修复。

UniSim v1.4.0…v1.5.1 差异包含状态正确性修复。新版 MuJoCo adapter 的 _sync_tracked_body_state() 在 step 后首次 body 查询时,对 dirty environment 执行最终运动学、速度及 tracking sensor 同步;旧版直接读取已有缓存。UniLab 的 body-state 消费路径会触发这些查询。

三个任务都观察到“Physics 变化较小、update state 增量较大”,与上述新增工作一致,但当前阶段计时不能独立证明某个函数是根因。需要测量调用次数、刷新行数、覆盖的 body/sensor、复制量与串行/原生执行成本,区分必要刷新和重复工作。1.5.1 修复了旧版可能滞后的读数,不能把 1.4.0 的较高吞吐直接当作等价正确语义的性能上限。

Owner、范围与实施边界

  • UniLab:collector benchmark、Manager-Based observation/reward 的公共状态消费,以及避免上层重复读取/复制。不得在 env 或训练代码中调用 backend 私有接口。
  • UniSim MuJoCo adapter:状态新鲜度、dirty/cache 生命周期、按需刷新与批量查询。若瓶颈需要原生并行或融合实现,由 mjbatch 的原生 owner 承担,不在 UniLab 重建 executor。
  • UniLab 的预期 PR base 为 main;依赖 build: pin UniSim 1.5.1 and compare MuJoCo collector throughput #1601,或在明确记录的隔离环境中固定正式 1.5.1 验证。上游修复各自向其仓库 main 提 PR,并在本 issue 关联。
  • 遵守 ADR-0007 包边界及父级 AGENTS.md:资产解析留在冷路径,后端行为位于 SimBackend 后;不引入第二 DR 生命周期、learner/collector 协议改造或新的常规性能 CI。

本 issue 不扩大到其他物理后端、GPU collector、大规模训练调参或 G1 历史资产导入修复。若需要新公共能力、生命周期或持久 benchmark 服务,先单独记录范围决定。

验收

  • 在相同任务、核数、seed 和依赖条件下复现 1.5.1 的开销,增加可审查的路径级 profile/A-B,证明具体瓶颈;额外插桩与正式吞吐测量分开,记录其开销。
  • 修复已确认的重复读取/复制/刷新或串行瓶颈,行为放在正确 owner;不通过关闭最终状态刷新、减少应有物理子步、丢弃终止/replay 工作或改变任务物理语义提高分数。
  • 以修复前的 1.5.1 正确语义为回归参考,覆盖连续 step 后 pose/velocity、按需/重复查询、partial reset 隔离,以及 callback 前和 step 后的新鲜度边界。接触/force sensor 的求解时刻不得被重算或覆盖成另一种语义。
  • 对上述三个任务同口径复测 N=1024、4096,至少各三次独立进程并交替顺序;报告吞吐中位数/范围、配对变化、physics/update/replay 分项和 reset 数量,给出可重复的改善。若仍未达到旧版数值,保留剩余差距与必要正确性成本的解释,不声称完全消除回退。
  • 更新报告、原始数据和修复 PR 链接;UniLab 最终 head 通过 make checkmake test-all 及 main PR 远程 CI,上游改动通过各自仓库门禁。仅测量 MuJoCo,不用 mock/skip 代替必需的真实运行结果。

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions