Skip to content

perf(env): collapse duplicate action/control scalar syncs on collector hot path - #2486

Merged
TATP-233 merged 1 commit into
mainfrom
perf/issue-2482-action-scalar-reads
Oct 21, 2026
Merged

TATP-233 merged 1 commit into
mainfrom
perf/issue-2482-action-scalar-reads

Conversation

@TATP-233

Copy link
Copy Markdown
Collaborator

摘要

#2482 的部分前置清理。无 MPS 的 CUDA 载体下,collector/learner 双 CUDA context 切换会放大 apply_action 路径上的每一次 blocking scalar read。本 PR 移除其中重复的两处:

  • TorchEnv._validate_control:此前每步对全 control 执行 torch.isfinite(control).all() 后立即 bool() 读取(硬同步)。
  • ActionManager.process_action(reuse_recorded_verdict=True):step() 已记录 device verdict,manager 重用路径又对同一个 0-d bool 做 bool()(第二次硬同步)。

修复方式:reuse 路径只记录不读取;JointPositionAction 为 affine 目标保留一个 device-resident verdict;TorchEnv._validate_control 在 control-validation 边界发布 manager verdict —— fail-closed 合同不变,但每步只读一次小 verdict 而非全 control reduction 读。verdict 每步清空,不跨步泄漏。

保留的行为边界(调研发现,未改变)

clip 生效时 +Inf raw action 会先被 clamp 成有限值(如 1.0),随后 raw-based 的 validate_actions() 仍按 raw Inf 抛错 —— 现状合同为"raw 严格,applied 宽松"。本 PR 沿用该语义,未引入新漏洞。

Benchmark(无回归)

本机 RTX 4090、无 MPS、mujoco SAC g1_walk_flat、seed=1、2048 envs、3 blocks × 200 iters、tail-100;A/B 成对(仅 stash envs/mdp/actions.py 切换):

Arm steps/s (3 blocks) apply_action (tail-100)
baseline 65.2k / 66.3k / 64.2k(mean 64.9k) 5.94 / 5.26 / 5.90(mean 5.65 ms)
patched 63.8 / 66.9 / 63.8(mean 65.2k) 5.94 / 5.20 / 5.57(mean 5.57 ms)

吞吐 +0.5%、apply_action −0.08 ms,均在噪声内且方向一致(非回归)。

范围说明(不关闭 #2482)

issue 的验收目标(88k steps/s、apply_action 0.4 ms)未由本 PR 达成,剩余 no-MPS 惩罚归因于本 PR 范围之外:

  1. learner→collector action 发布使用 non_blocking=False(double_buffer_runner.py:1149);
  2. HOST_BRIDGE write_control 的每步硬 synchronize(unisim tensor_io.py)。

这两项需后续 PR 处理;本 PR 定位为该路径的前置清理,保持 benchmark 归因干净。

验证

  • make check ✅(ruff / mypy / pyright)
  • make test ✅ 2718 passed
  • make test-all ✅(34/34 module-mode + 35/35 script-mode)
  • 新增测试:tests/base/test_torch_env.py 2 个用例(manager verdict fail-closed、verdict 不跨步泄漏)

Closes 部分推进 #2482(issue 保持 open,剩余两项在范围说明中列出)。

…r hot path

Issue #2482 partial groundwork. CUDA-carrier runs without MPS expose every
blocking scalar read on the apply_action path to dual-CUDA-context switching
overhead. The collector step previously performed two hard bool() reads of
0-d finite verdicts per step:

- TorchEnv._validate_control ran torch.isfinite(control).all() and read the
  scalar every step.
- ActionManager.process_action(reuse_recorded_verdict=True) re-read the
  verdict that step() had already recorded.

The reuse path now records without reading, and JointPositionAction keeps one
device-resident verdict for its affine target. TorchEnv._validate_control
publishes the manager verdict at the control-validation boundary, so the
contract stays fail closed with one small verdict read instead of a full
control reduction read. The verdict is cleared per step and never leaks.

Benchmark parity was confirmed locally (RTX 4090, no-MPS, mujoco SAC
g1_walk_flat, 2048 envs, 3x200 iters, tail-100; A/B by stashing only
actions.py): baseline 64.9k steps/s / 5.65 ms apply_action vs patched
65.2k / 5.57 ms. The remaining no-MPS apply_action penalty is attributed
outside this change (learner action publication non_blocking=False and
host-bridge write_control hard sync) and is tracked for follow-up work.
@TATP-233
TATP-233 merged commit 9b7acd0 into main Oct 21, 2026
12 checks passed
@TATP-233
TATP-233 deleted the perf/issue-2482-action-scalar-reads branch October 21, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant