alyx Member
Joined: 07 Aug 2024 Posts: 18
|
Posted: Wed Dec 03, 2025 7:34 am Post subject: systemd sucks. Patching intel-lpmd to not require systemd. |
|
|
(extra title info, including other power optimising tricks)
Preface: systemd is a heavy bloated mess that had no reason to come into existence as most everything it could do, openrc and sysv could also, while being much lighter, and also not trying to do everything all at once. I feel systemd has ruined the concept of owning your linux install, as nowadays you rarely get a choice unless you're using one of 6 distros. I have the same grievances with pulseaudio (which was a joke up until probably around 2020 which at that point pipewire was already better) and wayland (do i even need to say anything)
I recently got a new laptop, an ASUS Zenbook OLED UX3405C, it has a Core Ultra 5 225H. I am running Gentoo on it. I have went down the power usage rabbit hole. First off was kernel configuration, I configured my kernel to use intel pstates over acpi-cpufreq, and I defaulted the governor to performance, then I used auto-cpufreq to downclock my cpu to 3.6ghz on battery (not 3.6 on all cores, its like 3.6 on perf, 2.5 on efficiency, and 1.8 on ultra efficency cores, something like that). this got me down to 12ish watts on battery, which is pretty good.
Then I found intel's LPMD project, an insane project that can see usage etc and turn off and on cores as and when their performance is beneficial. the issue? this project is systemd only. So I patched it to not require it.
First we clone the project, ```git clone https://github.com/intel/intel-lpmd.git```
now, if we try just run ./autogen.sh without doing anything its not gonna work.
```checking for gio-unix-2.0 >= 2.22 gmodule-2.0 glib-2.0 gobject-2.0... yes
checking for libxml-2.0 >= 2.4... yes
checking for libnl-3.0... yes
checking for libnl-genl-3.0... yes
checking for libsystemd... no
checking for libsystemd-daemon... no
configure: error: libsystemd support requested but found```
libsystemd is part of the `systemd` package on gentoo, obviously since I refuse to use systemd, this package isnt on my system. Now I could just install it without actively using systemd but that would be silly. so lets patch systemd out and good init systems in.
first, we edit configure.ac to patch out the check for libsystemd, remove the following:
```PKG_CHECK_MODULES([SYSTEMD], [libsystemd], [],
[PKG_CHECK_MODULES([SYSTEMD], [libsystemd-daemon], [],
AC_MSG_ERROR([libsystemd support requested but found]))])```
now we can use autogen.sh, but youll find that make still fails.
``` CC src/intel_lpmd-lpmd_cgroup.o
src/lpmd_cgroup.c:22:10: fatal error: systemd/sd-bus.h: File o directory non esistente
22 | #include <systemd/sd-bus.h>
| ^~~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [Makefile:826: src/intel_lpmd-lpmd_cgroup.o] Error 1
make[2]: uscita dalla directory «/home/alyx/Documenti/intel-lpmd»
make[1]: *** [Makefile:1110: all-recursive] Error 1
make[1]: uscita dalla directory «/home/alyx/Documenti/intel-lpmd»
make: *** [Makefile:502: all] Error 2```
so lets go and check out that cgroup file, shall we!
`#include <systemd/sd-bus.h>`
obviously, we are using systemd stuff from the get go. a lot of things are coded to use systemd deeply in it, heres a snippet
```static int process_cpu_cgroupv2(lpmd_config_state_t *state)
{
if (cpumask_equal(state->cpumask_idx, CPUMASK_ONLINE)) {
restore_systemd_cgroup ();
return lpmd_write_str (PATH_CG2_SUBTREE_CONTROL, "-cpuset", LPMD_LOG_DEBUG);
} else {
if (lpmd_write_str (PATH_CG2_SUBTREE_CONTROL, "+cpuset", LPMD_LOG_DEBUG))
return 1;
return update_systemd_cgroup(state);
}
}```
but we can get around this. scroll down just a bit more
```/* Support for cgroup based cpu isolation */
static int process_cpu_isolate(lpmd_config_state_t *state)
{
if (lpmd_write_str ("/sys/fs/cgroup/lpm/cpuset.cpus.partition", "member", LPMD_LOG_DEBUG))
return 1;
if (!cpumask_equal(state->cpumask_idx, CPUMASK_ONLINE)) {
if (lpmd_write_str ("/sys/fs/cgroup/lpm/cpuset.cpus", get_cpu_isolation_str(state->cpumask_idx), LPMD_LOG_D>
return 1;
if (lpmd_write_str ("/sys/fs/cgroup/lpm/cpuset.cpus.partition", "isolated", LPMD_LOG_DEBUG))
return 1;
} else {
if (lpmd_write_str ("/sys/fs/cgroup/lpm/cpuset.cpus", get_cpu_isolation_str(CPUMASK_ONLINE), LPMD_LOG_DEBUG>
return 1;
}
return 0;
}```
we can just manually write to the files!
```alyx@calufrax ~/Downloads/intel-lpmd $ cat src/lpmd_cgroup.c
/*
* lpmd_cgroup.c: task isolation via cgroup setting (no systemd dependency)
*
* Copyright (C) 2025 Intel
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include "lpmd.h"
/* Support for LPM_CPU_CGROUPV2 */
#define PATH_CGROUP "/sys/fs/cgroup"
#define PATH_CG2_SUBTREE_CONTROL PATH_CGROUP "/cgroup.subtree_control"
static int write_allowed_cpus(uint8_t *vals, int size)
{
char path[256];
FILE *f;
snprintf(path, sizeof(path), "%s/cpuset.cpus", PATH_CGROUP);
f = fopen(path, "w");
if (!f)
return -1;
/* vals[] is already formatted bitmask array from LPMD helpers */
for (int i = 0; i < size; i++)
fprintf(f, "%02x", vals[i]);
fprintf(f, "\n");
fclose(f);
return 0;
}
static int restore_cgroup(void)
{
int size;
uint8_t *vals = get_cgroup_systemd_vals(CPUMASK_ONLINE, &size);
if (!vals)
return -1;
return write_allowed_cpus(vals, size);
}
static int update_cgroup(lpmd_config_state_t *state)
{
int size;
uint8_t *vals = get_cgroup_systemd_vals(state->cpumask_idx, &size);
if (!vals)
return -1;
return write_allowed_cpus(vals, size);
}
static int process_cpu_cgroupv2(lpmd_config_state_t *state)
{
if (cpumask_equal(state->cpumask_idx, CPUMASK_ONLINE)) {
restore_cgroup();
return lpmd_write_str(PATH_CG2_SUBTREE_CONTROL, "-cpuset", LPMD_LOG_DEBUG);
} else {
if (lpmd_write_str(PATH_CG2_SUBTREE_CONTROL, "+cpuset", LPMD_LOG_DEBUG))
return 1;
return update_cgroup(state);
}
}
/* Support for cgroup based cpu isolation */
static int process_cpu_isolate(lpmd_config_state_t *state)
{
if (lpmd_write_str("/sys/fs/cgroup/lpm/cpuset.cpus.partition",
"member", LPMD_LOG_DEBUG))
return 1;
if (!cpumask_equal(state->cpumask_idx, CPUMASK_ONLINE)) {
if (lpmd_write_str("/sys/fs/cgroup/lpm/cpuset.cpus",
get_cpu_isolation_str(state->cpumask_idx),
LPMD_LOG_DEBUG))
return 1;
if (lpmd_write_str("/sys/fs/cgroup/lpm/cpuset.cpus.partition",
"isolated", LPMD_LOG_DEBUG))
return 1;
} else {
if (lpmd_write_str("/sys/fs/cgroup/lpm/cpuset.cpus",
get_cpu_isolation_str(CPUMASK_ONLINE),
LPMD_LOG_DEBUG))
return 1;
}
return 0;
}
int cgroup_cleanup(void)
{
DIR *dir = opendir("/sys/fs/cgroup/lpm");
if (dir) {
closedir(dir);
rmdir("/sys/fs/cgroup/lpm");
}
restore_cgroup();
return 0;
}
int cgroup_init(lpmd_config_t *config)
{
if (lpmd_write_str(PATH_CG2_SUBTREE_CONTROL, "+cpuset", LPMD_LOG_DEBUG))
return 1;
if (config->mode == LPM_CPU_ISOLATE)
return mkdir("/sys/fs/cgroup/lpm", 0744);
return 0;
}
int process_cgroup(lpmd_config_state_t *state, enum lpm_cpu_process_mode mode)
{
if (state->cpumask_idx == CPUMASK_NONE) {
lpmd_log_debug("Ignore cgroup processing\n");
return 0;
}
lpmd_log_info("Process Cgroup ...\n");
if (mode == LPM_CPU_CGROUPV2)
return process_cpu_cgroupv2(state);
if (mode == LPM_CPU_ISOLATE)
return process_cpu_isolate(state);
return 0;
}```
so i wrote a patch. obviously posting this on here isn't very clean, and my patch also kinda sucks, but its a proof of concept and more importantly, it fucking works.
That's all, and I leave with this. A lot of companies claim to love linux (talkin' about you microsoft) but for all the flac intel gets, they are a really worthy look for modern linux machines, especially laptops. they contribute a lot to the kernel, etc and their code quality is amazing. the Xe2 driver that is still experimental has been working downright flawlessly for me on this machine for example, in both xorg and wayland sessions, with everything ive thrown at it, gaming etc. Their CPU's and ARC D/IGPUs deserve way more credit than they get.
Thanks for reading!
-alyx |
|