Skip to content

Use ring buffer for the SimProfiler#3304

Open
ttktjmt wants to merge 1 commit into
google-deepmind:livefrom
ttktjmt:refactor/sim-profiler-ring-buffer
Open

Use ring buffer for the SimProfiler#3304
ttktjmt wants to merge 1 commit into
google-deepmind:livefrom
ttktjmt:refactor/sim-profiler-ring-buffer

Conversation

@ttktjmt
Copy link
Copy Markdown

@ttktjmt ttktjmt commented Jun 1, 2026

Update() called erase(begin()) + push_back() on 11 vectors every frame, O(N) per buffer. Replace with a head_ write cursor and direct indexed writes (buf[head_] = val), advancing the cursor modulo 200 at the end of each update. Pass head_ as ImPlot's offset parameter so the circular buffer renders correctly without data movement.

@google-cla
Copy link
Copy Markdown

google-cla Bot commented Jun 1, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Replace O(N) erase(begin())+push_back() per frame with O(1) indexed writes using a pointer.
@ttktjmt ttktjmt force-pushed the refactor/sim-profiler-ring-buffer branch from f7b3cf8 to 9c72c3f Compare June 1, 2026 05:34
@okmatija
Copy link
Copy Markdown
Collaborator

okmatija commented Jun 1, 2026

Thanks for the PR! We have not been very good with writing tests for the studio components, perhaps you could kick this off by adding a simple one for the SimProfiler. You could make sure it passes with and without your change e.g., by implementing the test in a first commit and doing the refactor in the next one.

@ttktjmt
Copy link
Copy Markdown
Author

ttktjmt commented Jun 2, 2026

@okmatija Thank you for the review!
Sure, I can add a simple test for SimProfiler as a first step. The design of the test contracts depends on whether they need to cover behavior both before and after this change, or only after.

Contracts covering both before and after the change:

  • Calling Update() N times does not crash
  • If N ≤ max_frames, exactly N frames are recorded
  • If N > max_frames, it does not crash
  • The most recently recorded values are retrievable
  • After Clear(), subsequent calls to Update() work correctly

Contracts focused only on the behavior after this change:

  • A single call to Update() increments the recorded frame count by 1 (i.e., head advances from 0 to 1)
  • Calling Update() max_frames + 1 times wraps head back via % max_frames (i.e., head goes from max_frames to 1)
  • Calling Clear() resets head to 0
  • The N-th call to Update() writes to slot N-1 (e.g., the 1st call writes to slot 0, the 2nd to slot 1, with dim_body values)

Which scope would you prefer?

@okmatija
Copy link
Copy Markdown
Collaborator

okmatija commented Jun 2, 2026

We don't want to maintain detailed tests I think, just some basic sanity checking is enough IMO. Also, looking at the API again I think we don't really have a useful public function we can use to implement the tests (we don't really want to check private implmeentation details like where head_ is), perhaps we could add a Summary() function which returns a Summary struct some useful info e.g., counts and averages? With that data we could implement one test that does something like:

  • Record N < max_frames and check summary.
  • Record one more frame and check summary.
  • Record one more frame (so N > max_frames) and check summary.
  • Clear() and check summary is all zero or whatever makes sense.

The summary data may be useful in the UI somewhere. WDYT @haroonq ?

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