Skip to content

Commit 9da9d4a

Browse files
gonnetxnnpack-bot
authored andcommitted
In ensure_num_threads, if we have to call executor->schedule more than twice, create a task that does that instead.
This avoids blocking the calling thread too long on repeated calls to `executor->schedule`, which can be expensive. Ideally, the `pthreadpool_executor` should provide a `schedule_n` function to schedule a group of tasks, but that would require a larger API change. PiperOrigin-RevId: 811255624
1 parent f0af18b commit 9da9d4a

1 file changed

Lines changed: 42 additions & 3 deletions

File tree

src/pthreads.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@
7373
#include <cpuinfo.h>
7474
#endif
7575

76+
/* Alloca */
77+
#if defined(_MSC_VER)
78+
#include <malloc.h>
79+
#define alloca _alloca
80+
#endif // defined(_MSC_VER)
81+
7682
/* Public library header */
7783
#include <pthreadpool.h>
7884

@@ -593,6 +599,23 @@ struct pthreadpool* pthreadpool_create_v2(struct pthreadpool_executor* executor,
593599
return threadpool;
594600
}
595601

602+
static void wake_up_threads(void** contexts) {
603+
struct pthreadpool* threadpool = (struct pthreadpool*)contexts[0];
604+
struct pthreadpool_executor* executor = &threadpool->executor;
605+
for (uint32_t k = 1; contexts[k] != NULL; k++) {
606+
if (contexts[k + 1] != NULL) {
607+
/* Fly, my pretties! Fly, fly, fly! */
608+
executor->schedule(threadpool->executor_context, contexts[k],
609+
(void (*)(void*))thread_main);
610+
} else {
611+
void* context = contexts[k];
612+
free(contexts);
613+
thread_main(context);
614+
return;
615+
}
616+
}
617+
}
618+
596619
static void ensure_num_threads(struct pthreadpool* threadpool,
597620
uint32_t num_threads) {
598621
assert(num_threads >= 1);
@@ -604,21 +627,37 @@ static void ensure_num_threads(struct pthreadpool* threadpool,
604627
return;
605628
}
606629

630+
void** thread_contexts = alloca(sizeof(void*) * num_threads);
631+
int32_t num_threads_to_wake = 0;
632+
607633
/* Create any missing threads for this threadpool. */
608634
for (uint32_t tid = 1;
609635
tid < num_threads &&
610636
pthreadpool_load_consume_int32_t(&threadpool->num_active_threads) > 0;
611637
tid++) {
612638
struct thread_info* thread = &threadpool->threads[tid];
613639

614-
// Check whether this thread was active, and if not, start it up.
640+
// Check whether this thread was active, and if not, add it to the list of
641+
// threads that need starting.
615642
if (!pthreadpool_exchange_sequentially_consistent_uint32_t(
616643
&thread->is_active, 1)) {
617644
pthreadpool_register_threads(threadpool, 1);
645+
thread_contexts[num_threads_to_wake++] = thread;
646+
}
647+
}
618648

649+
if (num_threads_to_wake > 1) {
650+
void** contexts = malloc(sizeof(void*) * (num_threads_to_wake + 2));
651+
contexts[0] = threadpool;
652+
memcpy(contexts + 1, thread_contexts, sizeof(void*) * num_threads_to_wake);
653+
contexts[num_threads_to_wake + 1] = NULL;
654+
/* Fly, my pretties! Fly, fly, fly! */
655+
executor->schedule(threadpool->executor_context, contexts,
656+
(void (*)(void*))wake_up_threads);
657+
} else if (num_threads_to_wake == 1) {
658+
for (int k = 0; k < num_threads_to_wake; k++) {
619659
/* Fly, my pretties! Fly, fly, fly! */
620-
pthreadpool_log_debug("starting thread %u (arg=%p).", tid, thread);
621-
executor->schedule(threadpool->executor_context, thread,
660+
executor->schedule(threadpool->executor_context, thread_contexts[k],
622661
(void (*)(void*))thread_main);
623662
}
624663
}

0 commit comments

Comments
 (0)