[RFC,14/14] anv/allocator: Add support for non-userptr.

Submitted by Rafael Antognolli on Dec. 8, 2018, 12:05 a.m.

Details

Message ID 20181208000553.29501-15-rafael.antognolli@intel.com
State New
Headers show
Series "Do not use userptr in anv if softpin is available." ( rev: 1 ) in Mesa

Not browsing as part of any series.

Commit Message

Rafael Antognolli Dec. 8, 2018, 12:05 a.m.
If softpin is supported, create new BOs for the required size and add the
respective BO maps. The other main change of this commit is that
anv_block_pool_map() now returns the map for the BO that the given
offset is part of. So there's no block_pool->map access anymore (when
softpin is used.
---
 src/intel/vulkan/anv_allocator.c | 92 ++++++++++++++++++--------------
 1 file changed, 53 insertions(+), 39 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/intel/vulkan/anv_allocator.c b/src/intel/vulkan/anv_allocator.c
index 0d426edfb57..46f2278a56c 100644
--- a/src/intel/vulkan/anv_allocator.c
+++ b/src/intel/vulkan/anv_allocator.c
@@ -473,17 +473,19 @@  anv_block_pool_init(struct anv_block_pool *pool,
    pool->size = 0;
    pool->start_address = gen_canonical_address(start_address);
 
-   pool->fd = memfd_create("block pool", MFD_CLOEXEC);
-   if (pool->fd == -1)
-      return vk_error(VK_ERROR_INITIALIZATION_FAILED);
-
-   /* Just make it 2GB up-front.  The Linux kernel won't actually back it
-    * with pages until we either map and fault on one of them or we use
-    * userptr and send a chunk of it off to the GPU.
-    */
-   if (ftruncate(pool->fd, BLOCK_POOL_MEMFD_SIZE) == -1) {
-      result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
-      goto fail_fd;
+   if (!(pool->bo_flags & EXEC_OBJECT_PINNED)) {
+      pool->fd = memfd_create("block pool", MFD_CLOEXEC);
+      if (pool->fd == -1)
+         return vk_error(VK_ERROR_INITIALIZATION_FAILED);
+
+      /* Just make it 2GB up-front.  The Linux kernel won't actually back it
+       * with pages until we either map and fault on one of them or we use
+       * userptr and send a chunk of it off to the GPU.
+       */
+      if (ftruncate(pool->fd, BLOCK_POOL_MEMFD_SIZE) == -1) {
+         result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
+         goto fail_fd;
+      }
    }
 
    if (!u_vector_init(&pool->mmap_cleanups,
@@ -507,7 +509,8 @@  anv_block_pool_init(struct anv_block_pool *pool,
  fail_mmap_cleanups:
    u_vector_finish(&pool->mmap_cleanups);
  fail_fd:
-   close(pool->fd);
+   if (!(pool->bo_flags & EXEC_OBJECT_PINNED))
+      close(pool->fd);
 
    return result;
 }
@@ -525,8 +528,9 @@  anv_block_pool_finish(struct anv_block_pool *pool)
    }
 
    u_vector_finish(&pool->mmap_cleanups);
+   if (!(pool->bo_flags & EXEC_OBJECT_PINNED))
+      close(pool->fd);
 
-   close(pool->fd);
    anv_block_pool_bo_finish(pool);
 }
 
@@ -537,6 +541,7 @@  anv_block_pool_expand_range(struct anv_block_pool *pool,
    void *map;
    uint32_t gem_handle;
    struct anv_mmap_cleanup *cleanup;
+   const bool use_softpin = !!(pool->bo_flags & EXEC_OBJECT_PINNED);
 
    /* Assert that we only ever grow the pool */
    assert(center_bo_offset >= pool->back_state.end);
@@ -544,7 +549,8 @@  anv_block_pool_expand_range(struct anv_block_pool *pool,
 
    /* Assert that we don't go outside the bounds of the memfd */
    assert(center_bo_offset <= BLOCK_POOL_MEMFD_CENTER);
-   assert(size - center_bo_offset <=
+   assert(use_softpin ||
+          size - center_bo_offset <=
           BLOCK_POOL_MEMFD_SIZE - BLOCK_POOL_MEMFD_CENTER);
 
    cleanup = u_vector_add(&pool->mmap_cleanups);
@@ -553,28 +559,36 @@  anv_block_pool_expand_range(struct anv_block_pool *pool,
 
    *cleanup = ANV_MMAP_CLEANUP_INIT;
 
-   /* Just leak the old map until we destroy the pool.  We can't munmap it
-    * without races or imposing locking on the block allocate fast path. On
-    * the whole the leaked maps adds up to less than the size of the
-    * current map.  MAP_POPULATE seems like the right thing to do, but we
-    * should try to get some numbers.
-    */
-   map = mmap(NULL, size, PROT_READ | PROT_WRITE,
-              MAP_SHARED | MAP_POPULATE, pool->fd,
-              BLOCK_POOL_MEMFD_CENTER - center_bo_offset);
-   if (map == MAP_FAILED)
-      return vk_errorf(pool->device->instance, pool->device,
-                       VK_ERROR_MEMORY_MAP_FAILED, "mmap failed: %m");
-
-   gem_handle = anv_gem_userptr(pool->device, map, size);
-   if (gem_handle == 0) {
-      munmap(map, size);
-      return vk_errorf(pool->device->instance, pool->device,
-                       VK_ERROR_TOO_MANY_OBJECTS, "userptr failed: %m");
+   uint32_t newbo_size = size - pool->size;
+   if (use_softpin) {
+      gem_handle = anv_gem_create(pool->device, newbo_size);
+      map = anv_gem_mmap(pool->device, gem_handle, 0, newbo_size, 0);
+      if (map == MAP_FAILED)
+         return vk_errorf(pool->device->instance, pool->device,
+                          VK_ERROR_MEMORY_MAP_FAILED, "gem mmap failed: %m");
+   } else {
+      /* Just leak the old map until we destroy the pool.  We can't munmap it
+       * without races or imposing locking on the block allocate fast path. On
+       * the whole the leaked maps adds up to less than the size of the
+       * current map.  MAP_POPULATE seems like the right thing to do, but we
+       * should try to get some numbers.
+       */
+      map = mmap(NULL, size, PROT_READ | PROT_WRITE,
+                 MAP_SHARED | MAP_POPULATE, pool->fd,
+                 BLOCK_POOL_MEMFD_CENTER - center_bo_offset);
+      if (map == MAP_FAILED)
+         return vk_errorf(pool->device->instance, pool->device,
+                          VK_ERROR_MEMORY_MAP_FAILED, "mmap failed: %m");
+      gem_handle = anv_gem_userptr(pool->device, map, size);
+      if (gem_handle == 0) {
+         munmap(map, size);
+         return vk_errorf(pool->device->instance, pool->device,
+                          VK_ERROR_TOO_MANY_OBJECTS, "userptr failed: %m");
+      }
    }
 
    cleanup->map = map;
-   cleanup->size = size;
+   cleanup->size = use_softpin ? newbo_size : size;
    cleanup->gem_handle = gem_handle;
 
 #if 0
@@ -593,7 +607,9 @@  anv_block_pool_expand_range(struct anv_block_pool *pool,
 
    /* Now that we successfull allocated everything, we can write the new
     * values back into pool. */
-   pool->map = map + center_bo_offset;
+   if (!use_softpin) {
+      pool->map = map + center_bo_offset;
+   }
    pool->center_bo_offset = center_bo_offset;
 
    /* For block pool BOs we have to be a bit careful about where we place them
@@ -628,7 +644,7 @@  anv_block_pool_expand_range(struct anv_block_pool *pool,
     * range. On the other hand, if not using softpin, we need to add a BO if we
     * don't have one yet.
     */
-   if (!pool->bo) {
+   if (use_softpin || !pool->bo) {
       bo_elem = malloc(sizeof(*bo_elem));
       bo = &bo_elem->bo;
    } else {
@@ -639,10 +655,9 @@  anv_block_pool_expand_range(struct anv_block_pool *pool,
    if (!pool->bo)
       pool->bo = bo;
 
-   anv_bo_init(bo, gem_handle, size);
+   anv_bo_init(bo, gem_handle, use_softpin ? newbo_size : size);
    if (pool->bo_flags & EXEC_OBJECT_PINNED) {
-      bo->offset = pool->start_address + BLOCK_POOL_MEMFD_CENTER -
-         center_bo_offset;
+      bo->offset = pool->start_address + pool->size;
    }
    bo->flags = pool->bo_flags;
    bo->map = map;
@@ -850,7 +865,6 @@  anv_block_pool_alloc_new(struct anv_block_pool *pool,
    while (1) {
       state.u64 = __sync_fetch_and_add(&pool_state->u64, block_size);
       if (state.next + block_size <= state.end) {
-         assert(pool->map);
          return state.next;
       } else if (state.next <= state.end) {
          if (pool->bo_flags & EXEC_OBJECT_PINNED && state.next < state.end) {