1
/**************************************************************************
3
* Copyright 2019 Red Hat.
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the "Software"),
8
* to deal in the Software without restriction, including without limitation
9
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
* and/or sell copies of the Software, and to permit persons to whom the
11
* Software is furnished to do so, subject to the following conditions:
13
* The above copyright notice and this permission notice shall be included
14
* in all copies or substantial portions of the Software.
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
**************************************************************************/
27
* compute shader thread pool.
28
* based on threadpool.c but modified heavily to be compute shader tuned.
31
#include "util/u_thread.h"
32
#include "util/u_memory.h"
33
#include "lp_cs_tpool.h"
36
lp_cs_tpool_worker(void *data)
38
struct lp_cs_tpool *pool = data;
39
struct lp_cs_local_mem lmem;
41
memset(&lmem, 0, sizeof(lmem));
44
while (!pool->shutdown) {
45
struct lp_cs_tpool_task *task;
46
unsigned iter_per_thread;
48
while (list_is_empty(&pool->workqueue) && !pool->shutdown)
49
cnd_wait(&pool->new_work, &pool->m);
54
task = list_first_entry(&pool->workqueue, struct lp_cs_tpool_task,
57
unsigned this_iter = task->iter_start;
59
iter_per_thread = task->iter_per_thread;
61
if (task->iter_remainder &&
62
task->iter_start + task->iter_remainder == task->iter_total) {
63
task->iter_remainder--;
67
task->iter_start += iter_per_thread;
69
if (task->iter_start == task->iter_total)
70
list_del(&task->list);
73
for (unsigned i = 0; i < iter_per_thread; i++)
74
task->work(task->data, this_iter + i, &lmem);
77
task->iter_finished += iter_per_thread;
78
if (task->iter_finished == task->iter_total)
79
cnd_broadcast(&task->finish);
82
FREE(lmem.local_mem_ptr);
87
lp_cs_tpool_create(unsigned num_threads)
89
struct lp_cs_tpool *pool = CALLOC_STRUCT(lp_cs_tpool);
94
(void) mtx_init(&pool->m, mtx_plain);
95
cnd_init(&pool->new_work);
97
list_inithead(&pool->workqueue);
98
assert (num_threads <= LP_MAX_THREADS);
99
pool->num_threads = num_threads;
100
for (unsigned i = 0; i < num_threads; i++)
101
pool->threads[i] = u_thread_create(lp_cs_tpool_worker, pool);
106
lp_cs_tpool_destroy(struct lp_cs_tpool *pool)
112
pool->shutdown = true;
113
cnd_broadcast(&pool->new_work);
114
mtx_unlock(&pool->m);
116
for (unsigned i = 0; i < pool->num_threads; i++) {
117
thrd_join(pool->threads[i], NULL);
120
cnd_destroy(&pool->new_work);
121
mtx_destroy(&pool->m);
125
struct lp_cs_tpool_task *
126
lp_cs_tpool_queue_task(struct lp_cs_tpool *pool,
127
lp_cs_tpool_task_func work, void *data, int num_iters)
129
struct lp_cs_tpool_task *task;
131
if (pool->num_threads == 0) {
132
struct lp_cs_local_mem lmem;
134
memset(&lmem, 0, sizeof(lmem));
135
for (unsigned t = 0; t < num_iters; t++) {
136
work(data, t, &lmem);
138
FREE(lmem.local_mem_ptr);
141
task = CALLOC_STRUCT(lp_cs_tpool_task);
148
task->iter_total = num_iters;
150
task->iter_per_thread = num_iters / pool->num_threads;
151
task->iter_remainder = num_iters % pool->num_threads;
153
cnd_init(&task->finish);
157
list_addtail(&task->list, &pool->workqueue);
159
cnd_broadcast(&pool->new_work);
160
mtx_unlock(&pool->m);
165
lp_cs_tpool_wait_for_task(struct lp_cs_tpool *pool,
166
struct lp_cs_tpool_task **task_handle)
168
struct lp_cs_tpool_task *task = *task_handle;
174
while (task->iter_finished < task->iter_total)
175
cnd_wait(&task->finish, &pool->m);
176
mtx_unlock(&pool->m);
178
cnd_destroy(&task->finish);