mirror of https://github.com/yshui/picom.git
Merge pull request #1169 from yshui/rtkit
This commit is contained in:
commit
6f2033772b
|
@ -23,6 +23,10 @@
|
|||
* Fix window shader not having an effect when frame opacity is enabled (#1174)
|
||||
* Fix binding root pixmap in case of depth mismatch (#984)
|
||||
|
||||
## Dependency changes
|
||||
|
||||
* picom now optionally depends on `rtkit` at runtime to give itself realtime scheduling priority.
|
||||
|
||||
# v11.1 (2024-Jan-28)
|
||||
|
||||
## Bug fixes
|
||||
|
|
|
@ -66,7 +66,7 @@ endif
|
|||
if get_option('dbus')
|
||||
cflags += ['-DCONFIG_DBUS']
|
||||
deps += [dependency('dbus-1', required: true)]
|
||||
srcs += [ 'dbus.c' ]
|
||||
srcs += [ 'dbus.c', 'rtkit.c' ]
|
||||
endif
|
||||
|
||||
if get_option('xrescheck')
|
||||
|
|
34
src/picom.c
34
src/picom.c
|
@ -19,7 +19,6 @@
|
|||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
@ -2603,39 +2602,6 @@ err:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/// Switch to real-time scheduling policy (SCHED_RR) if possible
|
||||
///
|
||||
/// Make picom realtime to reduce latency, and make rendering times more predictable to
|
||||
/// help pacing.
|
||||
///
|
||||
/// This requires the user to set up permissions for the real-time scheduling. e.g. by
|
||||
/// setting `ulimit -r`, or giving us the CAP_SYS_NICE capability.
|
||||
void set_rr_scheduling(void) {
|
||||
int priority = sched_get_priority_min(SCHED_RR);
|
||||
|
||||
int ret;
|
||||
struct sched_param param;
|
||||
int old_policy;
|
||||
ret = pthread_getschedparam(pthread_self(), &old_policy, ¶m);
|
||||
if (ret != 0) {
|
||||
log_debug("Failed to get old scheduling priority");
|
||||
return;
|
||||
}
|
||||
|
||||
param.sched_priority = priority;
|
||||
|
||||
ret = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m);
|
||||
if (ret != 0) {
|
||||
log_info("Failed to set real-time scheduling priority to %d. Consider "
|
||||
"giving picom the CAP_SYS_NICE capability or equivalent "
|
||||
"support.",
|
||||
priority);
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("Set real-time scheduling priority to %d", priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a session.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright 2009 Lennart Poettering
|
||||
// Copyright 2010 David Henningsson <diwic@ubuntu.com>
|
||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
|
||||
// Imported from https://github.com/heftig/rtkit/blob/master/rtkit.c
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/syscall.h>
|
||||
#elif defined(__NetBSD__)
|
||||
#include <lwp.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/thr.h>
|
||||
#elif defined(__DragonFly__)
|
||||
#include <sys/lwp.h>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "rtkit.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1"
|
||||
#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1"
|
||||
#define RTKIT_INTERFACE "org.freedesktop.RealtimeKit1"
|
||||
|
||||
static inline long compat_gettid(void) {
|
||||
long ret = -1;
|
||||
#if defined(__linux__)
|
||||
ret = (pid_t)syscall(SYS_gettid);
|
||||
#elif defined(__NetBSD__)
|
||||
ret = _lwp_self();
|
||||
#elif defined(__FreeBSD__)
|
||||
long lwpid;
|
||||
thr_self(&lwpid);
|
||||
ret = lwpid;
|
||||
#elif defined(__DragonFly__)
|
||||
ret = lwp_gettid();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
rtkit_get_int_property(DBusConnection *connection, const char *propname, long long *propval) {
|
||||
DBusMessage *m = NULL, *r = NULL;
|
||||
DBusMessageIter iter, subiter;
|
||||
dbus_int64_t i64;
|
||||
dbus_int32_t i32;
|
||||
DBusError error;
|
||||
int current_type;
|
||||
int ret = 0;
|
||||
const char *interfacestr = RTKIT_INTERFACE;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, RTKIT_OBJECT_PATH,
|
||||
"org.freedesktop.DBus.Properties", "Get");
|
||||
if (!m) {
|
||||
ret = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!dbus_message_append_args(m, DBUS_TYPE_STRING, &interfacestr,
|
||||
DBUS_TYPE_STRING, &propname, DBUS_TYPE_INVALID)) {
|
||||
ret = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = dbus_connection_send_with_reply_and_block(connection, m, -1, &error);
|
||||
if (!r) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (dbus_set_error_from_message(&error, r)) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ret = -EBADMSG;
|
||||
dbus_message_iter_init(r, &iter);
|
||||
while ((current_type = dbus_message_iter_get_arg_type(&iter)) != DBUS_TYPE_INVALID) {
|
||||
if (current_type == DBUS_TYPE_VARIANT) {
|
||||
dbus_message_iter_recurse(&iter, &subiter);
|
||||
|
||||
while ((current_type = dbus_message_iter_get_arg_type(&subiter)) !=
|
||||
DBUS_TYPE_INVALID) {
|
||||
|
||||
if (current_type == DBUS_TYPE_INT32) {
|
||||
dbus_message_iter_get_basic(&subiter, &i32);
|
||||
*propval = i32;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (current_type == DBUS_TYPE_INT64) {
|
||||
dbus_message_iter_get_basic(&subiter, &i64);
|
||||
*propval = i64;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
dbus_message_iter_next(&subiter);
|
||||
}
|
||||
}
|
||||
dbus_message_iter_next(&iter);
|
||||
}
|
||||
|
||||
finish:
|
||||
if (m) {
|
||||
dbus_message_unref(m);
|
||||
}
|
||||
if (r) {
|
||||
dbus_message_unref(r);
|
||||
}
|
||||
if (dbus_error_is_set(&error)) {
|
||||
log_debug("Couldn't get property %s from rtkit: (dbus) %s", propname,
|
||||
error.message);
|
||||
dbus_error_free(&error);
|
||||
return false;
|
||||
}
|
||||
if (ret != 0) {
|
||||
log_debug("Couldn't get property %s from rtkit: %s", propname, strerror(-ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rtkit_get_rttime_usec_max(DBusConnection *connection, long long *retval) {
|
||||
return rtkit_get_int_property(connection, "RTTimeUSecMax", retval);
|
||||
}
|
||||
|
||||
static inline void free_dbus_connection(DBusConnection **connection) {
|
||||
if (*connection) {
|
||||
dbus_connection_close(*connection);
|
||||
dbus_connection_unref(*connection);
|
||||
*connection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void free_dbus_message(DBusMessage **message) {
|
||||
if (*message) {
|
||||
dbus_message_unref(*message);
|
||||
*message = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool rtkit_make_realtime(long thread, int priority) {
|
||||
cleanup(free_dbus_message) DBusMessage *m = NULL;
|
||||
cleanup(free_dbus_message) DBusMessage *r = NULL;
|
||||
dbus_uint64_t u64;
|
||||
dbus_uint32_t u32;
|
||||
DBusError error;
|
||||
int ret = 0;
|
||||
long long rttime_usec_max = 0;
|
||||
bool succeeded = true;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
cleanup(free_dbus_connection) DBusConnection *connection =
|
||||
dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
|
||||
if (dbus_error_is_set(&error)) {
|
||||
log_info("Couldn't get system bus: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
return false;
|
||||
}
|
||||
dbus_connection_set_exit_on_disconnect(connection, false);
|
||||
|
||||
if (thread == 0) {
|
||||
thread = compat_gettid();
|
||||
}
|
||||
|
||||
if (!rtkit_get_rttime_usec_max(connection, &rttime_usec_max)) {
|
||||
log_debug("Couldn't get RTTimeUSecMax from rtkit.");
|
||||
return false;
|
||||
}
|
||||
if (rttime_usec_max <= 0) {
|
||||
log_debug("Unreasonable RTTimeUSecMax from rtkit: %lld", rttime_usec_max);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(RLIMIT_RTTIME)
|
||||
struct rlimit old_rlim, new_rlim;
|
||||
// For security reasons, rtkit requires us to set RLIMIT_RTTIME before it will
|
||||
// give us realtime priority.
|
||||
if (getrlimit(RLIMIT_RTTIME, &old_rlim) != 0) {
|
||||
log_debug("Couldn't get RLIMIT_RTTIME.");
|
||||
return false;
|
||||
}
|
||||
new_rlim = old_rlim;
|
||||
new_rlim.rlim_cur = min3(new_rlim.rlim_max, (rlim_t)rttime_usec_max, 100000); // 100ms
|
||||
new_rlim.rlim_max = new_rlim.rlim_cur;
|
||||
if (setrlimit(RLIMIT_RTTIME, &new_rlim) != 0) {
|
||||
log_debug("Couldn't set RLIMIT_RTTIME.");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, RTKIT_OBJECT_PATH,
|
||||
RTKIT_INTERFACE, "MakeThreadRealtime");
|
||||
if (!m) {
|
||||
ret = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
u64 = (dbus_uint64_t)thread;
|
||||
u32 = (dbus_uint32_t)priority;
|
||||
|
||||
if (!dbus_message_append_args(m, DBUS_TYPE_UINT64, &u64, DBUS_TYPE_UINT32, &u32,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
ret = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = dbus_connection_send_with_reply_and_block(connection, m, -1, &error);
|
||||
if (!r) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (dbus_set_error_from_message(&error, r)) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
finish:
|
||||
if (dbus_error_is_set(&error)) {
|
||||
log_info("Couldn't make thread realtime with rtkit: (dbus) %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
succeeded = false;
|
||||
} else if (ret != 0) {
|
||||
log_info("Couldn't make thread realtime with rtkit: %s", strerror(-ret));
|
||||
succeeded = false;
|
||||
}
|
||||
#if defined(RLIMIT_RTTIME)
|
||||
if (!succeeded) {
|
||||
// Restore RLIMIT_RTTIME
|
||||
setrlimit(RLIMIT_RTTIME, &old_rlim);
|
||||
}
|
||||
#endif
|
||||
|
||||
return succeeded;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
bool rtkit_make_realtime(long thread, int priority);
|
||||
|
||||
#else
|
||||
|
||||
static inline bool rtkit_make_realtime(pid_t thread attr_unused, int priority attr_unused) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
37
src/utils.c
37
src/utils.c
|
@ -1,8 +1,10 @@
|
|||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "compiler.h"
|
||||
#include "rtkit.h"
|
||||
#include "string_utils.h"
|
||||
#include "test.h"
|
||||
#include "utils.h"
|
||||
|
@ -272,4 +274,39 @@ void rolling_quantile_pop_front(struct rolling_quantile *rq, int x) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Switch to real-time scheduling policy (SCHED_RR) if possible
|
||||
///
|
||||
/// Make picom realtime to reduce latency, and make rendering times more predictable to
|
||||
/// help pacing.
|
||||
///
|
||||
/// This requires the user to set up permissions for the real-time scheduling. e.g. by
|
||||
/// setting `ulimit -r`, or giving us the CAP_SYS_NICE capability.
|
||||
void set_rr_scheduling(void) {
|
||||
int priority = sched_get_priority_min(SCHED_RR);
|
||||
|
||||
if (rtkit_make_realtime(0, priority)) {
|
||||
log_info("Set realtime priority to %d with rtkit.", priority);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to use pthread_setschedparam
|
||||
struct sched_param param;
|
||||
int old_policy;
|
||||
int ret = pthread_getschedparam(pthread_self(), &old_policy, ¶m);
|
||||
if (ret != 0) {
|
||||
log_info("Couldn't get old scheduling priority.");
|
||||
return;
|
||||
}
|
||||
|
||||
param.sched_priority = priority;
|
||||
|
||||
ret = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m);
|
||||
if (ret != 0) {
|
||||
log_info("Couldn't set real-time scheduling priority to %d.", priority);
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("Set real-time scheduling priority to %d.", priority);
|
||||
}
|
||||
|
||||
// vim: set noet sw=8 ts=8 :
|
||||
|
|
|
@ -406,6 +406,7 @@ void rolling_quantile_destroy(struct rolling_quantile *rq);
|
|||
int rolling_quantile_estimate(struct rolling_quantile *rq, struct rolling_window *elements);
|
||||
void rolling_quantile_push_back(struct rolling_quantile *rq, int x);
|
||||
void rolling_quantile_pop_front(struct rolling_quantile *rq, int x);
|
||||
void set_rr_scheduling(void);
|
||||
|
||||
// Some versions of the Android libc do not have timespec_get(), use
|
||||
// clock_gettime() instead.
|
||||
|
|
|
@ -183,6 +183,8 @@ static void *sgi_video_sync_thread(void *data) {
|
|||
goto start_failed;
|
||||
}
|
||||
|
||||
log_init_tls();
|
||||
set_rr_scheduling();
|
||||
pthread_mutex_lock(&args->start_mtx);
|
||||
args->start_status = 0;
|
||||
pthread_cond_signal(&args->start_cnd);
|
||||
|
|
Loading…
Reference in New Issue