Skip to content

Have rerun render shared memory topics (fix dev for MacOS)#1716

Draft
jeff-hykin wants to merge 12 commits intodevfrom
jeff/fix/dev2
Draft

Have rerun render shared memory topics (fix dev for MacOS)#1716
jeff-hykin wants to merge 12 commits intodevfrom
jeff/fix/dev2

Conversation

@jeff-hykin
Copy link
Copy Markdown
Member

@jeff-hykin jeff-hykin commented Mar 30, 2026

Draft b/c ShmSubset probably shouldn't have subscribe_all since its basically a shim. Better fix would be changing rerun bridge to support topics without subscribe all.

Problem

MacOS doesn't render any camera images to rerun, cause rerun doesn't support shared memory transport

Solution

Breaking Changes

How to Test

Contributor License Agreement

  • I have read and approved the CLA.

….py, add typing_extensions dep

Address Paul's review comment: fix remaining Self imports that used
'Any as Self' fallback on Python 3.10, and add typing_extensions as an
explicit dependency in pyproject.toml.
typer.confirm raises click.Abort when stdin is not a TTY. New
dimos/utils/prompt.py provides confirm() that returns the default
when not interactive. system_configurator now uses it.

Revert: git revert HEAD
dimos/utils/prompt.py provides:
- confirm(): returns default if not TTY, else typer.confirm()
- sudo_run(): prepends sudo if not root

Moved sudo_run from system_configurator/base.py to prompt.py.
Updated all importers (base.py, lcm.py, clock_sync.py, tests).

Root cause: Ivan's 8edc995 replaced input() with typer.confirm()
which raises click.Abort on non-TTY stdin.

Revert: git revert HEAD
@jeff-hykin jeff-hykin marked this pull request as draft March 30, 2026 23:36
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 30, 2026

Greptile Summary

This PR adds macOS support to the Rerun bridge by introducing a ShmSubset shim that lets the bridge subscribe_all on a fixed set of known shared-memory topics (since SHM pubsub has no topic-discovery mechanism). It also corrects the topic name to "/color_image" (adding the required leading slash) and propagates default_capacity through the pickle protocol for pSHMTransport/SHMTransport.

Key changes:

  • ShmSubset (shmpubsub.py): New stop-gap adapter wrapping PickleSharedMemory/BytesSharedMemory to expose a subscribe_all interface. Marked QUALITY_LEVEL: temporary; the docstring example omits the required / prefix on the topic name, which would fail the new bridge assertion.
  • bridge.py: Adds a slash-prefix guard to _get_entity_path using assert, which will be silently disabled in optimised builds (-O).
  • transport.py: default_capacity is now propagated through __reduce__/__setstate__, though the current implementation causes a redundant PickleSharedMemory to be allocated and discarded during unpickling.
  • unitree_go2_basic.py: Fixes topic name and wires ShmSubset into the bridge's pubsubs list.

Confidence Score: 4/5

  • Safe to merge with minor fixes; one docstring error would produce a runtime AssertionError for anyone following the example.
  • The P1 issue (docstring example missing the / prefix) would cause an immediate AssertionError for any developer who copies it verbatim into a non-Go2 project. The P2 issues (using assert for runtime validation, redundant SHM allocation during pickling) are style/best-practice concerns that don't block the primary macOS fix path, but the docstring error is concrete enough to warrant a 4.
  • dimos/protocol/pubsub/impl/shmpubsub.py (docstring example) and dimos/visualization/rerun/bridge.py (assert vs. proper exception).

Important Files Changed

Filename Overview
dimos/visualization/rerun/bridge.py Adds a leading-slash assertion to _get_entity_path; using assert for runtime validation is fragile under -O and should be a proper exception.
dimos/protocol/pubsub/impl/shmpubsub.py Introduces ShmSubset shim and makes default_capacity optional; docstring example missing required leading / on topic name will trigger the new bridge assertion.
dimos/core/transport.py Adds default_capacity to pSHMTransport/SHMTransport constructors and pickle protocol; __init__ allocates a redundant SHM object during unpickling that __setstate__ immediately discards.
dimos/robot/unitree/go2/blueprints/basic/unitree_go2_basic.py Fixes topic name to use /color_image (with leading slash) and wires ShmSubset into the Rerun bridge's pubsubs list for macOS compatibility.

Sequence Diagram

sequenceDiagram
    participant BP as unitree_go2_basic
    participant SS as ShmSubset
    participant SHM as PickleSharedMemory
    participant Bridge as RerunBridgeModule
    participant RR as Rerun Viewer

    BP->>Bridge: pubsubs=[LCM(), ShmSubset(["/color_image"])]
    Bridge->>SS: subscribe_all(callback)
    SS->>SHM: PickleSharedMemory(default_capacity=capacity)
    SS->>SHM: start()
    SS->>SHM: subscribe("/color_image", _cb)
    SHM-->>SS: unsub fn

    note over SHM: macOS robot publishes via pSHMTransport
    SHM->>SS: _cb(msg, "/color_image")
    SS->>Bridge: callback(msg, "/color_image")
    Bridge->>Bridge: _get_entity_path("/color_image")<br/>assert startswith("/") ✓
    Bridge->>RR: rr.log(entity_path, rerun_data)
Loading

Reviews (1): Last reviewed commit: "Merge branch 'dev' of github.com:dimensi..." | Re-trigger Greptile

# Strip everything after # (LCM topic suffix)
topic_str = topic_str.split("#")[0]
# Ensure / separator between prefix and topic
assert topic_str.startswith("/"), f"{topic_str} doesn't start with slash"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Assert used for runtime input validation

assert is silently stripped when Python runs with the -O (optimise) flag, so this guard will disappear in any optimised deployment. If a topic arrives without a leading slash, the bridge will silently produce a malformed entity path instead of surfacing an error. A proper ValueError (or at minimum a logged warning) is the right tool here.

Suggested change
assert topic_str.startswith("/"), f"{topic_str} doesn't start with slash"
if not topic_str.startswith("/"):
raise ValueError(f"{topic_str!r} doesn't start with slash; SHM topic names must begin with '/'")

from dimos.protocol.pubsub.impl.shmpubsub import ShmSubset

bridge = RerunBridgeModule(
pubsubs=[LCM(), ShmSubset(topics=[("color_image", 6220800, "pickle")])],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Docstring example omits required leading slash

The example topic name is "color_image" (no leading /), but the bridge now asserts topic_str.startswith("/") at bridge.py:274. A developer who copies this example verbatim will trigger an AssertionError at runtime. The example should mirror the actual usage in unitree_go2_basic.py ("/color_image").

Suggested change
pubsubs=[LCM(), ShmSubset(topics=[("color_image", 6220800, "pickle")])],
bridge = RerunBridgeModule(
pubsubs=[LCM(), ShmSubset(topics=[("/color_image", 6220800, "pickle")])],
)

Comment on lines 168 to +173
def __reduce__(self): # type: ignore[no-untyped-def]
return (pSHMTransport, (self.topic,))
return (pSHMTransport, (self.topic,), {"default_capacity": self._default_capacity})

def __setstate__(self, state: dict) -> None: # type: ignore[no-untyped-def]
self._default_capacity = state.get("default_capacity")
self.shm = PickleSharedMemory(default_capacity=self._default_capacity)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Pickle round-trip allocates a wasted SHM object

With the current __reduce__ / __setstate__ split, unpickling pSHMTransport (and SHMTransport) calls __init__ first (because __reduce__ returns (pSHMTransport, (self.topic,), state)). That __init__ call constructs a PickleSharedMemory(default_capacity=None), which is immediately discarded when __setstate__ constructs the correct one. This is a minor but unnecessary allocation.

One common pattern to avoid this is to delegate to __new__ in __reduce__ and perform all initialisation in __setstate__:

def __reduce__(self):
    return (
        _reconstruct_pshm,  # module-level helper that calls __new__
        (type(self), self.topic, self._default_capacity),
    )

Or simply accept the redundant allocation as a known trade-off and add a comment. The same applies to SHMTransport (lines 203-208).

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