-
Notifications
You must be signed in to change notification settings - Fork 120
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
chore(perf): Revert commit to bring back up to 20% perf #574
chore(perf): Revert commit to bring back up to 20% perf #574
Conversation
In one of the commits capacity optimization were made. It saved 1 unit of storage per circular buffer but actually takes up to 20% of performance. Link to commit: piscinajs@395e630
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 we do benchmarks with payloads twice or three times its size?
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.
Do you mean to push something bigger than integers or just more items?
If the second option then it's already done.
Results could be seen here #555 (comment) for twice the size, 64 times the size and 1024 times the size of single circular 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.
Oh, good call, sorry I missed that
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.
No problem.
Btw in the last few days I tried to play with circular buffer size, tried to preallocate and reuse ring buffers with a pool and so on but nothing really brings benefits, only performance degradations.
It feels like FixedQueue was created by a dark magician who put an "unbeatable" spell on 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.
It is pretty well optimized. Liked the tradeoff of memory for more performance 👌
@@ -65,7 +65,7 @@ test('remove not queued task should not lead to errors', async ({ equal }) => { | |||
test('removing elements from intermediate CircularBuffer should not lead to issues', async ({ equal, same }) => { | |||
const queue = new FixedQueue(); | |||
|
|||
const batchSize = 2048; | |||
const batchSize = 2047; |
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.
Does it fails with 2048?
In the worst case, it will pre-allocate another buffer, isn't 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.
In general it doesn't fail but it should match the batch size due to test's intensions.
The test may require additional clarification with comments.
The main goal was to check following scenario:
- We fill the queue with 3 full circular buffers amount of items.
- Empty the middle circular buffer.
- This should lead to the removal of the middle buffer from the queue:
- Before emptying: tail buffer -> middle buffer -> head buffer.
- After emptying: tail buffer -> head buffer.
My initial remove
implementation didn't remove empty buffer so I wrote a test to fix 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.
Nice, now is clear; maybe add that to the description of the test can help understand why are we doing that
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.
Although I added the description I must admit that the test is actually insufficient/fragile due to lack of internal checks.
As you rightly noticed it doesn't and it wouldn't break even if the size of internal circular buffer will ever changes.
We potentialy could try to really check the amount of buffers with something like following, but this approach will definetly be broken when we ship "real" private fields in further major release.
const queue = new FixedQueue()
let buffer = queue.tail
let count = 0
while (buffer !== null) {
count++
buffer = buffer.next
}
console.log(`The queue has ${count} buffers`)
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.
Overall, I'd not recommend to alter the internals just for testing; I've always advocated for testing the outcome rather than expectations.
If we want to check how many internal circular buffers has been made, we can always check the overall outcome, we know that if two circular buffers are made, at least we should have 2048 + 1, this at the FixedTaskQueue
level.
At the FixedQueue
we can go deep but always using the interfaces as a bridge and not going beyond
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 completely agree that it's not the right way. I just worry about further consequences due to the lack of clarity.
Is there anything else blocking the PR from being landed?
As mentioned here #555 (comment) in one of the commits capacity optimization were made.
It saved 1 unit of storage per circular buffer but actually takes up to 20% of performance.
Link to commit which caused perf drop: 395e630