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
Simple ringbuffer with tests #116
Simple ringbuffer with tests #116
Conversation
src/frequenz/sdk/util/ringbuffer.py
Outdated
def write(self, value: T, index: int) -> None: | ||
"""""" | ||
self.data[index] = value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- You can also override
__setitem__
:) - Maybe check if index < len(self.data)?
16ad023
to
67541ec
Compare
67541ec
to
35544a8
Compare
I pushed an update that shows a basic working of the timestamp buffer. The numpy variant still has a problem that I am currently looking into. More logic tests are to come as well as performance tests |
bc0a8ee
to
f3d0b72
Compare
|
96de0fa
to
2057ab9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of the comments are just me putting the pylint
or mypy
hat, so it is not as bad as it looks 😆
benchmarks/benchmark_ringbuffer.py
Outdated
# Copyright © 2022 Frequenz Energy-as-a-Service GmbH | ||
|
||
""" | ||
Performance test for the `Ringbuffer` class |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please mirror the directory structure in src
for benchmarks so it is easier to figure out which benchmark is benchmarking what. In this case it should be benchmarks/util/ringbuffer.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see power_distribution
in the src
dir so I assumed it would be more.. arbitrary..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think at some point that one was top-level, we probably forgot to update the benchmarks
structure when we moved it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it is intentional but the benchmark disappeared from the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah no, that was a bad renaming
benchmarks/benchmark_ringbuffer.py
Outdated
(f"{basetime + timedelta(days=day)} average {np.average(minutes)}") | ||
(f"{basetime + timedelta(days=day)} median {np.median(minutes)}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are these strings laying around there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just trying to prevent python from optimizing them away
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get it? You want to test the performance of building a formatted string?
src/frequenz/sdk/util/ringbuffer.py
Outdated
|
||
|
||
class RingBuffer(Generic[T]): | ||
def __init__(self, container: Any): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably want to have some restrictions on the container, like MutableSequence
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd love to, but I found no type that would fit so far. Will investigate again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests/utils/ringbuffer.py:19: error: Argument 1 to "RingBuffer" has incompatible type "ndarray[Any, dtype[f
loating[_64Bit]]]"; expected "MutableSequence[<nothing>]" [arg-type]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you show how you changed the code to get that message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just changed Any
to MutableBuffer[T]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, yeah, it looks like it's not even a Sequence
(although it should), but probably won't get all the methods needed by a MutableSequence
: numpy/numpy#2776.
So we have 2 options I can see:
- Use an union:
MutableSquence[T] | np.ndarray
, which is a bit ugly to have this special casing, why onlynp.ndarray
and not anything else that looks like a duck? - Use a
Protocol
: just look at all the methods and attributes you need a container to have an write aBufferContainer
protocol.
IMHO 2. is the correct option, but it is a bit of work that might not be justified at this point, so I would leave Any
and create an issue to improve this in the future.
""" | ||
return index % self.max_size() | ||
|
||
def __getitem__(self, index_or_slice: int | slice) -> T | Sequence[T]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as before, better not provide this if the implementation is not correct IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it is correct insofar as that it provides direct access to the buffer..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above, I think it is more clear to provide access to the underlying container and let people slice that directly instead.
Another comment is you can improve type checking by adding @overload
s, to specify which subset of types are valid in those unions. Here is an example: https://github.com/frequenz-floss/frequenz-sdk-python/pull/130/files#diff-43d601005020a1afe419acdfad091a0e813ddd9a6f2e1d4e0db73c030ff8d599R135-R143
Beware of damn GitHub compressing comments and hiding them, make sure to click when it says "N hidden conversations. Load more". |
2057ab9
to
64c2a6b
Compare
64c2a6b
to
123807e
Compare
0d16f7f
to
ffa7b7c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There were a few pending unanswered comments from the previous review. I think all the remaining stuff is very minor. There are only 2 major topics:
- If, when and how do we need the sorted buffer.
- If we really need proper slicing (setting and getting). My impression is we don't need setting a slice. About getting, not sure, maybe, maybe it is enough with using
islice
and we save some complexity (which IMHO while implementing the resampling buffer was not at all minor, specially with the many cases if we include steps and negative values).
Signed-off-by: Marenz <mathias.baumann@frequenz.com>
0464117
to
80bbd4d
Compare
Closing this to keep the branch around for the simple ring buffer, will create a new PR with only the sorted ring buffer |
First draft, more tests to come, also performance test.
next step is testing the slicing parts.
Signed-off-by: Marenz mathias.baumann@frequenz.com