llvmpipe: add compute threadpool + mutex
authorDave Airlie <airlied@redhat.com>
Tue, 27 Aug 2019 02:45:39 +0000 (12:45 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 4 Sep 2019 05:22:20 +0000 (15:22 +1000)
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
In order to efficiently run a number of compute blocks, use
a threadpool that just allows for jobs with unique sequential
ids to be dispatched.

src/gallium/drivers/llvmpipe/Makefile.sources
src/gallium/drivers/llvmpipe/lp_cs_tpool.c [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_cs_tpool.h [new file with mode: 0644]
src/gallium/drivers/llvmpipe/lp_screen.c
src/gallium/drivers/llvmpipe/lp_screen.h
src/gallium/drivers/llvmpipe/meson.build

index d928ccb..4312ddc 100644 (file)
@@ -13,6 +13,8 @@ C_SOURCES := \
        lp_clear.h \
        lp_context.c \
        lp_context.h \
+       lp_cs_tpool.c \
+       lp_cs_tpool.h \
        lp_debug.h \
        lp_draw_arrays.c \
        lp_fence.c \
diff --git a/src/gallium/drivers/llvmpipe/lp_cs_tpool.c b/src/gallium/drivers/llvmpipe/lp_cs_tpool.c
new file mode 100644 (file)
index 0000000..0449572
--- /dev/null
@@ -0,0 +1,153 @@
+/**************************************************************************
+ *
+ * Copyright 2019 Red Hat.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * compute shader thread pool.
+ * based on threadpool.c but modified heavily to be compute shader tuned.
+ */
+
+#include "util/u_thread.h"
+#include "util/u_memory.h"
+#include "lp_cs_tpool.h"
+
+static int
+lp_cs_tpool_worker(void *data)
+{
+   struct lp_cs_tpool *pool = data;
+   struct lp_cs_local_mem lmem;
+
+   memset(&lmem, 0, sizeof(lmem));
+   mtx_lock(&pool->m);
+
+   while (!pool->shutdown) {
+      struct lp_cs_tpool_task *task;
+
+      while (list_empty(&pool->workqueue) && !pool->shutdown)
+         cnd_wait(&pool->new_work, &pool->m);
+
+      if (pool->shutdown)
+         break;
+
+      task = list_first_entry(&pool->workqueue, struct lp_cs_tpool_task,
+                              list);
+      unsigned this_iter = task->iter_start++;
+
+      if (task->iter_start == task->iter_total)
+         list_del(&task->list);
+
+      mtx_unlock(&pool->m);
+      task->work(task->data, this_iter, &lmem);
+      mtx_lock(&pool->m);
+      task->iter_finished++;
+      if (task->iter_finished == task->iter_total)
+         cnd_broadcast(&task->finish);
+   }
+   mtx_unlock(&pool->m);
+   free(lmem.local_mem_ptr);
+   return 0;
+}
+
+struct lp_cs_tpool *
+lp_cs_tpool_create(unsigned num_threads)
+{
+   struct lp_cs_tpool *pool = CALLOC_STRUCT(lp_cs_tpool);
+
+   if (!pool)
+      return NULL;
+
+   (void) mtx_init(&pool->m, mtx_plain);
+   cnd_init(&pool->new_work);
+
+   list_inithead(&pool->workqueue);
+   assert (num_threads <= LP_MAX_THREADS);
+   pool->num_threads = num_threads;
+   for (unsigned i = 0; i < num_threads; i++)
+      pool->threads[i] = u_thread_create(lp_cs_tpool_worker, pool);
+   return pool;
+}
+
+void
+lp_cs_tpool_destroy(struct lp_cs_tpool *pool)
+{
+   if (!pool)
+      return;
+
+   mtx_lock(&pool->m);
+   pool->shutdown = true;
+   cnd_broadcast(&pool->new_work);
+   mtx_unlock(&pool->m);
+
+   for (unsigned i = 0; i < pool->num_threads; i++) {
+      thrd_join(pool->threads[i], NULL);
+   }
+
+   cnd_destroy(&pool->new_work);
+   mtx_destroy(&pool->m);
+   free(pool);
+}
+
+struct lp_cs_tpool_task *
+lp_cs_tpool_queue_task(struct lp_cs_tpool *pool,
+                       lp_cs_tpool_task_func work, void *data, int num_iters)
+{
+   struct lp_cs_tpool_task *task;
+
+   task = CALLOC_STRUCT(lp_cs_tpool_task);
+   if (!task) {
+      return NULL;
+   }
+
+   task->work = work;
+   task->data = data;
+   task->iter_total = num_iters;
+   cnd_init(&task->finish);
+
+   mtx_lock(&pool->m);
+
+   list_addtail(&task->list, &pool->workqueue);
+
+   cnd_signal(&pool->new_work);
+   mtx_unlock(&pool->m);
+   return task;
+}
+
+void
+lp_cs_tpool_wait_for_task(struct lp_cs_tpool *pool,
+                          struct lp_cs_tpool_task **task_handle)
+{
+   struct lp_cs_tpool_task *task = *task_handle;
+
+   if (!pool || !task)
+      return;
+
+   mtx_lock(&pool->m);
+   while (task->iter_finished < task->iter_total)
+      cnd_wait(&task->finish, &pool->m);
+   mtx_unlock(&pool->m);
+
+   cnd_destroy(&task->finish);
+   free(task);
+   *task_handle = NULL;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_cs_tpool.h b/src/gallium/drivers/llvmpipe/lp_cs_tpool.h
new file mode 100644 (file)
index 0000000..d32a5e0
--- /dev/null
@@ -0,0 +1,81 @@
+/**************************************************************************
+ *
+ * Copyright 2019 Red Hat.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **************************************************************************/
+
+/* This is a compute shader specific thread pool.
+ * It allows the queuing of a number of tasks per work item.
+ * The item is added to the work queue once, but it must execute
+ * number of iterations times. This saves storing a bunch of queue
+ * structs with just unique indexes in them.
+ * It also supports a local memory support struct to be passed from
+ * outside the thread exec function.
+ */
+#ifndef LP_CS_QUEUE
+#define LP_CS_QUEUE
+
+#include "pipe/p_compiler.h"
+
+#include "util/u_thread.h"
+#include "util/list.h"
+
+#include "lp_limits.h"
+
+struct lp_cs_tpool {
+   mtx_t m;
+   cnd_t new_work;
+
+   thrd_t threads[LP_MAX_THREADS];
+   unsigned num_threads;
+   struct list_head workqueue;
+   bool shutdown;
+};
+
+struct lp_cs_local_mem {
+   unsigned local_size;
+   void *local_mem_ptr;
+};
+
+typedef void (*lp_cs_tpool_task_func)(void *data, int iter_idx, struct lp_cs_local_mem *lmem);
+
+struct lp_cs_tpool_task {
+   lp_cs_tpool_task_func work;
+   void *data;
+   struct list_head list;
+   cnd_t finish;
+   unsigned iter_total;
+   unsigned iter_start;
+   unsigned iter_finished;
+};
+
+struct lp_cs_tpool *lp_cs_tpool_create(unsigned num_threads);
+void lp_cs_tpool_destroy(struct lp_cs_tpool *);
+
+struct lp_cs_tpool_task *lp_cs_tpool_queue_task(struct lp_cs_tpool *,
+                                                lp_cs_tpool_task_func func,
+                                                void *data, int num_iters);
+
+void lp_cs_tpool_wait_for_task(struct lp_cs_tpool *pool,
+                            struct lp_cs_tpool_task **task);
+
+#endif /* LP_BIN_QUEUE */
index 4265e49..e2c0985 100644 (file)
@@ -49,6 +49,7 @@
 #include "lp_public.h"
 #include "lp_limits.h"
 #include "lp_rast.h"
+#include "lp_cs_tpool.h"
 
 #include "state_tracker/sw_winsys.h"
 
@@ -595,6 +596,9 @@ llvmpipe_destroy_screen( struct pipe_screen *_screen )
    struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
    struct sw_winsys *winsys = screen->winsys;
 
+   if (screen->cs_tpool)
+      lp_cs_tpool_destroy(screen->cs_tpool);
+
    if (screen->rast)
       lp_rast_destroy(screen->rast);
 
@@ -604,7 +608,7 @@ llvmpipe_destroy_screen( struct pipe_screen *_screen )
       winsys->destroy(winsys);
 
    mtx_destroy(&screen->rast_mutex);
-
+   mtx_destroy(&screen->cs_mutex);
    FREE(screen);
 }
 
@@ -717,5 +721,14 @@ llvmpipe_create_screen(struct sw_winsys *winsys)
    }
    (void) mtx_init(&screen->rast_mutex, mtx_plain);
 
+   screen->cs_tpool = lp_cs_tpool_create(screen->num_threads);
+   if (!screen->cs_tpool) {
+      lp_rast_destroy(screen->rast);
+      lp_jit_screen_cleanup(screen);
+      FREE(screen);
+      return NULL;
+   }
+   (void) mtx_init(&screen->cs_mutex, mtx_plain);
+
    return &screen->base;
 }
index da702ad..6ac52b8 100644 (file)
@@ -41,7 +41,7 @@
 
 
 struct sw_winsys;
-
+struct lp_cs_tpool;
 
 struct llvmpipe_screen
 {
@@ -57,6 +57,9 @@ struct llvmpipe_screen
 
    struct lp_rasterizer *rast;
    mtx_t rast_mutex;
+
+   struct lp_cs_tpool *cs_tpool;
+   mtx_t cs_mutex;
 };
 
 
index 6ad3017..7eb752c 100644 (file)
@@ -33,6 +33,8 @@ files_llvmpipe = files(
   'lp_clear.h',
   'lp_context.c',
   'lp_context.h',
+  'lp_cs_tpool.h',
+  'lp_cs_tpool.c',
   'lp_debug.h',
   'lp_draw_arrays.c',
   'lp_fence.c',