Skip to content

Commit 5ec1c2e

Browse files
committed
Replace SortedSet with a set in the Matryoshka algorithm
The `SortedSet` implementation appears to be buggy, so it is being replaced with `set`. This is slower in theory, but not much difference is expected in practice. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 5d9222a commit 5ec1c2e

File tree

2 files changed

+19
-9
lines changed

2 files changed

+19
-9
lines changed

src/frequenz/sdk/actor/_power_managing/_base_classes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,14 @@ def __eq__(self, other: object) -> bool:
252252

253253
return self.priority == other.priority and self.source_id == other.source_id
254254

255+
def __hash__(self) -> int:
256+
"""Get the hash of the proposal.
257+
258+
Returns:
259+
The hash of the proposal.
260+
"""
261+
return hash((self.priority, self.source_id))
262+
255263

256264
class Algorithm(enum.Enum):
257265
"""The available algorithms for the power manager."""

src/frequenz/sdk/actor/_power_managing/_matryoshka.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
from ...timeseries import Power
3030
from . import _bounds
3131
from ._base_classes import BaseAlgorithm, Proposal, _Report
32-
from ._sorted_set import SortedSet
3332

3433
if typing.TYPE_CHECKING:
3534
from ...timeseries._base_types import SystemBounds
@@ -44,12 +43,12 @@ class Matryoshka(BaseAlgorithm):
4443
def __init__(self, max_proposal_age: timedelta) -> None:
4544
"""Create a new instance of the matryoshka algorithm."""
4645
self._max_proposal_age_sec = max_proposal_age.total_seconds()
47-
self._component_buckets: dict[frozenset[int], SortedSet[Proposal]] = {}
46+
self._component_buckets: dict[frozenset[int], set[Proposal]] = {}
4847
self._target_power: dict[frozenset[int], Power] = {}
4948

5049
def _calc_target_power(
5150
self,
52-
proposals: SortedSet[Proposal],
51+
proposals: set[Proposal],
5352
system_bounds: SystemBounds,
5453
) -> Power:
5554
"""Calculate the target power for the given components.
@@ -83,7 +82,7 @@ def _calc_target_power(
8382
exclusion_bounds = system_bounds.exclusion_bounds
8483

8584
target_power = Power.zero()
86-
for next_proposal in reversed(proposals):
85+
for next_proposal in sorted(proposals, reverse=True):
8786
if upper_bound < lower_bound:
8887
break
8988
if next_proposal.preferred_power:
@@ -183,9 +182,10 @@ def calculate_target_power(
183182
return None
184183

185184
if proposal is not None:
186-
self._component_buckets.setdefault(component_ids, SortedSet()).insert(
187-
proposal
188-
)
185+
bucket = self._component_buckets.setdefault(component_ids, set())
186+
if proposal in bucket:
187+
bucket.remove(proposal)
188+
bucket.add(proposal)
189189

190190
# If there has not been any proposal for the given components, don't calculate a
191191
# target power and just return `None`.
@@ -243,7 +243,9 @@ def get_status(
243243
):
244244
exclusion_bounds = system_bounds.exclusion_bounds
245245

246-
for next_proposal in reversed(self._component_buckets.get(component_ids, [])):
246+
for next_proposal in sorted(
247+
self._component_buckets.get(component_ids, []), reverse=True
248+
):
247249
if next_proposal.priority <= priority:
248250
break
249251
proposal_lower = next_proposal.bounds.lower or lower_bound
@@ -286,4 +288,4 @@ def drop_old_proposals(self, loop_time: float) -> None:
286288
if (loop_time - proposal.creation_time) > self._max_proposal_age_sec:
287289
to_delete.append(proposal)
288290
for proposal in to_delete:
289-
bucket.delete(proposal)
291+
bucket.remove(proposal)

0 commit comments

Comments
 (0)