Skip to content

chore: Improve Sonos Memory Usage #2306

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

dljsjr
Copy link
Member

@dljsjr dljsjr commented Jul 30, 2025

Type of Change

  • Refactor

Checklist

  • I have performed a self-review of my code
  • I have commented my code in hard-to-understand areas
  • I have verified my changes by testing with a device or have communicated a plan for testing
  • I am adding new behavior, such as adding a sub-driver, and have added and run new unit tests to cover the new behavior

Depends On

Description of Change

@NoahCornell did some analysis of driver heap usage, and Sonos was
disproportionately above the mean for the heap-space-per-device line fit
on the dataset.

This PR improves memory usage by limiting the information we keep resident
from API responses to the fields that we actually use in regular operation.

Additional background:

One source of heap usage was unbounded memory growth due to task spawning
on a certain error pathway, which he already fixed in a different PR.

Another source was the fact that we were cacheing the entire API
response for the Player and Group information for the LAN's Sonos topology.
These API payloads are pretty large, and have actually gotten larger over time.

This has been the case for this driver for a very long time; the
decision to store the whole response object was made so that we would
have the information available if we needed it in the future for bug
fixes or enhancements.

It turns out that the information we're utilizing hasn't really changed
much over the last few years, so I'm feeling quite comfortable about
excising the majority of the payload information at this point. We see
pretty signifcant memory savings with these changes, and the savings
should scale appreciably with device count, which is a big win.

Summary of Completed Tests

Tested on my personal setup by overriding the driver files directly. Will need to be regression tested by internal QA once this lands on Alpha; the OAuth stuff precludes this from being tested using the PR channel invite.

dljsjr added 3 commits July 29, 2025 17:50
We have historically ignored non-primary devices in bonded sets during
discovery/onboarding, going back to the pre-Edge days. 

Bonded sets are things like stereo pairs or home theater setups.

These devices cannot be controlled via the WSS LAN API at all, and they
aren't treated as being part of a Group in the Sonos group model; the
intent is for API consumers to treat the entire bonded set as a single
"player". Only one of the devices in the set exposes an API endpoint,
which differs from a Group where all the players expose an endpoint.
While groups service most commands via calling the API endpoint on the
Group Coordinator, certain commands like volume can be sent to
non-coordinator players. This is not the case with bonded sets; the
entire set always acts atomically, and only the primary device in the
set can service commands. Hence, we treat non-primary devices as not
controllable in a bonded set, and we don't onboard them.

However, we didn't really have very robust handling of devices that
become part of a bonded set at runtime after onboarding. This led to
unnecessary CPU and RAM usage by creating a few tight loops due to
unexpected failure/edge cases when making certain calls.

Because we would fail to discover this device under normal
circumstances, the preferred way to handle this transition is to mark
the device as being offline. We discussed emitting a delete for these
devices, but it seems that it wouldn't be too uncommon for some users to
create and destroy bonded sets ephemerally the way one might do with a
Group. For this reason we decided we would avoid deleting the records.

If a non-primary in a bonded set is removed from the bonded set, it will
be marked as online again.
@NoahCornell did some analysis of driver heap usage, and Sonos was
disproportionately above the mean for the heap-space-per-device line fit
on the dataset.

This PR improves memory usage by limiting the information we keep resident
from API responses to the fields that we actually use in regular operation.

Additional background:

One source of heap usage was unbounded memory growth due to task spawning
on a certain error pathway, which he already fixed in a different PR.

Another source was the fact that we were cacheing the entire API
response for the Player and Group information for the LAN's Sonos topology.
These API payloads are pretty large, and have actually gotten larger over time.

This has been the case for this driver for a very long time; the
decision to store the whole response object was made so that we would
have the information available if we needed it in the future for bug
fixes or enhancements.

It turns out that the information we're utilizing hasn't really changed
much over the last few years, so I'm feeling quite comfortable about
excising the majority of the payload information at this point. We see
pretty signifcant memory savings with these changes, and the savings
should scale appreciably with device count, which is a big win.
Copy link

Copy link

Test Results

   68 files    447 suites   0s ⏱️
2 324 tests 2 324 ✅ 0 💤 0 ❌
3 923 runs  3 923 ✅ 0 💤 0 ❌

Results for commit 5a92f43.

Copy link

Minimum allowed coverage is 90%

Generated by 🐒 cobertura-action against 5a92f43

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