From 594c584b4669521b85dbe354af7ccfa2bcf9b617 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 23 Aug 2010 14:38:51 +0200 Subject: Release resources before allocating Before trying to allocate memory we free a large chunk of freeable resources. Leaving the resources unfreed before allocating increases the risks of unnecessarily fragmenting the heap, which is bad, especially for the vram which needs large free contiguous allocations for surfaces. We do somewhat limit the number of resources we free on each call to ensure that we get an approximately even spread of the cost of allocations. --- display/res.c | 81 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/display/res.c b/display/res.c index 6fe375f..eef6a49 100644 --- a/display/res.c +++ b/display/res.c @@ -36,8 +36,6 @@ #define WAIT_FOR_EVENT(pdev, event, timeout) EngWaitForSingleObject(event, timeout) #endif -#define SURFACE_ALLOC_RELEASE_BUNCH_SIZE 3 - static _inline QXLPHYSICAL PA(PDev *pdev, PVOID virt, UINT8 slot_id) { PMemSlot *p_slot = &pdev->mem_slots[slot_id]; @@ -285,10 +283,36 @@ static void WaitForReleaseRing(PDev* pdev) DEBUG_PRINT((pdev, 16, "%s: 0x%lx, done\n", __FUNCTION__, pdev)); } +static void FlushReleaseRing(PDev *pdev) +{ + UINT64 output; + int notify; + int num_to_release = 50; + + output = pdev->Res.free_outputs; + + while (1) { + while (output != 0) { + output = ReleaseOutput(pdev, output); + if (--num_to_release == 0) { + break; + } + } + + if (SPICE_RING_IS_EMPTY(pdev->release_ring)) { + break; + } + + output = *SPICE_RING_CONS_ITEM(pdev->release_ring); + SPICE_RING_POP(pdev->release_ring, notify); + } + + pdev->Res.free_outputs = output; +} + // todo: separate VRAM releases from DEVRAM releases -#define AllocMem(pdev, mspace_type, size) __AllocMem(pdev, mspace_type, size, TRUE, 1) -static void *__AllocMem(PDev* pdev, UINT32 mspace_type, size_t size, - BOOL force, INT32 release_bunch) +#define AllocMem(pdev, mspace_type, size) __AllocMem(pdev, mspace_type, size, TRUE) +static void *__AllocMem(PDev* pdev, UINT32 mspace_type, size_t size, BOOL force) { UINT8 *ptr; @@ -296,35 +320,32 @@ static void *__AllocMem(PDev* pdev, UINT32 mspace_type, size_t size, DEBUG_PRINT((pdev, 12, "%s: 0x%lx size %u\n", __FUNCTION__, pdev, size)); EngAcquireSemaphore(pdev->Res.malloc_sem); - while (!(ptr = mspace_malloc(pdev->Res.mspaces[mspace_type]._mspace, size))) { - int notify; - int num_to_release = release_bunch; - while (pdev->Res.free_outputs && num_to_release) { - pdev->Res.free_outputs = ReleaseOutput(pdev, pdev->Res.free_outputs); - num_to_release--; + while (1) { + /* Release lots of queued resources, before allocating, as we + want to release early to minimize fragmentation risks. */ + FlushReleaseRing(pdev); + + ptr = mspace_malloc(pdev->Res.mspaces[mspace_type]._mspace, size); + if (ptr) { + break; } - if (!num_to_release) { + if (pdev->Res.free_outputs != 0 || + !SPICE_RING_IS_EMPTY(pdev->release_ring)) { + /* We have more things to free, try that */ continue; } if (force) { + /* Ask spice to free some stuff */ WaitForReleaseRing(pdev); } else { - if (SPICE_RING_IS_EMPTY(pdev->release_ring)) { - break; - } - } - - pdev->Res.free_outputs = *SPICE_RING_CONS_ITEM(pdev->release_ring); - SPICE_RING_POP(pdev->release_ring, notify); - - while (pdev->Res.free_outputs && num_to_release) { - pdev->Res.free_outputs = ReleaseOutput(pdev, pdev->Res.free_outputs); - num_to_release--; + /* Fail */ + break; } } + EngReleaseSemaphore(pdev->Res.malloc_sem); ASSERT(pdev, (!ptr && !force) || (ptr >= pdev->Res.mspaces[mspace_type].mspace_start && ptr < pdev->Res.mspaces[mspace_type].mspace_end)); @@ -630,8 +651,7 @@ _inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM: { *stride = x * depth / 8; *stride = ALIGN(*stride, 4); - *base_mem = __AllocMem(pdev, MSPACE_TYPE_VRAM, (*stride) * y, FALSE, - SURFACE_ALLOC_RELEASE_BUNCH_SIZE); + *base_mem = __AllocMem(pdev, MSPACE_TYPE_VRAM, (*stride) * y, FALSE); *phys_mem = PA(pdev, (PVOID)((UINT64)*base_mem), pdev->vram_mem_slot); break; } @@ -1339,14 +1359,11 @@ static CacheImage *AllocCacheImage(PDev* pdev) { RingItem *item; while (!(item = RingGetTail(pdev, &pdev->Res.dynamic->cache_image_lru))) { - int notify; - if (pdev->Res.free_outputs) { - pdev->Res.free_outputs = ReleaseOutput(pdev, pdev->Res.free_outputs); - continue; + if (pdev->Res.free_outputs == 0 && + SPICE_RING_IS_EMPTY(pdev->release_ring)) { + WaitForReleaseRing(pdev); } - WaitForReleaseRing(pdev); - pdev->Res.free_outputs = *SPICE_RING_CONS_ITEM(pdev->release_ring); - SPICE_RING_POP(pdev->release_ring, notify); + FlushReleaseRing(pdev); } RingRemove(pdev, item); return CONTAINEROF(item, CacheImage, lru_link); -- cgit v1.2.3