VirtualBox

Changeset 97927 in vbox for trunk/src/VBox/Additions/common


Ignore:
Timestamp:
Dec 31, 2022 12:54:35 AM (2 years ago)
Author:
vboxsync
Message:

Add/VBoxGuestR0LibPhysHeap.cpp: Added some crude code to occasionally scan chunks and merge adjacent free blocks when there.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR0LibPhysHeap.cpp

    r97926 r97927  
    6060 *
    6161 * When freeing blocks, two subsequent free blocks are always merged together.
    62  * Current implementation merges blocks only when there is a free block after
    63  * the just freed one, never when there is one before it as that's too
    64  * expensive.
     62 *
     63 * Since the free list isn't sorted by address or anything, it is expensive to
     64 * determine whether the block before us is free and we should merge with it.
     65 * The current implementation merges blocks only when there is a free block
     66 * after the just freed one, never when there is one before it as that's too
     67 * expensive.  So, to counter this free list fragmentation, we will occasionally
     68 * scan chunks with a majority of free blocks and merge adjacent ones.
    6569 */
    6670
     
    440444
    441445    RTMemContFree(pChunk, pChunk->cbSize);
     446}
     447
     448
     449/**
     450 * Worker for VbglR0PhysHeapFree that merges adjacent free nodes in @a pChunk.
     451 *
     452 * The caller has check that there must be 1 or more such.
     453 */
     454static void vbglR0PhysHeapMergeAdjacentFreeBlocksInChunk(VBGLPHYSHEAPCHUNK *pChunk)
     455{
     456    uintptr_t const    uEnd       = (uintptr_t)pChunk + pChunk->cbSize;
     457    VBGLPHYSHEAPBLOCK *pPrevBlock = NULL;
     458    VBGLPHYSHEAPBLOCK *pCurBlock  = (VBGLPHYSHEAPBLOCK *)(pChunk + 1);
     459    while ((uintptr_t)pCurBlock < uEnd)
     460    {
     461        VBGLPHYSHEAPBLOCK * const pNextBlock = (VBGLPHYSHEAPBLOCK *)((uintptr_t)(pCurBlock + 1) + pCurBlock->cbDataSize);
     462
     463        AssertReturnVoid(pCurBlock->u32Signature == VBGL_PH_BLOCKSIGNATURE);
     464        AssertReturnVoid(pCurBlock->pChunk == pChunk);
     465        if (   !pCurBlock->fAllocated
     466            && pPrevBlock
     467            && !pPrevBlock->fAllocated)
     468        {
     469            /* Adjust size of the previous memory block. */
     470            pPrevBlock->cbDataSize += sizeof(*pCurBlock) + pCurBlock->cbDataSize;
     471
     472            /* Unlink the current block and invalid it. */
     473            vbglPhysHeapUnlinkBlock(pCurBlock);
     474
     475            pCurBlock->u32Signature = ~VBGL_PH_BLOCKSIGNATURE;
     476            pCurBlock->cbDataSize   = UINT32_MAX / 4;
     477
     478            /* The previous node remains the same as we advance to the next one. */
     479        }
     480        else
     481            pPrevBlock = pCurBlock;
     482        pCurBlock = pNextBlock;
     483    }
    442484}
    443485
     
    657699             * Check if the block after this one is also free and we can merge it into
    658700             * this one.
    659              *
    660              * Because the free list isn't sorted by address we cannot cheaply do the
    661              * same for the block before us, so we have to hope for the best for now.
    662701             */
    663             /** @todo When the free:used ration in chunk is too skewed, scan the whole
    664              *        chunk and merge adjacent blocks that way every so often.  Always do so
    665              *        when this is the last used one and we end up with more than 1 free
    666              *        node afterwards. */
    667702            pChunk = pBlock->pChunk;
    668703            pNeighbour = (VBGLPHYSHEAPBLOCK *)((uintptr_t)(pBlock + 1) + pBlock->cbDataSize);
     
    705740                            vbglPhysHeapChunkDelete(pChunk);
    706741                            pNeighbour = pBlock = NULL; /* invalid */
     742                            pChunk = NULL;
    707743                            break;
    708744                        }
    709745                    }
     746                }
     747            }
     748
     749            /*
     750             * Hack to counter the lack of merging with the node before us, scan
     751             * the chunk and merge adjacent free nodes.
     752             */
     753            if (pChunk)
     754            {
     755                int32_t const cAllocBlocks  = pChunk->acBlocks[1 /*alloc*/];
     756                int32_t const cApproxExcess = pChunk->acBlocks[0 /*free*/] - cAllocBlocks - 1;
     757                if (   cApproxExcess > 0 /* there are too many free nodes */
     758                    && cAllocBlocks >= 0 /* sanity check */)
     759                {
     760                    /* Just do the merging if there aren't that many blocks: */
     761                    if (cAllocBlocks <= 4)
     762                        vbglR0PhysHeapMergeAdjacentFreeBlocksInChunk(pChunk);
     763                    /* Do the merging if we're above a 1:2 ratio: */
     764                    else if (cApproxExcess >= cAllocBlocks)
     765                        vbglR0PhysHeapMergeAdjacentFreeBlocksInChunk(pChunk);
    710766                }
    711767            }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette