-
Notifications
You must be signed in to change notification settings - Fork 83
JitterBuffer: Improve performance for SampleBuilder use #292
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
base: master
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #292 +/- ##
==========================================
- Coverage 78.64% 78.60% -0.04%
==========================================
Files 82 83 +1
Lines 5113 5497 +384
==========================================
+ Hits 4021 4321 +300
- Misses 921 995 +74
- Partials 171 181 +10
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
I'll try it later! |
|
@thatsnotright I tested this branch locally in my usecase and confirmed that SampleBuilder's performance is good! (mostly same CPU/memory usage as the latest release) |
@at-wat Thank you for taking the time to test, I appreciate your time! I'll clean up the code a little and make some test coverage improvements and then work with @Sean-Der on next steps! |
ea085bb to
ab615fe
Compare
521c4f0 to
339f38e
Compare
339f38e to
6d35fb4
Compare
3ff714b to
6982678
Compare
7639fd0 to
72641d8
Compare
72641d8 to
e99f243
Compare
e7aab86 to
8e6a4ed
Compare
9e75f82 to
77fa007
Compare
6572218 to
2de1b4e
Compare
91acafb to
d2a5878
Compare
Rework the jitterbuffer for SampleBuilder use Allow Skipping packets
d2a5878 to
7e03435
Compare
|
@thatsnotright could you add a benchmark test and post a comparison between the master branch and this PR? |
at-wat
left a comment
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 consider adding a benchmark test to compare with the master branch.
It would be better to have bench test cases for some different amount of unordered packet.
PriorityQueue is now unused but the code is remained. It should be removed.
| func safeUint16(i int) uint16 { | ||
| if i < 0 { | ||
| return 0 | ||
| } | ||
| if i > math.MaxUint16 { | ||
| return math.MaxUint16 | ||
| } | ||
|
|
||
| return uint16(i) | ||
| } | ||
|
|
||
| func safeUint32(i int) uint32 { | ||
| if i < 0 { | ||
| return 0 | ||
| } | ||
| if i > math.MaxInt32 { | ||
| return math.MaxUint32 | ||
| } | ||
|
|
||
| return uint32(i) | ||
| } |
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.
They seems to be used to clamp sequence number and timestamp.
Is it correct to clamp instead of rolling over?
e.g. testing the sequence of (0xFFFE, 0xFFFF, 0xFFFF, 0xFFFF) doesn't make sense and should be (0xFFFE, 0xFFFF, 0x0001, 0x0002)
| } | ||
|
|
||
| func TestJitterBufferInOrderPackets(t *testing.T) { | ||
| assert := assert.New(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.
I think overriding a package name by a local variable makes confusion
| } | ||
|
|
||
| // Wait for buffer to transition to emitting state | ||
| for jb.state == Buffering { |
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 guess this should be accessed with lock
| tree.Clear() | ||
| _, err := tree.Pop() | ||
| assert.Error(err) | ||
| assert.Contains(err.Error(), "priority not found") |
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.
Should be checked by assert.ErrorIs
| tests := []struct { | ||
| name string | ||
| ops func(*RBTree) | ||
| validate func(*testing.T, *RBTree) | ||
| }{ |
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.
IMO, these test cases don't share almost any code and doesn't make sense to be a table driven. Simply writing t.Run("TableRotation", ...) { would be better
| if diff > 32768 { | ||
| return -1 | ||
| } | ||
| if diff < -32768 { | ||
| return 1 | ||
| } | ||
| if diff < 0 { | ||
| return -1 | ||
| } | ||
| if diff > 0 { | ||
| return 1 | ||
| } |
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.
| if diff > 32768 { | |
| return -1 | |
| } | |
| if diff < -32768 { | |
| return 1 | |
| } | |
| if diff < 0 { | |
| return -1 | |
| } | |
| if diff > 0 { | |
| return 1 | |
| } | |
| switch { | |
| case diff > 32768: | |
| return -1 | |
| case diff < -32768: | |
| return 1 | |
| case diff < 0: | |
| return -1 | |
| case diff > 0: | |
| return 1 | |
| } |
| // RBTree structure is a red-black tree for fast access based on priority. | ||
| type RBTree struct { | ||
| root *rbnode | ||
| length uint16 | ||
| } | ||
|
|
||
| // NewTree creates a new red-black tree. | ||
| func NewTree() *RBTree { | ||
| return &RBTree{} | ||
| } |
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.
Having public RBTree in jitterbuffer package looks not proper.
(Users shouldn't have to take care of the internal implementation)
I think it should be an internal sub-package.
| if err != nil { | ||
| if errors.Is(err, ErrNotFound) { | ||
| if i.skipMissingPackets { | ||
| i.log.Warn("Skipping missing packet") |
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 guess this may spam the logs. Maybe it should be debug level?
| } | ||
|
|
||
| // Pop will remove the root in the queue. | ||
| func (t *RBTree) Pop() (*rtp.Packet, error) { |
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 the root node mean the approx. median of the stored priority (sequence number)?
I'm not sure popping this makes sense.
Description
This PR Should hopefully improve the performance for use by SampleBuilder and in the general case.
@at-wat If you have time would you be able to test this PR and the corresponding branch I created in the webrtc repository? pion/webrtc#2959
Thank you!