Add a free FEC block cache to avoid memory allocations

This commit is contained in:
Cameron Gutman 2021-06-09 20:29:05 -05:00
parent fb9aab0e57
commit f01103af23
2 changed files with 64 additions and 3 deletions

View File

@ -81,6 +81,43 @@ static void validateFecBlockState(PRTP_AUDIO_QUEUE queue) {
#endif
}
static PRTPA_FEC_BLOCK allocateFecBlock(PRTP_AUDIO_QUEUE queue, uint32_t blockSize) {
PRTPA_FEC_BLOCK block = queue->freeBlockHead;
if (block != NULL) {
LC_ASSERT(queue->freeBlockCount > 0);
// If the block size matches, we're good to go
if (block->blockSize == blockSize) {
// Advance the free block list to the next entry
queue->freeBlockHead = block->next;
queue->freeBlockCount--;
// Return the new block
return block;
}
else {
// The block size didn't match. This should never happen with GFE
// because it uses constant sized data shards, but Sunshine can
// trigger this condition. If it does happen, let's free the cached
// entry so we can populate the cache with correctly sized blocks.
queue->freeBlockHead = block->next;
queue->freeBlockCount--;
// Free the existing block
free(block);
}
}
else {
LC_ASSERT(queue->freeBlockCount == 0);
}
// We either didn't have any free entries or the block
// size didn't match, so allocate a new FEC block now.
uint16_t dataPacketSize = blockSize + sizeof(RTP_PACKET);
return malloc(sizeof(*block) + (RTPA_DATA_SHARDS * dataPacketSize) + (RTPA_FEC_SHARDS * blockSize));
}
static void freeFecBlockHead(PRTP_AUDIO_QUEUE queue) {
PRTPA_FEC_BLOCK blockHead = queue->blockHead;
@ -97,7 +134,16 @@ static void freeFecBlockHead(PRTP_AUDIO_QUEUE queue) {
validateFecBlockState(queue);
free(blockHead);
if (queue->freeBlockCount >= RTPA_CACHED_FEC_BLOCK_LIMIT) {
// Too many entries cached, so just free this one
free(blockHead);
}
else {
// Place this entry at the head of the free list for better cache behavior
blockHead->next = queue->freeBlockHead;
queue->freeBlockHead = blockHead;
queue->freeBlockCount++;
}
}
void RtpaCleanupQueue(PRTP_AUDIO_QUEUE queue) {
@ -109,6 +155,15 @@ void RtpaCleanupQueue(PRTP_AUDIO_QUEUE queue) {
queue->blockTail = NULL;
while (queue->freeBlockHead != NULL) {
PRTPA_FEC_BLOCK block = queue->freeBlockHead;
queue->freeBlockHead = block->next;
queue->freeBlockCount--;
free(block);
}
LC_ASSERT(queue->freeBlockCount == 0);
reed_solomon_release(queue->rs);
queue->rs = NULL;
}
@ -227,9 +282,9 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
existingBlock = existingBlock->next;
}
// We didn't find an existing FEC block, so we'll have to make one
// We didn't find an existing FEC block, so we'll have to allocate one
uint16_t dataPacketSize = blockSize + sizeof(RTP_PACKET);
PRTPA_FEC_BLOCK block = malloc(sizeof(*block) + (RTPA_DATA_SHARDS * dataPacketSize) + (RTPA_FEC_SHARDS * blockSize));
PRTPA_FEC_BLOCK block = allocateFecBlock(queue, blockSize);
if (block == NULL) {
return NULL;
}

View File

@ -12,6 +12,9 @@
#define RTPA_FEC_SHARDS 2
#define RTPA_TOTAL_SHARDS (RTPA_DATA_SHARDS + RTPA_FEC_SHARDS)
// Maximum number of FEC block entries to cache
#define RTPA_CACHED_FEC_BLOCK_LIMIT 4
typedef struct _AUDIO_FEC_HEADER {
uint8_t fecShardIndex;
uint8_t payloadType;
@ -50,6 +53,9 @@ typedef struct _RTP_AUDIO_QUEUE {
reed_solomon* rs;
PRTPA_FEC_BLOCK freeBlockHead;
uint16_t freeBlockCount;
uint16_t nextRtpSequenceNumber;
uint16_t oldestRtpBaseSequenceNumber;