-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Reduce use of maximum-sized packet buffers #4434
Conversation
#### Problem CHIP code contains many uses of PacketBuffer::New(), which allocates a maximum-size buffer. This is often much larger than actually required, which wastes heap. #### Summary of Changes - Replaced `PacketBuffer::New()` and `NewWithAvailableSize()` with `PacketBufferHandle::New()`, which requires an explicit packet size. (The parameter order is opposite to the old `NewWithAvailableSize()` because the reserved size is usually the default.) Made the available parameter a `size_t` because for many callers it originates as such, and `New()` already checks it; this allows removing `CanCastTo` tests from callers. Also, documented the guarantee that `New()` never returns a buffer with less space than requested, and removed post-New size tests. - Added `NewWithData()` to encapsulate a common use of `New()`, and reduce the risk of length errors between the steps. - Implemented `RightSize()` for the heap allocation case. - Added constants `kMaxPacketBufferSizeWithoutReserve` and `kMaxPacketBufferSize` for use where the maximum size is required or the size is unknown. - Added `kMaxIPAddressStringLength` for `NetworkProvisioning::SendIPAddress`. - Added `NetworkProvisioning::EncodedStringSize()` for `SendNetworkCredentials()`. - Moved some size constants into BLE header files. fixes project-chip#4351 - Reduce use of maximum-sized packet buffers
Dibs on these bytes to add a |
Size increase report for "esp32-example-build" from ab81fbb
Full report output
|
Size increase report for "nrfconnect-example-build" from ab81fbb
Full report output
|
@kpschoedel conflicts? |
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.
LGTM overall, but please address comments, perhaps in a follow-up
src/inet/TCPEndPoint.cpp
Outdated
@@ -2404,12 +2404,12 @@ void TCPEndPoint::ReceiveData() | |||
bool isNewBuf = true; | |||
|
|||
if (mRcvQueue.IsNull()) | |||
rcvBuf = PacketBuffer::New(0); | |||
rcvBuf = System::PacketBufferHandle::New(System::kMaxPacketBufferSizeWithoutReserve, 0); |
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.
This should actually be a "max TCP CHIP message size" cosntant.
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 see an existing one; what's the right place for it?
src/lib/core/tests/TestCHIPTLV.cpp
Outdated
@@ -1948,7 +1948,7 @@ void WriteDeleteReadTest(nlTestSuite * inSuite) | |||
*/ | |||
void CheckPacketBuffer(nlTestSuite * inSuite, void * inContext) | |||
{ | |||
System::PacketBufferHandle buf = System::PacketBuffer::New(0); | |||
System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::kMaxPacketBufferSizeWithoutReserve, 0); |
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.
Again, we should have some more explicit size than this weird system default
@@ -344,7 +344,7 @@ CHIP_ERROR ReliableMessageContext::SendStandaloneAckMessage() | |||
CHIP_ERROR err = CHIP_NO_ERROR; | |||
|
|||
// Allocate a buffer for the null message | |||
System::PacketBufferHandle msgBuf = System::PacketBuffer::NewWithAvailableSize(0); | |||
System::PacketBufferHandle msgBuf = System::PacketBufferHandle::New(0); |
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.
This doesn't make it clear that all overhead is swallowed in "reserved" default argument. Suggest making the default reserved argument explicit here.
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.
Will do.
ctx.GetInetLayer().SystemLayer()->Init(nullptr); | ||
|
||
chip::System::PacketBufferHandle buffer = chip::System::PacketBuffer::NewWithAvailableSize(payload_len); | ||
chip::System::PacketBufferHandle buffer = chip::System::PacketBufferHandle::NewWithData(PAYLOAD, sizeof PAYLOAD, kMaxTagLen); |
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.
Weird that it's not sizeof(PAYLOAD)
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.
sizeof
is an operator with a special case for types; it's “sizeof
expr” like “–
expr”, or “sizeof (
type)
” like a cast. Of course “(
expr)
” is a valid expr, so I'll add the parens if it's distracting. (Surprised clang-format doesn't force it one way or the other.)
src/system/SystemPacketBuffer.cpp
Outdated
// Reallocate only if enough space will be saved. | ||
uint8_t * const start = reinterpret_cast<uint8_t *>(mBuffer) + CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE; | ||
uint8_t * const payload = reinterpret_cast<uint8_t *>(mBuffer->payload); | ||
const uint16_t usedSize = static_cast<uint16_t>(payload - start + mBuffer->len); |
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.
This should use size_t
, and only use downscaling to uint16_t if needed.=
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.
Will do
memcpy(other->Start(), mBuffer->Start(), mBuffer->DataLength()); | ||
other->SetDataLength(mBuffer->DataLength()); | ||
const uint16_t blockSize = usedSize + CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE; | ||
PacketBuffer * newBuffer = reinterpret_cast<PacketBuffer *>(chip::Platform::MemoryAlloc(blockSize)); |
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.
Could this use a Realloc-like API (did not check if we have it) followed by a memmove below?
@@ -124,6 +124,11 @@ CHIP_ERROR NetworkProvisioning::HandleNetworkProvisioningMessage(uint8_t msgType | |||
return err; | |||
} | |||
|
|||
uint16_t NetworkProvisioning::EncodedStringSize(const char * str) | |||
{ | |||
return static_cast<uint16_t>(strlen(str) + sizeof(uint16_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.
return static_cast<uint16_t>(strlen(str) + sizeof(uint16_t)); | |
return static_cast<uint16_t>(sizeof(uint16_t) + strlen(str)); |
Also suggest using size_t here, not uint16_t, or at least internally use size_t and ensure it fits within 16 bits
System::PacketBufferHandle buffer = System::PacketBufferHandle::New(Inet::kMaxIPAddressStringLength); | ||
VerifyOrExit(!buffer.IsNull(), err = CHIP_ERROR_NO_MEMORY); | ||
addrStr = addr.ToString(Uint8::to_char(buffer->Start()), buffer->AvailableDataLength()); | ||
buffer->SetDataLength(static_cast<uint16_t>(strlen(addrStr) + 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.
Why the +1? Should this be +2 ?
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 matches what the code did, but maybe that's wrong. Is it supposed to use EncodeString
?
newBuffer->len = mBuffer->len; | ||
newBuffer->ref = 1; | ||
newBuffer->alloc_size = static_cast<uint16_t>(usedSize); | ||
memcpy(reinterpret_cast<uint8_t *>(newBuffer) + CHIP_SYSTEM_PACKETBUFFER_HEADER_SIZE, start, usedSize); |
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.
This doesn't follow the chain. Rightsizing is to get a single linear buffer of correct chain from a single PacketBuffer of size > optiomal OR from a chain. This would need to take in account the chain, otherwise this may copy past the end of the buffer. I am surprised to see ->len
being used directly, rather than looking at the entire chain (e.g. equivalent of TotalLength)
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.
Yes. I thought I had written that, but evidently didn't (or misplaced it on another branch). Will move to draft until I add 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.
Memory has been refreshed. The LwIP implementation also does not support chains, so I added the comment to call CompactHead()
first for that case. If RightSize()
itself needs to handle chains, I'd rather land that separately.
@kpschoedel there are a ton of merge conflicts here, can you resolve and re-request review? Thanks! |
@tcarmelveilleux - does this look good to you now? @saurabhst @jelderton can you folks take a peek too? |
Still draft; I still want to merge over the correct |
Actually, changed my mind on that. |
Appears all @tcarmelveilleux 's comments are addressed. Approving/merging. |
* Reduce use of maximum-sized packet buffers CHIP code contains many uses of PacketBuffer::New(), which allocates a maximum-size buffer. This is often much larger than actually required, which wastes heap. - Replaced `PacketBuffer::New()` and `NewWithAvailableSize()` with `PacketBufferHandle::New()`, which requires an explicit packet size. (The parameter order is opposite to the old `NewWithAvailableSize()` because the reserved size is usually the default.) Made the available parameter a `size_t` because for many callers it originates as such, and `New()` already checks it; this allows removing `CanCastTo` tests from callers. Also, documented the guarantee that `New()` never returns a buffer with less space than requested, and removed post-New size tests. - Added `NewWithData()` to encapsulate a common use of `New()`, and reduce the risk of length errors between the steps. - Implemented `RightSize()` for the heap allocation case. - Added constants `kMaxPacketBufferSizeWithoutReserve` and `kMaxPacketBufferSize` for use where the maximum size is required or the size is unknown. - Added `kMaxIPAddressStringLength` for `NetworkProvisioning::SendIPAddress`. - Added `NetworkProvisioning::EncodedStringSize()` for `SendNetworkCredentials()`. - Moved some size constants into BLE header files. fixes project-chip#4351 - Reduce use of maximum-sized packet buffers * Fix merge of remote-tracking branch 'origin/master' into x4351-new * review * restyled
* Reduce use of maximum-sized packet buffers CHIP code contains many uses of PacketBuffer::New(), which allocates a maximum-size buffer. This is often much larger than actually required, which wastes heap. - Replaced `PacketBuffer::New()` and `NewWithAvailableSize()` with `PacketBufferHandle::New()`, which requires an explicit packet size. (The parameter order is opposite to the old `NewWithAvailableSize()` because the reserved size is usually the default.) Made the available parameter a `size_t` because for many callers it originates as such, and `New()` already checks it; this allows removing `CanCastTo` tests from callers. Also, documented the guarantee that `New()` never returns a buffer with less space than requested, and removed post-New size tests. - Added `NewWithData()` to encapsulate a common use of `New()`, and reduce the risk of length errors between the steps. - Implemented `RightSize()` for the heap allocation case. - Added constants `kMaxPacketBufferSizeWithoutReserve` and `kMaxPacketBufferSize` for use where the maximum size is required or the size is unknown. - Added `kMaxIPAddressStringLength` for `NetworkProvisioning::SendIPAddress`. - Added `NetworkProvisioning::EncodedStringSize()` for `SendNetworkCredentials()`. - Moved some size constants into BLE header files. fixes project-chip#4351 - Reduce use of maximum-sized packet buffers * Fix merge of remote-tracking branch 'origin/master' into x4351-new * review * restyled
* Reduce use of maximum-sized packet buffers #### Problem CHIP code contains many uses of PacketBuffer::New(), which allocates a maximum-size buffer. This is often much larger than actually required, which wastes heap. #### Summary of Changes - Replaced `PacketBuffer::New()` and `NewWithAvailableSize()` with `PacketBufferHandle::New()`, which requires an explicit packet size. (The parameter order is opposite to the old `NewWithAvailableSize()` because the reserved size is usually the default.) Made the available parameter a `size_t` because for many callers it originates as such, and `New()` already checks it; this allows removing `CanCastTo` tests from callers. Also, documented the guarantee that `New()` never returns a buffer with less space than requested, and removed post-New size tests. - Added `NewWithData()` to encapsulate a common use of `New()`, and reduce the risk of length errors between the steps. - Implemented `RightSize()` for the heap allocation case. - Added constants `kMaxPacketBufferSizeWithoutReserve` and `kMaxPacketBufferSize` for use where the maximum size is required or the size is unknown. - Added `kMaxIPAddressStringLength` for `NetworkProvisioning::SendIPAddress`. - Added `NetworkProvisioning::EncodedStringSize()` for `SendNetworkCredentials()`. - Moved some size constants into BLE header files. fixes project-chip#4351 - Reduce use of maximum-sized packet buffers * Fix merge of remote-tracking branch 'origin/master' into x4351-new * review * restyled
As of a868187 ("Reduce use of maximum-sized packet buffers (project-chip#4434)"), network provisioning does not allocate enough space to encrypt the WiFi credentials payload, resulting in the following error: CHIP:NP: Failed in sending Network Creds. error Error 4047 (0x00000FCF) Pending API improvements to make these errors less likely, manually add the needed extra space at allocation time. Fixes project-chip#4823
As of a868187 ("Reduce use of maximum-sized packet buffers (#4434)"), network provisioning does not allocate enough space to encrypt the WiFi credentials payload, resulting in the following error: CHIP:NP: Failed in sending Network Creds. error Error 4047 (0x00000FCF) Pending API improvements to make these errors less likely, manually add the needed extra space at allocation time. Fixes #4823
Problem
CHIP code contains many uses of PacketBuffer::New(), which allocates a
maximum-size buffer. This is often much larger than actually required,
which wastes heap.
Summary of Changes
PacketBuffer::New()
andNewWithAvailableSize()
withPacketBufferHandle::New()
, which requires an explicit packet size.(The parameter order is opposite to the old
NewWithAvailableSize()
because the reserved size is usually the default.) Made the available
parameter a
size_t
because for many callers it originates as such,and
New()
already checks it; this allows removingCanCastTo
testsfrom callers. Also, documented the guarantee that
New()
neverreturns a buffer with less space than requested, and removed post-New
size tests.
NewWithData()
to encapsulate a common use ofNew()
, andreduce the risk of length errors between the steps.
RightSize()
for the heap allocation case.kMaxPacketBufferSizeWithoutReserve
andkMaxPacketBufferSize
for use where the maximum size is required orthe size is unknown.
kMaxIPAddressStringLength
forNetworkProvisioning::SendIPAddress
.NetworkProvisioning::EncodedStringSize()
forSendNetworkCredentials()
.fixes #4351 - Reduce use of maximum-sized packet buffers