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:
parent
52aa84b3c3
commit
1a6c0ea3d0
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,9 +771,10 @@ 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,
|
||||
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);
|
||||
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user