Skip to content
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

RtpStreamSend: Memory optimizations #840

Merged
merged 28 commits into from
Jun 28, 2022
Merged

RtpStreamSend: Memory optimizations #840

merged 28 commits into from
Jun 28, 2022

Conversation

jmillan
Copy link
Member

@jmillan jmillan commented Jun 22, 2022

Essentially extracted from #675

  • RtpStreamSend does not clone each RTP packet coming from Producer.

    • A std::shared_ptr holding the original packet is used by all RtpStreamSend
      instances.
  • RtpStreamSend does not clone each RTP packet when sending DTX.

    • The original RTP packet is DTX encoded/decoded when needed.
  • RtpStreamSend does not store up to 65536 RTP packets in a std::map.

    • Only a limited range of RTP packets are stored in a std::deque (up to 2000 ms of media).

Memory usage differences using mediasoup-demo with 6 attendees in a room:

  • v3: 60MB
  • rtpstreamsend-optimizations: 17.5MB.

@jmillan
Copy link
Member Author

jmillan commented Jun 22, 2022

@ibc, @nazar-pc,

#675 is extremely big and difficult to review. This is the Nth split I make out of that PR. Let's never do such big PR again with many different kind of changes, it's too time consuming and it takes too much time to get them merged.

AFAIK, after this only the object pool stuff would be missing.

Please, do dedicate some time reviewing. I've tested it and the memory savings big.

I have made some extra enhancements such as not cloning the RTP packet not even for sending DTX.

@jmillan jmillan requested review from ibc and nazar-pc June 22, 2022 15:33
@jmillan
Copy link
Member Author

jmillan commented Jun 22, 2022

Also @nazar-pc , removed the useNack argument from RtpStreamSend constructor since it's present in the already provided params argument.

@jmillan
Copy link
Member Author

jmillan commented Jun 22, 2022

Note: I'll write more tests.

Essentially extracted from #675

* RtpStreamSend does not clone each RTP packet coming from Producer.
 - A std::shared_ptr holding the original packet is used by all RtpStreamSend
   instances.

* RtpStreamSend does not clone each RTP packet when sending DTX.
 - The original RTP packet is DTX encoded/decoded when needed.

* RtpStreamSend does not store up to 65536 RTP packets in a std::map.
 - Only a limited range of RTP packets are stored in a std::deque.
@jmillan jmillan force-pushed the rtpstreamsend-optimizations branch from f17d5f9 to c5495a6 Compare June 23, 2022 08:38
worker/src/RTC/RtpStreamSend.cpp Show resolved Hide resolved
worker/src/RTC/RtpStreamSend.cpp Outdated Show resolved Hide resolved
worker/src/RTC/Router.cpp Outdated Show resolved Hide resolved
@jmillan
Copy link
Member Author

jmillan commented Jun 24, 2022

@nazar-pc, could you please look at the Rust CI error?

@jmillan
Copy link
Member Author

jmillan commented Jun 24, 2022

@nazar-pc, could you please look at the Rust CI error?

I'm checking

@jmillan
Copy link
Member Author

jmillan commented Jun 24, 2022

Rust is failing to link MaxRetransmissionDelay and MinRetransmissionDelay in the GH workflows.

cargo test is properly working for me locally. Any idea?

Screenshot 2022-06-24 at 21 47 19

worker/include/RTC/RtpStreamSend.hpp Outdated Show resolved Hide resolved
worker/include/RTC/RtpStreamSend.hpp Outdated Show resolved Hide resolved
@ibc
Copy link
Member

ibc commented Jun 24, 2022

OMG YES. static members initialization must be done in cpp files.

@jmillan
Copy link
Member Author

jmillan commented Jun 24, 2022

OMG YES. static members initialization must be done in cpp files.

Not required for numeric variables as per the spec. Indeed cargo test was working in localhost.

@ibc
Copy link
Member

ibc commented Jun 24, 2022

Prove that we initialize any static class numeric variable the way it was done in this PR before.

@jmillan
Copy link
Member Author

jmillan commented Jun 24, 2022

Prove that we initialize any static class numeric variable the way it was done in this PR before.

I didn't say otherwise.

@jmillan
Copy link
Member Author

jmillan commented Jun 28, 2022

Great problem I've found with the approach in this PR.

A shared_ptr is created in Router out of the original RtpPacket. The payload buffer of it points to a memory pointer of ReadBuffer in UdpSocketHandler or the corresponding in TcpConnectionHandler if we are using TCP.

This means that such payload pointer will get invalidated once the next packet arrives.

This is the reason why the original PR did a RtpPacket::Clone() on the first RtpStreamSend. Instead of that I'll clone the packet in Router , before passing it to the Consumer s, so they have an RtpPacket with it's own memory buffer that can be used safely in the future whenever a retransmission is needed.

@ibc
Copy link
Member

ibc commented Jun 28, 2022

A shared_ptr is created in Router out of the original RtpPacket. The payload buffer of it points to a memory pointer of ReadBuffer in UdpSocketHandler or the corresponding in TcpConnectionHandler if we are using TCP.

This means that such payload pointer will get invalidated once the next packet arrives.

Indeed. Just wondering, didn't this bug produce terrible issues already? It shouldn't be hard to reproduce AFAIU.

This is the reason why the original PR did a RtpPacket::Clone() on the first RtpStreamSend. Instead of that I'll clone the packet in Router , before passing it to the Consumer s, so they have an RtpPacket with it's own memory buffer that can be used safely in the future whenever a retransmission is needed.

Why cloning it in Router before passing it to Consumers? It should be cloned when generated in the Producer, right? or even in RtcStreamRecv.

@jmillan
Copy link
Member Author

jmillan commented Jun 28, 2022

Why cloning it in Router before passing it to Consumers? It should be cloned when generated in the Producer, right? or even in RtcStreamRecv.

If there is no Consumer there is even no need to clone the packet.

So the RtpPacket has its own buffer for future retransmissions.
@ibc
Copy link
Member

ibc commented Jun 28, 2022

We use RtpObservers as well. Please clone before.

@jmillan
Copy link
Member Author

jmillan commented Jun 28, 2022

We use RtpObservers as well. Please clone before.

And do they need to access the RtpPacket once after this libuv iteration?

They process the current packet and don't need to access the packet in the future.

@jmillan
Copy link
Member Author

jmillan commented Jun 28, 2022

We can clone the packet before, it's just not needed if there are no Consumers.

@ibc
Copy link
Member

ibc commented Jun 28, 2022

We use RtpObservers as well. Please clone before.

And do they need to access the RtpPacket once after this libuv iteration?

They process the current packet and don't need to access the packet in the future.

This is true for now. Will it be forever?

@jmillan
Copy link
Member Author

jmillan commented Jun 28, 2022

This is true for now. Will it be forever?

v3 does only clone in RtpStreamSend, thus only if Consumers exists.

I've set an explicit comment in Router, before cloning:

			// Clone the packet so it holds its own buffer, usable for future
			// retransmissions.

If you have a preference to always clone a RtpPacket now I won't oppose. We just can save those cycles when no needed.

worker/src/RTC/RtpPacket.cpp Outdated Show resolved Hide resolved
Copy link
Member

@ibc ibc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than pending comment this is great

@jmillan jmillan merged commit b42d907 into v3 Jun 28, 2022
@jmillan jmillan deleted the rtpstreamsend-optimizations branch June 28, 2022 16:23
@nazar-pc
Copy link
Collaborator

🎉

CHANGELOG.md Show resolved Hide resolved
satoren added a commit to satoren/mediasoup that referenced this pull request Jul 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants