[Mesa-dev] [PATCH] anv: device: never allocate more memory than heap_size

Nicolas Koch nioko1337 at gmail.com
Thu Sep 22 11:06:28 UTC 2016


Previously, the heap size of a physical device was kind of useless
because it was not enforced.
Now, we keep track of allocation sizes so that the sum of
all allocations can never exceed the heap size advertised by
anv_GetPhysicalDeviceMemoryProperties.
---
 src/intel/vulkan/anv_device.c  | 42 +++++++++++++++++++++++++++++++++---------
 src/intel/vulkan/anv_private.h |  8 ++++++++
 2 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index fecb850..162e372 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -190,6 +190,18 @@ anv_physical_device_init(struct anv_physical_device *device,
    /* XXX: Actually detect bit6 swizzling */
    isl_device_init(&device->isl_dev, device->info, swizzled);
 
+   /* Reserve some wiggle room for the driver by exposing only 75% of the
+    * aperture to the heap.
+    */
+   device->heap_size = 3 * device->aperture_size / 4;
+   device->used_heap_space = 0;
+   int ret = pthread_mutex_init(&device->mutex, NULL);
+   if (ret != 0) {
+      result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+      ralloc_free(device->compiler);
+      goto fail;
+   }
+
    return VK_SUCCESS;
 
 fail:
@@ -202,6 +214,7 @@ anv_physical_device_finish(struct anv_physical_device *device)
 {
    anv_finish_wsi(device);
    ralloc_free(device->compiler);
+   pthread_mutex_destroy(&device->mutex);
 }
 
 static const VkExtensionProperties global_extensions[] = {
@@ -638,12 +651,6 @@ void anv_GetPhysicalDeviceMemoryProperties(
     VkPhysicalDeviceMemoryProperties*           pMemoryProperties)
 {
    ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice);
-   VkDeviceSize heap_size;
-
-   /* Reserve some wiggle room for the driver by exposing only 75% of the
-    * aperture to the heap.
-    */
-   heap_size = 3 * physical_device->aperture_size / 4;
 
    if (physical_device->info->has_llc) {
       /* Big core GPUs share LLC with the CPU and thus one memory type can be
@@ -680,7 +687,7 @@ void anv_GetPhysicalDeviceMemoryProperties(
 
    pMemoryProperties->memoryHeapCount = 1;
    pMemoryProperties->memoryHeaps[0] = (VkMemoryHeap) {
-      .size = heap_size,
+      .size = physical_device->heap_size,
       .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,
    };
 }
@@ -1172,6 +1179,8 @@ VkResult anv_AllocateMemory(
     VkDeviceMemory*                             pMem)
 {
    ANV_FROM_HANDLE(anv_device, device, _device);
+   struct anv_physical_device *physical_device =
+      &device->instance->physicalDevice;
    struct anv_device_memory *mem;
    VkResult result;
 
@@ -1187,20 +1196,28 @@ VkResult anv_AllocateMemory(
    assert(pAllocateInfo->memoryTypeIndex == 0 ||
           (!device->info.has_llc && pAllocateInfo->memoryTypeIndex < 2));
 
-   /* FINISHME: Fail if allocation request exceeds heap size. */
-
    mem = anv_alloc2(&device->alloc, pAllocator, sizeof(*mem), 8,
                     VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    if (mem == NULL)
       return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
 
+   pthread_mutex_lock(&physical_device->mutex);
+
    /* The kernel is going to give us whole pages anyway */
    uint64_t alloc_size = align_u64(pAllocateInfo->allocationSize, 4096);
 
+   if (alloc_size + physical_device->used_heap_space > physical_device->heap_size) {
+        result = vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);
+        goto fail;
+   }
+
    result = anv_bo_init_new(&mem->bo, device, alloc_size);
    if (result != VK_SUCCESS)
       goto fail;
 
+   physical_device->used_heap_space += alloc_size;
+   pthread_mutex_unlock(&physical_device->mutex);
+
    mem->type_index = pAllocateInfo->memoryTypeIndex;
 
    *pMem = anv_device_memory_to_handle(mem);
@@ -1208,6 +1225,7 @@ VkResult anv_AllocateMemory(
    return VK_SUCCESS;
 
  fail:
+   pthread_mutex_unlock(&physical_device->mutex);
    anv_free2(&device->alloc, pAllocator, mem);
 
    return result;
@@ -1220,6 +1238,8 @@ void anv_FreeMemory(
 {
    ANV_FROM_HANDLE(anv_device, device, _device);
    ANV_FROM_HANDLE(anv_device_memory, mem, _mem);
+   struct anv_physical_device *physical_device =
+      &device->instance->physicalDevice;
 
    if (mem == NULL)
       return;
@@ -1230,6 +1250,10 @@ void anv_FreeMemory(
    if (mem->bo.gem_handle != 0)
       anv_gem_close(device, mem->bo.gem_handle);
 
+   pthread_mutex_lock(&physical_device->mutex);
+   physical_device->used_heap_space -= mem->bo.size;
+   pthread_mutex_unlock(&physical_device->mutex);
+
    anv_free2(&device->alloc, pAllocator, mem);
 }
 
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index f578a9d..ec888a6 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -574,6 +574,14 @@ struct anv_physical_device {
     uint32_t                                    subslice_total;
 
     /**
+     * Variables used to track the memory occupied by allocations from
+     * anv_AllocateMemory.
+     */
+    uint64_t                                    heap_size;
+    uint64_t                                    used_heap_space;
+    pthread_mutex_t                             mutex;
+
+    /**
      * Platform specific constants containing the maximum number of threads
      * for each pipeline stage.
      */
-- 
2.10.0



More information about the mesa-dev mailing list