From 1a6c0ea3d0d453be0b8f3094e8020e11cff65384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 7 Nov 2024 15:58:21 +0100 Subject: [PATCH] thread: Make thread priority preference more generic Either prefer "normal" or "realtime", via an enum, instead of a boolean. Also make it configurable with an env var `MUTTER_DEBUG_KMS_SCHEDULING_PRIORITY`, which can be set to either `normal` or `realtime`. Part-of: --- src/backends/native/meta-kms-impl-device.c | 10 +- src/backends/native/meta-kms.c | 28 +++++- src/backends/native/meta-thread-impl.c | 13 ++- src/backends/native/meta-thread-impl.h | 10 +- src/backends/native/meta-thread.c | 107 ++++++++++++++------- src/backends/native/meta-thread.h | 6 ++ src/tests/native-thread.c | 12 ++- 7 files changed, 126 insertions(+), 60 deletions(-) diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index ecd10e62e..f743b8631 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -1696,7 +1696,15 @@ is_using_deadline_timer (MetaKmsImplDevice *impl_device) MetaKmsImpl *impl = meta_kms_impl_device_get_impl (impl_device); MetaThreadImpl *thread_impl = META_THREAD_IMPL (impl); - return meta_thread_impl_is_realtime (thread_impl); + switch (meta_thread_impl_get_scheduling_priority (thread_impl)) + { + case META_SCHEDULING_PRIORITY_NORMAL: + return FALSE; + case META_SCHEDULING_PRIORITY_REALTIME: + return TRUE; + } + + g_assert_not_reached (); } } diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index 9af95ca9c..b22de8c29 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -382,8 +382,9 @@ meta_kms_new (MetaBackend *backend, MetaUdev *udev = meta_backend_native_get_udev (backend_native); MetaKms *kms; const char *thread_type_string; + const char *preferred_scheduling_priority_string; MetaThreadType thread_type = META_THREAD_TYPE_KERNEL; - gboolean wants_realtime_scheduling; + MetaSchedulingPriority preferred_scheduling_priority; thread_type_string = g_getenv ("MUTTER_DEBUG_KMS_THREAD_TYPE"); if (thread_type_string) @@ -395,17 +396,36 @@ meta_kms_new (MetaBackend *backend, else g_assert_not_reached (); } - - wants_realtime_scheduling = !(flags & META_KMS_FLAG_NO_MODE_SETTING); if (flags & META_KMS_FLAG_NO_MODE_SETTING) thread_type = META_THREAD_TYPE_USER; + preferred_scheduling_priority_string = + g_getenv ("MUTTER_DEBUG_KMS_SCHEDULING_PRIORITY"); + if (preferred_scheduling_priority_string) + { + if (g_strcmp0 (preferred_scheduling_priority_string, + "normal") == 0) + preferred_scheduling_priority = META_SCHEDULING_PRIORITY_NORMAL; + else if (g_strcmp0 (preferred_scheduling_priority_string, + "realtime") == 0) + preferred_scheduling_priority = META_SCHEDULING_PRIORITY_REALTIME; + else + g_assert_not_reached (); + } + else + { + if (flags & META_KMS_FLAG_NO_MODE_SETTING) + preferred_scheduling_priority = META_SCHEDULING_PRIORITY_NORMAL; + else + preferred_scheduling_priority = META_SCHEDULING_PRIORITY_REALTIME; + } + kms = g_initable_new (META_TYPE_KMS, NULL, error, "backend", backend, "name", "KMS thread", "thread-type", thread_type, - "wants-realtime", wants_realtime_scheduling, + "preferred-scheduling-priority", preferred_scheduling_priority, NULL); kms->flags = flags; diff --git a/src/backends/native/meta-thread-impl.c b/src/backends/native/meta-thread-impl.c index c32790f40..d430f6881 100644 --- a/src/backends/native/meta-thread-impl.c +++ b/src/backends/native/meta-thread-impl.c @@ -64,7 +64,7 @@ typedef struct _MetaThreadImplPrivate GSource *impl_source; GAsyncQueue *task_queue; - gboolean is_realtime; + MetaSchedulingPriority scheduling_priority; } MetaThreadImplPrivate; struct _MetaThreadTask @@ -579,7 +579,7 @@ meta_thread_impl_setup (MetaThreadImpl *thread_impl) void meta_thread_impl_run (MetaThreadImpl *thread_impl, - MetaThreadImplRunFlags flags) + MetaSchedulingPriority scheduling_priority) { MetaThreadImplPrivate *priv = meta_thread_impl_get_instance_private (thread_impl); @@ -587,9 +587,8 @@ meta_thread_impl_run (MetaThreadImpl *thread_impl, meta_assert_in_thread_impl (priv->thread); priv->loop = g_main_loop_new (priv->thread_context, FALSE); - priv->is_realtime = !!(flags & META_THREAD_IMPL_RUN_FLAG_REALTIME); + priv->scheduling_priority = scheduling_priority; g_main_loop_run (priv->loop); - priv->is_realtime = FALSE; } void @@ -606,11 +605,11 @@ meta_thread_impl_queue_task (MetaThreadImpl *thread_impl, g_async_queue_unlock (priv->task_queue); } -gboolean -meta_thread_impl_is_realtime (MetaThreadImpl *thread_impl) +MetaSchedulingPriority +meta_thread_impl_get_scheduling_priority (MetaThreadImpl *thread_impl) { MetaThreadImplPrivate *priv = meta_thread_impl_get_instance_private (thread_impl); - return priv->is_realtime; + return priv->scheduling_priority; } diff --git a/src/backends/native/meta-thread-impl.h b/src/backends/native/meta-thread-impl.h index 1837c465c..ca47b4692 100644 --- a/src/backends/native/meta-thread-impl.h +++ b/src/backends/native/meta-thread-impl.h @@ -24,12 +24,6 @@ typedef struct _MetaThread MetaThread; -typedef enum _MetaThreadImplRunFlags -{ - META_THREAD_IMPL_RUN_FLAG_NONE = 0, - META_THREAD_IMPL_RUN_FLAG_REALTIME = 1 << 0, -} MetaThreadImplRunFlags; - #define META_TYPE_THREAD_IMPL (meta_thread_impl_get_type ()) META_EXPORT_TEST G_DECLARE_DERIVABLE_TYPE (MetaThreadImpl, meta_thread_impl, @@ -75,14 +69,14 @@ void meta_thread_impl_terminate (MetaThreadImpl *thread_impl); void meta_thread_impl_setup (MetaThreadImpl *thread_impl); void meta_thread_impl_run (MetaThreadImpl *thread_impl, - MetaThreadImplRunFlags flags); + MetaSchedulingPriority scheduling_priority); int meta_thread_impl_dispatch (MetaThreadImpl *thread_impl); gboolean meta_thread_impl_is_in_impl (MetaThreadImpl *thread_impl); META_EXPORT_TEST -gboolean meta_thread_impl_is_realtime (MetaThreadImpl *thread_impl); +MetaSchedulingPriority meta_thread_impl_get_scheduling_priority (MetaThreadImpl *thread_impl); MetaThreadTask * meta_thread_task_new (MetaThreadTaskFunc func, gpointer user_data, diff --git a/src/backends/native/meta-thread.c b/src/backends/native/meta-thread.c index f668d1363..f0edf87c5 100644 --- a/src/backends/native/meta-thread.c +++ b/src/backends/native/meta-thread.c @@ -36,7 +36,7 @@ enum PROP_BACKEND, PROP_NAME, PROP_THREAD_TYPE, - PROP_WANTS_REALTIME, + PROP_PREFERED_SCHEDULING_PRIORITY, N_PROPS }; @@ -71,7 +71,7 @@ typedef struct _MetaThreadPrivate GMainContext *main_context; MetaThreadImpl *impl; - gboolean wants_realtime; + MetaSchedulingPriority preferred_scheduling_priority; gboolean waiting_for_impl_task; GSource *wrapper_source; @@ -88,7 +88,7 @@ typedef struct _MetaThreadPrivate pid_t thread_id; GMutex init_mutex; int realtime_inhibit_count; - gboolean is_realtime; + MetaSchedulingPriority scheduling_priority; } kernel; } MetaThreadPrivate; @@ -106,6 +106,20 @@ G_DEFINE_TYPE_WITH_CODE (MetaThread, meta_thread, G_TYPE_OBJECT, g_type_add_class_private (g_define_type_id, sizeof (MetaThreadClassPrivate))) +static const char * +meta_scheduling_priority_to_string (MetaSchedulingPriority priority) +{ + switch (priority) + { + case META_SCHEDULING_PRIORITY_NORMAL: + return "normal"; + case META_SCHEDULING_PRIORITY_REALTIME: + return "realtime"; + } + + g_assert_not_reached (); +} + static void meta_thread_callback_data_free (MetaThreadCallbackData *callback_data) { @@ -134,8 +148,8 @@ meta_thread_get_property (GObject *object, case PROP_THREAD_TYPE: g_value_set_enum (value, priv->thread_type); break; - case PROP_WANTS_REALTIME: - g_value_set_boolean (value, priv->wants_realtime); + case PROP_PREFERED_SCHEDULING_PRIORITY: + g_value_set_enum (value, priv->preferred_scheduling_priority); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -163,8 +177,8 @@ meta_thread_set_property (GObject *object, case PROP_THREAD_TYPE: priv->thread_type = g_value_get_enum (value); break; - case PROP_WANTS_REALTIME: - priv->wants_realtime = g_value_get_boolean (value); + case PROP_PREFERED_SCHEDULING_PRIORITY: + priv->preferred_scheduling_priority = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -342,7 +356,8 @@ can_use_realtime_scheduling_in_impl (MetaThread *thread) case META_THREAD_TYPE_USER: return FALSE; case META_THREAD_TYPE_KERNEL: - return priv->wants_realtime; + return (priv->preferred_scheduling_priority == + META_SCHEDULING_PRIORITY_REALTIME); } g_assert_not_reached (); @@ -358,19 +373,23 @@ should_use_realtime_scheduling_in_impl (MetaThread *thread) } static void -sync_realtime_scheduling_in_impl (MetaThread *thread) +sync_scheduling_priority_in_impl (MetaThread *thread) { MetaThreadPrivate *priv = meta_thread_get_instance_private (thread); g_autoptr (GError) error = NULL; - gboolean should_be_realtime; + MetaSchedulingPriority scheduling_priority; - should_be_realtime = should_use_realtime_scheduling_in_impl (thread); + if (should_use_realtime_scheduling_in_impl (thread)) + scheduling_priority = META_SCHEDULING_PRIORITY_REALTIME; + else + scheduling_priority = META_SCHEDULING_PRIORITY_NORMAL; - if (should_be_realtime == priv->kernel.is_realtime) + if (scheduling_priority == priv->kernel.scheduling_priority) return; - if (should_be_realtime) + switch (scheduling_priority) { + case META_SCHEDULING_PRIORITY_REALTIME: if (!request_realtime_scheduling (thread, &error)) { g_warning ("Failed to make thread '%s' realtime scheduled: %s", @@ -378,12 +397,12 @@ sync_realtime_scheduling_in_impl (MetaThread *thread) } else { - meta_topic (META_DEBUG_BACKEND, "Made thread '%s' real-time scheduled", priv->name); - priv->kernel.is_realtime = TRUE; + meta_topic (META_DEBUG_BACKEND, + "Made thread '%s' real-time scheduled", priv->name); + priv->kernel.scheduling_priority = scheduling_priority; } - } - else - { + break; + case META_SCHEDULING_PRIORITY_NORMAL: if (!request_normal_scheduling (thread, &error)) { g_warning ("Failed to make thread '%s' normally scheduled: %s", @@ -392,18 +411,34 @@ sync_realtime_scheduling_in_impl (MetaThread *thread) else { meta_topic (META_DEBUG_BACKEND, "Made thread '%s' normally scheduled", priv->name); - priv->kernel.is_realtime = FALSE; + priv->kernel.scheduling_priority = scheduling_priority; } } } +static MetaSchedulingPriority +determine_effective_thread_priority (MetaThread *thread) +{ + MetaThreadPrivate *priv = meta_thread_get_instance_private (thread); + + switch (priv->thread_type) + { + case META_THREAD_TYPE_USER: + return META_SCHEDULING_PRIORITY_NORMAL; + case META_THREAD_TYPE_KERNEL: + return priv->preferred_scheduling_priority; + } + + g_assert_not_reached (); +} + static gpointer thread_impl_func (gpointer user_data) { MetaThread *thread = META_THREAD (user_data); MetaThreadPrivate *priv = meta_thread_get_instance_private (thread); MetaThreadImpl *impl = priv->impl; - MetaThreadImplRunFlags run_flags = META_THREAD_IMPL_RUN_FLAG_NONE; + MetaSchedulingPriority effective_scheduling_priority; GMainContext *thread_context = meta_thread_impl_get_main_context (impl); #ifdef HAVE_PROFILER MetaContext *context = meta_backend_get_context (priv->backend); @@ -421,19 +456,18 @@ thread_impl_func (gpointer user_data) priv->kernel.thread_id = gettid (); priv->kernel.realtime_inhibit_count = 0; - priv->kernel.is_realtime = FALSE; meta_thread_impl_setup (impl); - sync_realtime_scheduling_in_impl (thread); + sync_scheduling_priority_in_impl (thread); - if (can_use_realtime_scheduling_in_impl (thread)) - { - g_message ("Thread '%s' will be using real time scheduling", priv->name); - run_flags |= META_THREAD_IMPL_RUN_FLAG_REALTIME; - } + effective_scheduling_priority = determine_effective_thread_priority (thread); - meta_thread_impl_run (impl, run_flags); + g_message ("Thread '%s' will be using %s scheduling", + priv->name, + meta_scheduling_priority_to_string (effective_scheduling_priority)); + + meta_thread_impl_run (impl, effective_scheduling_priority); #ifdef HAVE_PROFILER meta_profiler_unregister_thread (profiler, thread_context); @@ -737,12 +771,13 @@ meta_thread_class_init (MetaThreadClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_props[PROP_WANTS_REALTIME] = - g_param_spec_boolean ("wants-realtime", NULL, NULL, - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); + obj_props[PROP_PREFERED_SCHEDULING_PRIORITY] = + g_param_spec_enum ("preferred-scheduling-priority", NULL, NULL, + META_TYPE_SCHEDULING_PRIORITY, + META_SCHEDULING_PRIORITY_NORMAL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, obj_props); } @@ -1285,7 +1320,7 @@ meta_thread_inhibit_realtime_in_impl (MetaThread *thread) priv->kernel.realtime_inhibit_count++; if (priv->kernel.realtime_inhibit_count == 1) - sync_realtime_scheduling_in_impl (thread); + sync_scheduling_priority_in_impl (thread); break; case META_THREAD_TYPE_USER: break; @@ -1303,7 +1338,7 @@ meta_thread_uninhibit_realtime_in_impl (MetaThread *thread) priv->kernel.realtime_inhibit_count--; if (priv->kernel.realtime_inhibit_count == 0) - sync_realtime_scheduling_in_impl (thread); + sync_scheduling_priority_in_impl (thread); break; case META_THREAD_TYPE_USER: break; diff --git a/src/backends/native/meta-thread.h b/src/backends/native/meta-thread.h index 4765719ec..b18e83783 100644 --- a/src/backends/native/meta-thread.h +++ b/src/backends/native/meta-thread.h @@ -30,6 +30,12 @@ typedef enum _MetaThreadType META_THREAD_TYPE_USER, } MetaThreadType; +typedef enum _MetaSchedulingPriority +{ + META_SCHEDULING_PRIORITY_NORMAL, + META_SCHEDULING_PRIORITY_REALTIME, +} MetaSchedulingPriority; + #define META_TYPE_THREAD (meta_thread_get_type ()) META_EXPORT_TEST G_DECLARE_DERIVABLE_TYPE (MetaThread, meta_thread, diff --git a/src/tests/native-thread.c b/src/tests/native-thread.c index 003da4908..ed2b8c78b 100644 --- a/src/tests/native-thread.c +++ b/src/tests/native-thread.c @@ -1149,7 +1149,9 @@ assert_realtime (MetaThreadImpl *thread_impl, g_autoptr (GVariant) ret = NULL; uint32_t priority = 0; - g_assert_true (meta_thread_impl_is_realtime (thread_impl)); + g_assert_cmpint (meta_thread_impl_get_scheduling_priority (thread_impl), + ==, + META_SCHEDULING_PRIORITY_REALTIME); ret = call_rtkit_mock_method ("GetThreadPriority", g_variant_new ("(t)", gettid ())); @@ -1175,7 +1177,7 @@ meta_test_thread_realtime (void) "backend", backend, "name", "test realtime", "thread-type", META_THREAD_TYPE_KERNEL, - "wants-realtime", TRUE, + "preferred-scheduling-priority", META_SCHEDULING_PRIORITY_REALTIME, NULL); g_object_add_weak_pointer (G_OBJECT (thread), (gpointer *) &thread); g_assert_nonnull (thread); @@ -1197,7 +1199,9 @@ assert_no_realtime (MetaThreadImpl *thread_impl, g_autoptr (GVariant) ret = NULL; uint32_t priority = UINT32_MAX; - g_assert_false (meta_thread_impl_is_realtime (thread_impl)); + g_assert_cmpint (meta_thread_impl_get_scheduling_priority (thread_impl), + ==, + META_SCHEDULING_PRIORITY_NORMAL); ret = call_rtkit_mock_method ("GetThreadPriority", g_variant_new ("(t)", gettid ())); @@ -1223,7 +1227,7 @@ meta_test_thread_no_realtime (void) "backend", backend, "name", "test realtime", "thread-type", META_THREAD_TYPE_USER, - "wants-realtime", TRUE, + "preferred-scheduling-priority", META_SCHEDULING_PRIORITY_REALTIME, NULL); g_object_add_weak_pointer (G_OBJECT (thread), (gpointer *) &thread); g_assert_nonnull (thread);