This is the first part of the (dynamic) thread boost implementation, which boosts the main thread only.
In my testing on Windows just being the main thread usually gives a +1 to +2 priority boost (which also plays well with the theoretical QOS boost that main threads on macOS also have).
I assume on Linux this will be similarly beneficial in some cases.
This is a conservative +1 boost to the main thread for now. The next (and final part) will boost the priority of the thread handling the foreground windows messages (which is also something that native Windows does).
It is hard to reliably write tests for these adjustments since there is some more dynamic behavior, but in my testing this approach is a pretty good approximation (and does improve performance on some games like GTA V measurably).
From: Marc-Aurel Zent mzent@codeweavers.com
--- server/process.c | 2 +- server/thread.c | 17 ++++++++++++----- server/thread.h | 1 + 3 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/server/process.c b/server/process.c index b9bc02b6469..476dc9c42b8 100644 --- a/server/process.c +++ b/server/process.c @@ -2102,7 +2102,7 @@ DECL_HANDLER(list_processes) thread_info->start_time = thread->creation_time; thread_info->tid = thread->id; thread_info->base_priority = thread->base_priority; - thread_info->current_priority = thread->priority; + thread_info->current_priority = get_effective_thread_priority( thread ); thread_info->unix_tid = thread->unix_tid; thread_info->entry_point = thread->entry_point; thread_info->teb = thread->teb; diff --git a/server/thread.c b/server/thread.c index 853aff4cc84..1f75f3a49b2 100644 --- a/server/thread.c +++ b/server/thread.c @@ -255,9 +255,10 @@ void init_threading(void) if (nice_limit < 0 && debug_level) fprintf(stderr, "wine: Using setpriority to control niceness in the [%d,%d] range\n", nice_limit, -nice_limit ); }
-static void apply_thread_priority( struct thread *thread, int effective_priority ) +static void apply_thread_priority( struct thread *thread ) { int min = -nice_limit, max = nice_limit, range = max - min, niceness; + int effective_priority = get_effective_thread_priority( thread );
if (nice_limit >= 0) return;
@@ -291,7 +292,7 @@ static int get_mach_importance( int effective_priority ) return min + (effective_priority - 1) * range / 14; }
-static void apply_thread_priority( struct thread *thread, int effective_priority ) +static void apply_thread_priority( struct thread *thread ) { kern_return_t kr; mach_msg_type_name_t type; @@ -299,6 +300,7 @@ static void apply_thread_priority( struct thread *thread, int effective_priority struct thread_extended_policy thread_extended_policy; struct thread_precedence_policy thread_precedence_policy; mach_port_t thread_port, process_port = thread->process->trace_data; + int effective_priority = get_effective_thread_priority( thread );
if (!process_port) return; kr = mach_port_extract_right( process_port, thread->unix_tid, @@ -385,7 +387,7 @@ void init_threading(void) { }
-static void apply_thread_priority( struct thread *thread, int effective_priority ) +static void apply_thread_priority( struct thread *thread ) { }
@@ -823,6 +825,11 @@ affinity_t get_thread_affinity( struct thread *thread ) return mask; }
+int get_effective_thread_priority( struct thread *thread ) +{ + return thread->priority; +} + unsigned int set_thread_priority( struct thread *thread, int priority ) { int priority_class = thread->process->priority; @@ -833,7 +840,7 @@ unsigned int set_thread_priority( struct thread *thread, int priority ) thread->priority = priority;
/* if thread is gone or hasn't started yet, this will be called again from init_thread with a unix_tid */ - if (thread->state == RUNNING && thread->unix_tid != -1) apply_thread_priority( thread, priority ); + if (thread->state == RUNNING && thread->unix_tid != -1) apply_thread_priority( thread );
return STATUS_SUCCESS; } @@ -1818,7 +1825,7 @@ DECL_HANDLER(get_thread_info) reply->teb = thread->teb; reply->entry_point = thread->entry_point; reply->exit_code = (thread->state == TERMINATED) ? thread->exit_code : STATUS_PENDING; - reply->priority = thread->priority; + reply->priority = get_effective_thread_priority( thread ); reply->base_priority = thread->base_priority; reply->affinity = thread->affinity; reply->suspend_count = thread->suspend; diff --git a/server/thread.h b/server/thread.h index 9c552a88ed2..491210d03cd 100644 --- a/server/thread.h +++ b/server/thread.h @@ -127,6 +127,7 @@ extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum extern int thread_add_inflight_fd( struct thread *thread, int client, int server ); extern int thread_get_inflight_fd( struct thread *thread, int client ); extern struct token *thread_get_impersonation_token( struct thread *thread ); +extern int get_effective_thread_priority( struct thread *thread ); extern unsigned int set_thread_priority( struct thread *thread, int priority ); extern unsigned int set_thread_base_priority( struct thread *thread, int base_priority ); extern int set_thread_affinity( struct thread *thread, affinity_t affinity );
From: Marc-Aurel Zent mzent@codeweavers.com
--- server/process.c | 2 +- server/thread.c | 8 +++++++- server/thread.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/server/process.c b/server/process.c index 476dc9c42b8..92b89f67059 100644 --- a/server/process.c +++ b/server/process.c @@ -1719,7 +1719,7 @@ static void set_process_disable_boost( struct process *process, int disable_boos
LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) { - thread->disable_boost = disable_boost; + set_thread_disable_boost( thread, disable_boost ); } }
diff --git a/server/thread.c b/server/thread.c index 1f75f3a49b2..c0ec8203f41 100644 --- a/server/thread.c +++ b/server/thread.c @@ -881,6 +881,12 @@ unsigned int set_thread_base_priority( struct thread *thread, int base_priority return set_thread_priority( thread, priority ); }
+void set_thread_disable_boost( struct thread *thread, int disable_boost ) +{ + thread->disable_boost = disable_boost; + apply_thread_priority( thread ); +} + /* set all information about a thread */ static void set_thread_info( struct thread *thread, const struct set_thread_info_request *req ) @@ -911,7 +917,7 @@ static void set_thread_info( struct thread *thread, if (req->mask & SET_THREAD_INFO_DBG_HIDDEN) thread->dbg_hidden = 1; if (req->mask & SET_THREAD_INFO_DISABLE_BOOST) - thread->disable_boost = req->disable_boost; + set_thread_disable_boost( thread, req->disable_boost ); if (req->mask & SET_THREAD_INFO_DESCRIPTION) { WCHAR *desc; diff --git a/server/thread.h b/server/thread.h index 491210d03cd..05a81ef220b 100644 --- a/server/thread.h +++ b/server/thread.h @@ -130,6 +130,7 @@ extern struct token *thread_get_impersonation_token( struct thread *thread ); extern int get_effective_thread_priority( struct thread *thread ); extern unsigned int set_thread_priority( struct thread *thread, int priority ); extern unsigned int set_thread_base_priority( struct thread *thread, int base_priority ); +void set_thread_disable_boost( struct thread *thread, int disable_boost ); extern int set_thread_affinity( struct thread *thread, affinity_t affinity ); extern int suspend_thread( struct thread *thread ); extern int resume_thread( struct thread *thread );
From: Marc-Aurel Zent mzent@codeweavers.com
--- server/thread.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/server/thread.c b/server/thread.c index c0ec8203f41..2823c7d8076 100644 --- a/server/thread.c +++ b/server/thread.c @@ -337,7 +337,7 @@ static void apply_thread_priority( struct thread *thread ) break; } /* QOS_UNSPECIFIED is assigned the highest tier available, so it does not provide a limit */ - if (effective_priority >= LOW_REALTIME_PRIORITY) + if (effective_priority >= LOW_REALTIME_PRIORITY || effective_priority > thread->priority) { throughput_qos = THROUGHPUT_QOS_TIER_UNSPECIFIED; latency_qos = LATENCY_QOS_TIER_UNSPECIFIED; @@ -827,7 +827,15 @@ affinity_t get_thread_affinity( struct thread *thread )
int get_effective_thread_priority( struct thread *thread ) { - return thread->priority; + int priority = thread->priority; + + if (thread->disable_boost || priority >= LOW_REALTIME_PRIORITY) + return priority; + + if (get_process_first_thread( thread->process ) == thread) + priority++; + + return min( priority, LOW_REALTIME_PRIORITY - 1 ); }
unsigned int set_thread_priority( struct thread *thread, int priority )