From: Marek Olšák <marek.ol...@amd.com> for ARB_parallel_shader_compile --- src/util/u_queue.c | 50 ++++++++++++++++++++++++++++++++++++++++------ src/util/u_queue.h | 8 ++++++++ 2 files changed, 52 insertions(+), 6 deletions(-)
diff --git a/src/util/u_queue.c b/src/util/u_queue.c index 612ad5e83c6..383a9c09919 100644 --- a/src/util/u_queue.c +++ b/src/util/u_queue.c @@ -27,42 +27,43 @@ #include "u_queue.h" #include <time.h> #include "util/os_time.h" #include "util/u_string.h" #include "util/u_thread.h" #include "u_process.h" static void -util_queue_kill_threads(struct util_queue *queue, unsigned keep_num_threads); +util_queue_kill_threads(struct util_queue *queue, unsigned keep_num_threads, + bool finish_locked); /**************************************************************************** * Wait for all queues to assert idle when exit() is called. * * Otherwise, C++ static variable destructors can be called while threads * are using the static variables. */ static once_flag atexit_once_flag = ONCE_FLAG_INIT; static struct list_head queue_list; static mtx_t exit_mutex = _MTX_INITIALIZER_NP; static void atexit_handler(void) { struct util_queue *iter; mtx_lock(&exit_mutex); /* Wait for all queues to assert idle. */ LIST_FOR_EACH_ENTRY(iter, &queue_list, head) { - util_queue_kill_threads(iter, 0); + util_queue_kill_threads(iter, 0, false); } mtx_unlock(&exit_mutex); } static void global_init(void) { LIST_INITHEAD(&queue_list); atexit(atexit_handler); } @@ -333,20 +334,53 @@ util_queue_create_thread(struct util_queue *queue, unsigned index) * * Note that Linux only allows decreasing the priority. The original * priority can't be restored. */ pthread_setschedparam(queue->threads[index], SCHED_IDLE, &sched_param); #endif } return true; } +void +util_queue_adjust_num_threads(struct util_queue *queue, unsigned num_threads) +{ + num_threads = MIN2(num_threads, queue->max_threads); + num_threads = MAX2(num_threads, 1); + + mtx_lock(&queue->finish_lock); + unsigned old_num_threads = queue->num_threads; + + if (num_threads == old_num_threads) { + mtx_unlock(&queue->finish_lock); + return; + } + + if (num_threads < old_num_threads) { + util_queue_kill_threads(queue, num_threads, true); + mtx_unlock(&queue->finish_lock); + return; + } + + /* Create threads. + * + * We need to update num_threads first, because threads terminate + * when thread_index < num_threads. + */ + queue->num_threads = num_threads; + for (unsigned i = old_num_threads; i < num_threads; i++) { + if (!util_queue_create_thread(queue, i)) + break; + } + mtx_unlock(&queue->finish_lock); +} + bool util_queue_init(struct util_queue *queue, const char *name, unsigned max_jobs, unsigned num_threads, unsigned flags) { unsigned i; /* Form the thread name from process_name and name, limited to 13 @@ -371,20 +405,21 @@ util_queue_init(struct util_queue *queue, memset(queue, 0, sizeof(*queue)); if (process_len) { util_snprintf(queue->name, sizeof(queue->name), "%.*s:%s", process_len, process_name, name); } else { util_snprintf(queue->name, sizeof(queue->name), "%s", name); } queue->flags = flags; + queue->max_threads = num_threads; queue->num_threads = num_threads; queue->max_jobs = max_jobs; queue->jobs = (struct util_queue_job*) calloc(max_jobs, sizeof(struct util_queue_job)); if (!queue->jobs) goto fail; (void) mtx_init(&queue->lock, mtx_plain); (void) mtx_init(&queue->finish_lock, mtx_plain); @@ -422,48 +457,51 @@ fail: cnd_destroy(&queue->has_queued_cond); mtx_destroy(&queue->lock); free(queue->jobs); } /* also util_queue_is_initialized can be used to check for success */ memset(queue, 0, sizeof(*queue)); return false; } static void -util_queue_kill_threads(struct util_queue *queue, unsigned keep_num_threads) +util_queue_kill_threads(struct util_queue *queue, unsigned keep_num_threads, + bool finish_locked) { unsigned i; /* Signal all threads to terminate. */ - mtx_lock(&queue->finish_lock); + if (!finish_locked) + mtx_lock(&queue->finish_lock); if (keep_num_threads >= queue->num_threads) { mtx_unlock(&queue->finish_lock); return; } mtx_lock(&queue->lock); unsigned old_num_threads = queue->num_threads; queue->num_threads = keep_num_threads; cnd_broadcast(&queue->has_queued_cond); mtx_unlock(&queue->lock); for (i = keep_num_threads; i < old_num_threads; i++) thrd_join(queue->threads[i], NULL); - mtx_unlock(&queue->finish_lock); + if (!finish_locked) + mtx_unlock(&queue->finish_lock); } void util_queue_destroy(struct util_queue *queue) { - util_queue_kill_threads(queue, 0); + util_queue_kill_threads(queue, 0, false); remove_from_atexit_list(queue); cnd_destroy(&queue->has_space_cond); cnd_destroy(&queue->has_queued_cond); mtx_destroy(&queue->finish_lock); mtx_destroy(&queue->lock); free(queue->jobs); free(queue->threads); } diff --git a/src/util/u_queue.h b/src/util/u_queue.h index 756fa53e1bf..2d269099c20 100644 --- a/src/util/u_queue.h +++ b/src/util/u_queue.h @@ -201,20 +201,21 @@ struct util_queue_job { /* Put this into your context. */ struct util_queue { char name[14]; /* 13 characters = the thread name without the index */ mtx_t finish_lock; /* for util_queue_finish and protects threads/num_threads */ mtx_t lock; cnd_t has_queued_cond; cnd_t has_space_cond; thrd_t *threads; unsigned flags; int num_queued; + unsigned max_threads; unsigned num_threads; /* decreasing this number will terminate threads */ int max_jobs; int write_idx, read_idx; /* ring buffer pointers */ struct util_queue_job *jobs; /* for cleanup at exit(), protected by exit_mutex */ struct list_head head; }; bool util_queue_init(struct util_queue *queue, @@ -228,20 +229,27 @@ void util_queue_destroy(struct util_queue *queue); void util_queue_add_job(struct util_queue *queue, void *job, struct util_queue_fence *fence, util_queue_execute_func execute, util_queue_execute_func cleanup); void util_queue_drop_job(struct util_queue *queue, struct util_queue_fence *fence); void util_queue_finish(struct util_queue *queue); +/* Adjust the number of active threads. The new number of threads can't be + * greater than the initial number of threads at the creation of the queue, + * and it can't be less than 1. + */ +void +util_queue_adjust_num_threads(struct util_queue *queue, unsigned num_threads); + int64_t util_queue_get_thread_time_nano(struct util_queue *queue, unsigned thread_index); /* util_queue needs to be cleared to zeroes for this to work */ static inline bool util_queue_is_initialized(struct util_queue *queue) { return queue->threads != NULL; } -- 2.17.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev