Skip to content

perf: env_step sub-stage timing panel + optional numba TBB layer (+23% throughput on many-core) - #72

Merged
wlgys8 merged 12 commits into
mainfrom
perf/console-env-step-substages
Sep 22, 2026
Merged

wlgys8 merged 12 commits into
mainfrom
perf/console-env-step-substages

Conversation

@wlgys8

@wlgys8 wlgys8 commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Summary

排查 g1-wbt-dance 训练 collector 卡点(env_step 29ms 中 transition 占 9.8ms)过程中落地的两类改进:

1. Console Timing 面板:env_step 子阶段树

  • TorchEnv.step 接入 Perf 打点(apply_action / physics / transition / reset),scope 命名与 ArrayEnv 一致
  • MotrixSim sim_data.execute()active_perf_scope("read") 记录原生批量读取,自动挂到调用方阶段下(transition / reset),无需修改任何具体环境
  • async collector 启用被包装 env 的 Perf,以点分路径上报子阶段;worker 重建嵌套树(标量 total 与子节点任意到达顺序均可合并,修复了先标量后子节点时的 learner 崩溃)

面板效果:按 2 切换 Timing 页后可直接看到 physics / transition(read) / evaluate / reset(backend_apply…) 的耗时与占比。

2. 多核机器的 OpenMP 唤醒风暴修复(可选 TBB 层)

根因链:evaluate 每次 wall 8.4ms 但 CPU 只有 ~30 个有效线程 —— OMP_WAIT_POLICY=PASSIVE 下 192 个 OMP 线程每次 kernel 调用都要唤醒,barrier 长尾支配 wall time;OMP ACTIVE 自旋更糟(与 physics 线程池抢核)。

  • motrix-env-core 新增 pinned tbb extra(tbb==2021.13.0),workspace 根暴露 --extra tbb
  • preload_tbb() 以完整路径 RTLD_GLOBAL 预加载 <venv>/lib/libtbb.so.12(PyPI wheel 不含 Python 模块,numba 裸名 CDLL 找不到库),ManagerEnv.__init__ 在首个并行 kernel 前自动调用;未安装 extra 时静默回退默认层

测量数据

场景 evaluate 吞吐
OMP 192 线程(修复前) 8.4 ms 132.5k steps/s
OMP 限 64 线程 1.4 ms 168.8k steps/s
TBB 192 线程(本 PR) 1.0–1.3 ms 163k steps/s (+23%)
本地 32 线程 OMP vs TBB 1.49 vs 1.52 ms 打平(小核数无唤醒问题)

Test plan

  • motrix_rl 全量测试(console 嵌套树渲染、collector 点分路径上报、worker 嵌套回归测试)
  • motrix_env_core 全量测试 + TorchEnv / perf 模块测试
  • 服务器(192 核 epyc-9004)端到端训练验证:自动启用 TBB、evaluate 1.16ms、零环境变量
  • 本地 32 核 OMP/TBB 对照确认小核数无回退

… layer

Console timing panel now breaks env_step down into env-internal sub-stages
(apply_action / physics / transition / reset / observation, with nested
detail such as transition -> read and reset internals), and an optional TBB
threading layer removes an OpenMP wakeup storm on many-core machines.

- TorchEnv: opt-in Perf instrumentation on step, mirroring ArrayEnv scope names
- MotrixSim sim_data.execute: active_perf_scope("read") nests under the
  caller's stage (transition/reset) without touching concrete environments
- async collector: enable the wrapped env's Perf, report sub-stage means as
  dotted paths; worker rebuilds them into the nested panel tree (folding
  scalar totals into nodes so either arrival order works)
- motrix-env-core: pinned tbb extra + preload_tbb() (full-path RTLD_GLOBAL
  preload of <venv>/lib/libtbb.so.12) called in ManagerEnv.__init__, so numba
  auto-selects the TBB layer without LD_LIBRARY_PATH; silent no-op otherwise
- workspace root exposes the tbb extra

Measured on g1-wbt-dance @4096 envs (192-core): evaluate 8.4ms -> 1.0-1.3ms
(OMP thread-wakeup storm, ~30 effective threads -> ~180), end-to-end
throughput 132.5k -> 163k env-steps/s (+23%). On 32-core machines the two
layers are equivalent (1.49 vs 1.52ms).
FastSacEnvWrap.env always exposes the original environment, so read it
directly; only the optional Perf capability stays probed. The collector
test fake now implements the .env contract instead of the production code
silently tolerating its absence.
…honest elapsed anchor

- console: Run progress card now shows elapsed and an ETA estimate (from
  the cumulative iteration rate); the plain-text header gains the same eta
- Perf.stage_mean_ms(root): per-call mean ms of every sub-scope under a
  root, keyed by dotted path — the tree-flattening moves next to the data
  structure and the collector only adds its env_step_ prefix
- async learner: anchor elapsed/ETA (and the first rate window) at the
  first ingested collector batch instead of learner readiness — the
  collector's env build (scene compile, numba JIT) can outlast the learner
  build by tens of seconds, which previously showed up as a large elapsed
  on the first panel
sync_wait_writer & friends become sync.wait_writer, and env_step stages
become env_step.physics.read — one protocol for all nesting. The worker
now rebuilds the panel tree with a single rule (split on '.') and zero
per-prefix special cases; the scalar-total folding already handles either
arrival order. TensorBoard scalar names and the async-trainer design doc
follow the same dotted form.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

There are a few confirmed correctness/documentation issues (Markdown inline-code formatting and ETA/duration formatting edge cases) plus a small performance improvement opportunity (cache preload_tbb()), which should be addressed before approval.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Medium severity · 2 Low severity

Open (3)
What changed in this PR

This PR adds richer, nested performance timing instrumentation across env stepping and async FastSAC training, and introduces an optional Intel TBB threading layer preload to avoid OpenMP wakeup overhead on many-core hosts.

Changes:

  • Add nested env_step sub-stage timing (apply_action/physics/transition/reset + MotrixSim read scope) and merge dotted-path timing into a stable tree in the async worker/panel.
  • Add optional tbb extra + installer flag to preload libtbb.so.12 (RTLD_GLOBAL) before numba parallel kernels run, improving throughput on many-core machines.
  • Extend tests to cover dotted-path timing flattening, tree rebuild order-independence, and collector reporting of env_step substages.
File Description
wiki/​design/​fastsac-async-heterogeneous-trainer.md Update design doc to describe dotted-path nested timing metrics.
uv.lock Add tbb package and expose workspace tbb extra wiring.
pyproject.toml Add workspace-level tbb extra that pulls in motrix-env-core[tbb].
motrix_env_core/​pyproject.toml Add tbb optional dependency extra (pinned).
install.sh Add --tbb flag to install optional TBB extra.
motrix_env_core/​src/​motrix_env_core/​numba/​threading.py Add preload_tbb() helper to preload TBB from <venv>/lib.
motrix_env_core/​src/​motrix_env_core/​numba/​manager/​env.py Call preload_tbb() early in ManagerEnv init (before parallel kernels).
motrix_env_core/​src/​motrix_env_core/​perf.py Add stage_mean_ms() to flatten nested scopes into dotted timing paths.
motrix_env_motrixsim/​src/​motrix_env_motrixsim/​torch_env.py Add Perf scopes to TorchEnv.step() with ArrayEnv-consistent stage names.
motrix_env_motrixsim/​src/​motrix_env_motrixsim/​sim_data.py Wrap simulator read execution with active_perf_scope("read").
motrix_rl/​src/​motrix_rl/​fastsac/​async_impl/​collector.py Report env Perf sub-stage timings as dotted paths under env_step.*.
motrix_rl/​src/​motrix_rl/​fastsac/​async_impl/​worker.py Rebuild nested timing trees from dotted-path keys; anchor elapsed time after first ingest.
motrix_rl/​src/​motrix_rl/​console.py Add ETA + elapsed/remaining text rendering in console panels.
motrix_rl/​tests/​test_fastsac_collector.py Add tests for collector dotted-path env_step sub-stage timing reporting.
motrix_rl/​tests/​test_fastsac_learner.py Add tests for timing-path nesting merge behavior (scalar vs children order).
motrix_rl/​tests/​test_console.py Update panel rendering tests for timing subtree + run-progress time text.
motrix_env_core/​tests/​test_perf.py Add tests for dotted-path flattening in stage_mean_ms().
motrix_env_core/​tests/​test_numba_threading.py Add smoke test for preload_tbb() returning bool without raising.
bench/​bench_learner_update.py Add standalone learner-update profiling script.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread motrix_rl/src/motrix_rl/console.py
Comment thread motrix_env_core/src/motrix_env_core/numba/threading.py
Comment thread wiki/design/fastsac-async-heterogeneous-trainer.md Outdated
- _format_duration: clamp negative inputs and document the 0m45s form
- preload_tbb: cache the probe result; ManagerEnv constructs per env and
  should not repeat the glob + CDLL work
- wiki: fix nested backticks breaking markdown rendering
Adds the option to the install reference table in both languages and a
short section explaining when the TBB threading layer matters (many-core
training servers) and that it auto-activates once installed.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The learner timing “anchor” resets last_log_time but not last_log_step, which can inflate the first logged throughput window after anchoring.

Review effort: Lite
Findings: None

Resolved since last review (3)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Reset last_log_step when anchoring the resumed start time

motrix_rl/​src/​motrix_rl/​fastsac/​async_impl/​worker.py:482

The start-time anchoring logic resets last_log_time but leaves last_log_step at the original resume_step, so the first logged steps_per_second window can be inflated (numerator counts steps since resume, denominator counts time since the first ingested batch). Reset last_log_step when anchoring so the first window rate matches the anchored time base.

@wlgys8
wlgys8 merged commit 7294afa into main Sep 22, 2026
6 checks passed
@wlgys8
wlgys8 deleted the perf/console-env-step-substages branch September 23, 2026 02:56
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.

2 participants