Mesa (master): winsys/svga: Rework buffer allocation to make it more robust v2.

Thomas Hellstrom thomash at kemper.freedesktop.org
Fri Oct 14 00:55:39 PDT 2011


Module: Mesa
Branch: master
Commit: 5dddeb7776c62b6218add3a236551cde876b1cf0
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=5dddeb7776c62b6218add3a236551cde876b1cf0

Author: Thomas Hellstrom <thellstrom at vmware.com>
Date:   Wed Oct 12 15:27:10 2011 +0200

winsys/svga: Rework buffer allocation to make it more robust v2.

Don't allow any "CPU" buffers to be allocated by the pb_fenced
buffer manager, since we can't protect against failures during
buffer validation.
Also, add an extra slab buffer manager to allocate buffers from
the kernel if there is a failure to allocate from our big buffer pool.
The reason we use a slab manager for this, is to avoid allocating
many very small buffers from the kernel.

v2: Increased VMW_MAX_BUFFER_SIZE and fixed some comments.

Signed-off-by: Thomas Hellstrom <thellstrom at vmware.com>
Reviewed-by: José Fonseca <jfonseca at vmware.com>
Reviewed-by: Jakob Bornecrantz <jakob at vmware.com>

---

 src/gallium/winsys/svga/drm/vmw_screen.h       |    8 +++
 src/gallium/winsys/svga/drm/vmw_screen_pools.c |   56 +++++++++++++++++-------
 src/gallium/winsys/svga/drm/vmw_screen_svga.c  |   10 ++++-
 3 files changed, 57 insertions(+), 17 deletions(-)

diff --git a/src/gallium/winsys/svga/drm/vmw_screen.h b/src/gallium/winsys/svga/drm/vmw_screen.h
index 37ccc91..1ddebf2 100644
--- a/src/gallium/winsys/svga/drm/vmw_screen.h
+++ b/src/gallium/winsys/svga/drm/vmw_screen.h
@@ -43,6 +43,12 @@
 
 #define VMW_GMR_POOL_SIZE (16*1024*1024)
 #define VMW_QUERY_POOL_SIZE (8192)
+/*
+ * Something big, but arbitrary. The kernel reports an error if it can't
+ * handle this, and the svga driver will resort to multiple partial
+ * uploads.
+ */
+#define VMW_MAX_BUFFER_SIZE (512*1024*1024)
 
 struct pb_manager;
 struct vmw_region;
@@ -65,6 +71,8 @@ struct vmw_winsys_screen
       struct pb_manager *gmr;
       struct pb_manager *gmr_mm;
       struct pb_manager *gmr_fenced;
+      struct pb_manager *gmr_slab;
+      struct pb_manager *gmr_slab_fenced;
       struct pb_manager *query;
       struct pb_manager *query_mm;
       struct pb_manager *query_fenced;
diff --git a/src/gallium/winsys/svga/drm/vmw_screen_pools.c b/src/gallium/winsys/svga/drm/vmw_screen_pools.c
index 6350ea3..2525604 100644
--- a/src/gallium/winsys/svga/drm/vmw_screen_pools.c
+++ b/src/gallium/winsys/svga/drm/vmw_screen_pools.c
@@ -54,6 +54,9 @@ vmw_pools_cleanup(struct vmw_winsys_screen *vws)
 
    /* gmr_mm pool is already destroyed above */
 
+   if (vws->pools.gmr_slab_fenced)
+      vws->pools.gmr_slab_fenced->destroy(vws->pools.gmr_slab_fenced);
+
    if(vws->pools.gmr)
       vws->pools.gmr->destroy(vws->pools.gmr);
    if(vws->pools.query)
@@ -110,6 +113,8 @@ vmw_query_pools_init(struct vmw_winsys_screen *vws)
 boolean
 vmw_pools_init(struct vmw_winsys_screen *vws)
 {
+   struct pb_desc desc;
+
    vws->pools.gmr = vmw_gmr_bufmgr_create(vws);
    if(!vws->pools.gmr)
       goto error;
@@ -121,26 +126,18 @@ vmw_pools_init(struct vmw_winsys_screen *vws)
       goto error;
 
    /*
-    * GMR buffers are typically shortlived, but it's possible that at a given
-    * instance a buffer is mapped. So to avoid stalling we tell pipebuffer to
-    * forbid creation of buffers beyond half the GMR pool size,
-    *
-    * XXX: It is unclear weather we want to limit the total amount of temporary
-    * malloc memory used to backup unvalidated GMR buffers. On one hand it is
-    * preferrable to fail an allocation than exhausting the guest memory with
-    * temporary data, but on the other hand it is possible that a stupid
-    * application creates large vertex buffers and does not use them for a long
-    * time -- since the svga pipe driver only emits the DMA uploads when a
-    * buffer is used for drawing this would effectively disabling swapping GMR
-    * buffers to memory. So far, the preemptively flush already seems to keep
-    * total allocated memory within relatively small numbers, so we don't
-    * limit.
+    * We disallow "CPU" buffers to be created by the fenced_bufmgr_create,
+    * because that defers "GPU" buffer creation to buffer validation,
+    * and at buffer validation we have no means of handling failures
+    * due to pools space shortage or fragmentation. Effectively this
+    * makes sure all failures are reported immediately on buffer allocation,
+    * and we can revert to allocating directly from the kernel.
     */
    vws->pools.gmr_fenced = fenced_bufmgr_create(
       vws->pools.gmr_mm,
       vmw_fence_ops_create(vws),
-      VMW_GMR_POOL_SIZE/2,
-      ~0);
+      VMW_GMR_POOL_SIZE,
+      0);
 
 #ifdef DEBUG
    vws->pools.gmr_fenced = pb_debug_manager_create(vws->pools.gmr_fenced,
@@ -150,6 +147,33 @@ vmw_pools_init(struct vmw_winsys_screen *vws)
    if(!vws->pools.gmr_fenced)
       goto error;
 
+   /*
+    * The slab pool allocates buffers directly from the kernel except
+    * for very small buffers which are allocated from a slab in order
+    * not to waste memory, since a kernel buffer is a minimum 4096 bytes.
+    *
+    * Here we use it only for emergency in the case our pre-allocated
+    * buffer pool runs out of memory.
+    */
+   desc.alignment = 64;
+   desc.usage = ~0;
+   vws->pools.gmr_slab = pb_slab_range_manager_create(vws->pools.gmr,
+						      64,
+						      8192,
+						      16384,
+						      &desc);
+   if (!vws->pools.gmr_slab)
+       goto error;
+
+   vws->pools.gmr_slab_fenced =
+       fenced_bufmgr_create(vws->pools.gmr_slab,
+			    vmw_fence_ops_create(vws),
+			    VMW_MAX_BUFFER_SIZE,
+			    0);
+
+   if (!vws->pools.gmr_slab_fenced)
+       goto error;
+
    vws->pools.query_fenced = NULL;
    vws->pools.query_mm = NULL;
    vws->pools.query = NULL;
diff --git a/src/gallium/winsys/svga/drm/vmw_screen_svga.c b/src/gallium/winsys/svga/drm/vmw_screen_svga.c
index df4a384..bf817ca 100644
--- a/src/gallium/winsys/svga/drm/vmw_screen_svga.c
+++ b/src/gallium/winsys/svga/drm/vmw_screen_svga.c
@@ -73,7 +73,15 @@ vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
 
    assert(provider);
    buffer = provider->create_buffer(provider, size, &desc);
-   if(!buffer)
+
+   if(!buffer && provider == vws->pools.gmr_fenced) {
+
+      assert(provider);
+      provider = vws->pools.gmr_slab_fenced;
+      buffer = provider->create_buffer(provider, size, &desc);
+   }
+
+   if (!buffer)
       return NULL;
 
    return vmw_svga_winsys_buffer(buffer);



More information about the mesa-commit mailing list