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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4124>
This commit is contained in:
Jonas Ådahl 2024-11-07 15:58:21 +01:00 committed by Marge Bot
parent 52aa84b3c3
commit 1a6c0ea3d0
7 changed files with 126 additions and 60 deletions

View File

@ -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 ();
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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,

View File

@ -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);