mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
module-rt: enable setting UCLAMP_MIN and UCLAMP_MAX values
Modern heterogenous multiprocessor systems rely increasingly on scheduler hinting for efficiency gains and system optimisation. This is especially true on embedded systems, where background tasks such as audio daemons should be consigned to the most power-efficient core in the system. Left to its own devices, the Linux Completely Fair Scheduler tends to migrate Pipewire to more performant cores, even when this is unnecessary. Luckily, CFS can be told by a task to clamp its utilisation values. Coupled with energy-aware scheduling, this allows the scheduler to make better informed decisions about where tasks should be placed, and what pstate to set for the CPU it is running on. Enable the user to configure UCLAMP_MIN and UCLAMP_MAX values via arguments to libpipewire-module-rt. Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
This commit is contained in:
parent
0e35750fde
commit
70d2b0eeb4
3 changed files with 73 additions and 2 deletions
|
|
@ -31,6 +31,8 @@ context.modules = [
|
|||
rt.prio = 65
|
||||
#rt.time.soft = -1
|
||||
#rt.time.hard = -1
|
||||
#uclamp.min = 0
|
||||
#uclamp.max = 1024
|
||||
}
|
||||
flags = [ ifexists nofail ]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,13 +90,16 @@ context.modules = [
|
|||
|
||||
# Uses realtime scheduling to boost the audio thread priorities. This uses
|
||||
# RTKit if the user doesn't have permission to use regular realtime
|
||||
# scheduling.
|
||||
# scheduling. You can also clamp utilisation values to improve scheduling
|
||||
# on embedded and heterogeneous systems, e.g. Arm big.LITTLE devices.
|
||||
{ name = libpipewire-module-rt
|
||||
args = {
|
||||
nice.level = -11
|
||||
#rt.prio = 88
|
||||
#rt.time.soft = -1
|
||||
#rt.time.hard = -1
|
||||
#uclamp.min = 0
|
||||
#uclamp.max = 1024
|
||||
}
|
||||
flags = [ ifexists nofail ]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@
|
|||
* - `rlimits.enabled`: enable the use of rtlimits, default true.
|
||||
* - `rtportal.enabled`: enable the use of realtime portal, default true
|
||||
* - `rtkit.enabled`: enable the use of rtkit, default true
|
||||
* - `uclamp.min`: the minimum utilisation value the scheduler should consider
|
||||
* - `uclamp.max`: the maximum utilisation value the scheduler should consider
|
||||
|
||||
* The nice level is by default set to an invalid value so that clients don't
|
||||
* automatically have the nice level raised.
|
||||
|
|
@ -101,6 +103,8 @@
|
|||
* #rlimits.enabled = true
|
||||
* #rtportal.enabled = true
|
||||
* #rtkit.enabled = true
|
||||
* #uclamp.min = 0
|
||||
* #uclamp.max = 1024
|
||||
* }
|
||||
* flags = [ ifexists nofail ]
|
||||
* }
|
||||
|
|
@ -131,13 +135,18 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
|||
#define DEFAULT_RT_TIME_SOFT -1
|
||||
#define DEFAULT_RT_TIME_HARD -1
|
||||
|
||||
#define DEFAULT_UCLAMP_MIN 0
|
||||
#define DEFAULT_UCLAMP_MAX 1024
|
||||
|
||||
#define MODULE_USAGE "( nice.level=<priority: default "SPA_STRINGIFY(DEFAULT_NICE_LEVEL)"(don't change)> ) " \
|
||||
"( rt.prio=<priority: default "SPA_STRINGIFY(DEFAULT_RT_PRIO)"> ) " \
|
||||
"( rt.time.soft=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_SOFT)"> ) " \
|
||||
"( rt.time.hard=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_HARD)"> ) " \
|
||||
"( rlimits.enabled=<default true> ) " \
|
||||
"( rtportal.enabled=<default true> ) " \
|
||||
"( rtkit.enabled=<default true> ) "
|
||||
"( rtkit.enabled=<default true> ) " \
|
||||
"( uclamp.min=<default "SPA_STRINGIFY(DEFAULT_UCLAMP_MIN)"> ) " \
|
||||
"( uclamp.max=<default "SPA_STRINGIFY(DEFAULT_UCLAMP_MAX)"> )"
|
||||
|
||||
static const struct spa_dict_item module_props[] = {
|
||||
{ PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
|
||||
|
|
@ -183,6 +192,9 @@ struct impl {
|
|||
rlim_t rt_time_soft;
|
||||
rlim_t rt_time_hard;
|
||||
|
||||
int uclamp_min;
|
||||
int uclamp_max;
|
||||
|
||||
struct spa_hook module_listener;
|
||||
|
||||
unsigned rlimits_enabled:1;
|
||||
|
|
@ -1017,6 +1029,50 @@ static int do_rtkit_setup(struct spa_loop *loop, bool async, uint32_t seq,
|
|||
}
|
||||
#endif /* HAVE_DBUS */
|
||||
|
||||
int set_uclamp(int uclamp_min, int uclamp_max, pid_t pid) {
|
||||
#ifdef __linux__
|
||||
int ret;
|
||||
struct sched_attr {
|
||||
uint32_t size;
|
||||
uint32_t sched_policy;
|
||||
uint64_t sched_flags;
|
||||
int32_t sched_nice;
|
||||
uint32_t sched_priority;
|
||||
uint64_t sched_runtime;
|
||||
uint64_t sched_deadline;
|
||||
uint64_t sched_period;
|
||||
uint32_t sched_util_min;
|
||||
uint32_t sched_util_max;
|
||||
} attr;
|
||||
|
||||
ret = syscall(SYS_sched_getattr, pid, &attr, sizeof(struct sched_attr), 0);
|
||||
if (ret) {
|
||||
pw_log_warn("Could not retrieve scheduler attributes: %d", -errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* SCHED_FLAG_KEEP_POLICY |
|
||||
* SCHED_FLAG_KEEP_PARAMS |
|
||||
* SCHED_FLAG_UTIL_CLAMP_MIN |
|
||||
* SCHED_FLAG_UTIL_CLAMP_MAX */
|
||||
attr.sched_flags = 0x8 | 0x10 | 0x20 | 0x40;
|
||||
attr.sched_util_min = uclamp_min;
|
||||
attr.sched_util_max = uclamp_max;
|
||||
|
||||
ret = syscall(SYS_sched_setattr, pid, &attr, 0);
|
||||
|
||||
if (ret) {
|
||||
pw_log_warn("Could not set scheduler attributes: %d", -errno);
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
pw_log_warn("Setting UCLAMP values is only supported on Linux");
|
||||
return -EOPNOTSUPP;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
|
||||
SPA_EXPORT
|
||||
int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
||||
{
|
||||
|
|
@ -1047,6 +1103,8 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
impl->rlimits_enabled = pw_properties_get_bool(props, "rlimits.enabled", true);
|
||||
impl->rtportal_enabled = pw_properties_get_bool(props, "rtportal.enabled", true);
|
||||
impl->rtkit_enabled = pw_properties_get_bool(props, "rtkit.enabled", true);
|
||||
impl->uclamp_min = pw_properties_get_int32(props, "uclamp.min", DEFAULT_UCLAMP_MIN);
|
||||
impl->uclamp_max = pw_properties_get_int32(props, "uclamp.max", DEFAULT_UCLAMP_MAX);
|
||||
|
||||
impl->rl.rlim_cur = impl->rt_time_soft;
|
||||
impl->rl.rlim_max = impl->rt_time_hard;
|
||||
|
|
@ -1088,6 +1146,14 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
if (!use_rtkit)
|
||||
set_rlimit(impl);
|
||||
|
||||
if (impl->uclamp_max > 1024) {
|
||||
pw_log_warn("uclamp.max out of bounds. Got %d, clamping to 1024.", impl->uclamp_max);
|
||||
impl->uclamp_max = 1024;
|
||||
}
|
||||
|
||||
if (impl->uclamp_min || impl->uclamp_max < 1024)
|
||||
set_uclamp(impl->uclamp_min, impl->uclamp_max, impl->main_pid);
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
impl->use_rtkit = use_rtkit;
|
||||
if (impl->use_rtkit) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue