Conversation
wlgys8
force-pushed
the
perf/fastsac-weight-ipc
branch
from
September 21, 2026 05:02
335d229 to
c5f13b3
Compare
…lots with size gate The async learner->collector weight snapshot paid multiple device<->host crossings per cycle: a per-tensor synchronous .cpu() flatten plus shm copies on publish, and shm -> pinned -> H2D on every collector sync. Large actors (~27M params / ~108MB fp32) measured ~70ms per publish and ~10ms per sync, bottlenecking both processes. - publish flattens params on-device into one contiguous vector and crosses to the host in a single pinned transfer. - when learner and collector inference share one GPU, the double-buffered slots live in device memory via CUDA IPC (one mp.Queue handoff at startup) and publish/sync become device-to-device copies. The seqlock protocol is unchanged: GPU slot writes are event-synced before the version bump, and reads synchronize before the seq re-check so a republish during an in-flight copy is retried instead of tearing the actor. - the slot transport is extracted into weight_slots.py strategies (HostShmWeightSlots / GpuIpcWeightSlots) that WeightSnapshot delegates to; host shm remains the fallback for CPU learners, CPU collector inference, or mismatched device indices. - async_options.weight_ipc (auto/on/off, default auto) with weight_ipc_min_bytes (16MB) gates the device path: benchmarks show IPC is a net loss for small actors (g1-wbt-dance ~1MB params: ~76k -> ~71k env-steps/s) because its stream synchronizations cost more than the sub-millisecond host transfer they avoid, while large actors gain publish ~70ms -> ~2.3ms, sync ~10.6ms -> ~0.6ms and ~45k -> ~61k env-steps/s. Only the slot tensors cross the IPC queue (the strategy object holds an unpicklable CUDA event); shared_cpu_tensor moves to weight_slots so both modules share one zero-initialized allocator.
wlgys8
force-pushed
the
perf/fastsac-weight-ipc
branch
from
September 21, 2026 05:25
c5f13b3 to
2c6e183
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
FastSAC async 两进程训练中,权重快照(learner → collector)走 host 共享内存,每个 publish/sync 周期涉及多次设备↔主机搬运:
publish:参数逐 tensor 同步.cpu()+ shm 拷贝sync(collector 侧):shm → pinned → H2D 三跳大 actor(~27M 参数 / ~108MB fp32)下实测单次 publish 高达 ~70ms、sync ~10ms,成为 learner/collector 两侧的共同瓶颈。
改动
1. publish 传输融合(
23a66f6)参数在设备侧 flatten 成一个连续向量,单次 pinned D2H 进 host 槽;learner 与 collector 推理同卡时,双缓冲槽直接驻留 GPU(CUDA IPC,启动时经
mp.Queue一次性握手),publish/sync 变为 device-to-device 拷贝。seqlock 协议不变(seq 计数器仍在 host shm;GPU 拷贝在版本发布前 event-sync 完成,读取侧同步后再复查 seq,防止撕裂)。2. 传输抽象 + 按体积自动选路(
335d229)把槽位传输抽成独立模块
weight_slots.py的两个策略:HostShmWeightSlots— 共享内存双缓冲 + 单次 pinned 传输(默认)GpuIpcWeightSlots— CUDA-IPC 设备双缓冲 + D2D 拷贝新增配置:
auto(默认):同卡且参数 ≥ 16MB 才走 IPC,否则 host 路径。为什么需要 size gate
基准测试发现 IPC 对小 actor 是负收益(其读写两端的流/事件同步比它们省下的亚毫秒级 host 传输更贵):
auto让小 actor 保持零回归,大 actor 自动拿到收益。实现细节
torch.cuda.Event,collector 侧重建)shared_cpu_tensor移入weight_slots,两模块共享同一个零初始化分配器测试
auto回落 host 路径(吞吐与 main 持平 ~76k),on强制设备路径(host_snapshot 归零)验证开关生效