From ccfc4113d7e95d1409003dbe189ea8d098234575 Mon Sep 17 00:00:00 2001 From: hotline1337 Date: Thu, 8 Oct 2026 17:30:34 +0200 Subject: [PATCH 1/2] feat(core): add cpu_hybrid profile check Add a generic cpu_hybrid profile key which requires the running CPU to be hybrid (have E-cores). The cpus file of the Atom (E-core) perf PMU at /sys/devices/cpu_atom is relied upon instead of blacklisting individual device IDs: the file has to contain a CPU number, since non-hybrid dies of hybrid SoCs (e.g. Alder Lake-S without E-cores) still expose the PMU without any Atom CPU in its cpus list. --- src/data.rs | 6 ++++++ src/hwd_misc.rs | 11 +++++++++++ src/profile.rs | 7 +++++++ tests/profiles/cpu-profile-test.toml | 1 + 4 files changed, 25 insertions(+) diff --git a/src/data.rs b/src/data.rs index 50cb114..ecc6426 100644 --- a/src/data.rs +++ b/src/data.rs @@ -370,6 +370,12 @@ pub fn get_all_devices_of_profile(devices: &ListOfDevicesT, profile: &Profile) - } } + if let Some(cpu_hybrid) = profile.cpu_hybrid + && cpu_hybrid != crate::hwd_misc::is_hybrid_cpu() + { + return vec![]; + } + if let Some(gc_versions) = &profile.gc_versions { if let Some(hwd_gc_versions) = crate::hwd_misc::get_gc_versions() { return get_all_devices_from_gc_versions(devices, &hwd_gc_versions, gc_versions); diff --git a/src/hwd_misc.rs b/src/hwd_misc.rs index ba39945..0c194be 100644 --- a/src/hwd_misc.rs +++ b/src/hwd_misc.rs @@ -50,6 +50,17 @@ fn parse_cpu_info(content: &str) -> Option { Some(CpuInfo { vendor: vendor?, family: family?, model: model? }) } +/// Checks whether the CPU is hybrid, i.e. has E-cores. +/// +/// The kernel registers the Atom (E-core) perf PMU under `/sys/devices/cpu_atom` on hybrid CPUs. +/// Non-hybrid dies of hybrid SoCs (e.g. Alder Lake-S without E-cores) still expose the PMU, but +/// without any Atom CPU in its `cpus` list, so the file has to contain a CPU number. +#[must_use] +pub(crate) fn is_hybrid_cpu() -> bool { + std::fs::read_to_string("/sys/devices/cpu_atom/cpus") + .is_ok_and(|s| s.bytes().any(|b| b.is_ascii_digit())) +} + #[must_use] pub fn get_sysfs_busid_from_amdgpu_path(amdgpu_path: &str) -> &str { amdgpu_path.split('/') diff --git a/src/profile.rs b/src/profile.rs index 5997770..85402d3 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -49,6 +49,7 @@ pub struct Profile { pub gc_versions: Option>, pub cpu_family: Option, pub cpu_models: Option>, + pub cpu_hybrid: Option, pub chassis_types: Option>, pub environment_types: Option>, pub driver_conflict_group: Option, @@ -76,6 +77,7 @@ impl Default for Profile { gc_versions: None, cpu_family: None, cpu_models: None, + cpu_hybrid: None, chassis_types: None, environment_types: None, driver_conflict_group: None, @@ -258,6 +260,7 @@ fn parse_profile(node: &toml::Table, profile_name: &str) -> Result { gc_versions: parse_whitespace_list(node, "gc_versions"), cpu_family: node.get("cpu_family").and_then(|x| x.as_str().map(str::to_string)), cpu_models: parse_whitespace_list(node, "cpu_models"), + cpu_hybrid: node.get("cpu_hybrid").and_then(toml::Value::as_bool), chassis_types: parse_whitespace_list(node, "chassis_types"), environment_types: parse_whitespace_list(node, "environment_types"), driver_conflict_group: node @@ -469,6 +472,9 @@ fn profile_into_toml(profile: &Profile) -> toml::Table { if let Some(cpu_models) = &profile.cpu_models { table.insert("cpu_models".to_owned(), cpu_models.join(" ").into()); } + if let Some(cpu_hybrid) = profile.cpu_hybrid { + table.insert("cpu_hybrid".to_owned(), cpu_hybrid.into()); + } if let Some(chassis_types) = &profile.chassis_types { table.insert("chassis_types".to_owned(), chassis_types.join(" ").into()); } @@ -771,6 +777,7 @@ mod tests { assert_eq!(parsed_profiles[0].priority, 5); assert_eq!(parsed_profiles[0].packages, "intel-lpmd"); assert_eq!(parsed_profiles[0].cpu_family, Some("6".to_owned())); + assert_eq!(parsed_profiles[0].cpu_hybrid, Some(true)); assert_eq!( parsed_profiles[0].cpu_models, Some(vec![ diff --git a/tests/profiles/cpu-profile-test.toml b/tests/profiles/cpu-profile-test.toml index ab11114..4a6d598 100644 --- a/tests/profiles/cpu-profile-test.toml +++ b/tests/profiles/cpu-profile-test.toml @@ -5,6 +5,7 @@ vendor_ids = "8086" device_ids = "*" cpu_family = "6" cpu_models = "151 154 183 186 191 170 172 189 204 213" +cpu_hybrid = true priority = 5 packages = 'intel-lpmd' post_install = """ From 3bb447205dd26b474f6961c27f9187c309fee78d Mon Sep 17 00:00:00 2001 From: hotline1337 Date: Thu, 8 Oct 2026 17:30:34 +0200 Subject: [PATCH 2/2] fix(profiles): exclude non-hybrid CPUs from intel-lpmd intel-lpmd only supports hybrid Intel CPUs (with E-cores), but the cpu_family/cpu_models filter also matches non-hybrid Alder Lake SKUs sharing the same family and model, so the daemon was installed and exited immediately on those systems. Set cpu_hybrid for the profile to skip them generically. --- profiles/pci/power_management/profiles.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/profiles/pci/power_management/profiles.toml b/profiles/pci/power_management/profiles.toml index ab11114..4a6d598 100644 --- a/profiles/pci/power_management/profiles.toml +++ b/profiles/pci/power_management/profiles.toml @@ -5,6 +5,7 @@ vendor_ids = "8086" device_ids = "*" cpu_family = "6" cpu_models = "151 154 183 186 191 170 172 189 204 213" +cpu_hybrid = true priority = 5 packages = 'intel-lpmd' post_install = """