Skip to content

Use zero-copy ZMQ response relay - #1803

Merged
xeophon merged 1 commit into
feat/nano-as-v1from
codex/v1-zmq-zero-copy
Jun 21, 2026
Merged

Use zero-copy ZMQ response relay#1803
xeophon merged 1 commit into
feat/nano-as-v1from
codex/v1-zmq-zero-copy

Conversation

@xeophon

@xeophon xeophon commented Jun 21, 2026

Copy link
Copy Markdown
Member

Overview

Use zero-copy PyZMQ frames for V1 env-server responses and pool relays. The wire protocol, request routing, health handling, and response serialization remain unchanged; the PR only changes the two production transport files.

Why

Large training traces are already materialized once by msgpack. The previous transport path then copied the full payload when the worker server queued its response, copied it again when the pool received it as Python bytes, and copied it once more when the pool forwarded it to the client. Those payload-sized copies consume event-loop time, memory bandwidth, and transient RSS at the point where completed rollouts converge.

Changes

  • Send the packed server response with copy=False, allowing PyZMQ to retain the immutable buffer until libzmq finishes with it.
  • Receive worker responses as zmq.Frame objects in the pool.
  • Materialize only the small request ID for the pending-request dictionary lookup.
  • Forward the original request-ID and payload frames with copy=False.

Performance

A TCP loopback benchmark queued one 128 MiB response and measured the critical send/relay section plus process RSS after the queue settled. Each mode ran three times; the table reports medians.

Path Before After Time saved RSS before RSS after RSS saved
Server send 7.901 ms 0.649 ms 7.252 ms (91.8%) +256.1 MiB +128.2 MiB 127.9 MiB (49.9%)
Pool relay 13.872 ms 0.066 ms 13.806 ms (99.5%) +256.1 MiB +128.0 MiB 128.1 MiB (50.0%)

The remaining RSS is common receiver-side queue storage in the same-process benchmark. The removed portion is the avoidable payload duplication at the PyZMQ API boundaries. Small frames continue to follow PyZMQ's copy-threshold behavior.


Note

Low Risk
Transport-only optimization with no protocol or routing logic changes; relies on PyZMQ buffer lifetime semantics for copy=False, which is standard for large frames.

Overview
Large msgpack rollout responses no longer get copied at the PyZMQ send/recv boundaries on the v1 env server and worker pool.

EnvServer sends the packed response with copy=False, so libzmq can hold the immutable msgpack buffer until the send completes.

EnvServerPool receives worker replies with copy=False (as zmq.Frames), uses only request_id.bytes for the pending lookup, and relays request_id and the payload frame to the client ROUTER with copy=False. Request routing, health handling, and serialization are unchanged.

Reviewed by Cursor Bugbot for commit 5dbdb5d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Use zero-copy ZMQ multipart message relay in broker and server

Switches ZMQ recv/send calls in the broker loop and server request handler to use copy=False, avoiding buffer copies when receiving and forwarding multipart messages.

  • In pool.py, worker socket receives with recv_multipart(copy=False) and forwards via send_multipart(..., copy=False); pending lookup uses request_id.bytes since request_id is now a zmq.Frame.
  • In server.py, response is sent with send_multipart(..., copy=False) to avoid copying the payload frame.

Macroscope summarized 5dbdb5d.

@macroscopeapp

macroscopeapp Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved

This is a straightforward ZMQ performance optimization adding zero-copy (copy=False) to message passing. The changes are minimal, self-contained, and follow standard ZMQ patterns without altering application logic.

You can customize Macroscope's approvability policy. Learn more.

@xeophon
xeophon merged commit 34c34fc into feat/nano-as-v1 Jun 21, 2026
5 checks passed
pull Bot pushed a commit to Stars1233/verifiers that referenced this pull request Jun 23, 2026
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