Introduce a 4th power state on the modern interface

This maps out more closely to how the Windows power slider behaves,
in that it has 4 states for a user to select.

The 4 new states are:
 * power-saver
 * balanced-power
 * balanced-performance
 * performance

To avoid regressions from other software that uses power-profiles-daemon
the legacy interface only advertises support for the 3 previous states.

For example if a client tries to set 'balanced' on the legacy interface
it will map out to 'balanced-power' to the daemon.
If the daemon is currently in 'balanced-performance' it will still report
'balanced' to the client.
This commit is contained in:
Mario Limonciello 2024-02-23 23:25:38 -06:00
parent 90226bf0d8
commit 266d2b7bf8
13 changed files with 305 additions and 128 deletions

View file

@ -151,9 +151,35 @@ get_profile_available (PpdApp *data,
driver_profile_support (PPD_DRIVER (data->platform_driver), profile);
}
static const char *
get_active_profile (PpdApp *data)
static PpdProfile
ppd_profile_from_legacy_str (const gchar *str)
{
if (g_strcmp0 (str, "balanced") == 0)
return PPD_PROFILE_BALANCED_POWER;
if (g_strcmp0 (str, "balanced-power") == 0)
return PPD_PROFILE_UNSET;
if (g_strcmp0 (str, "balanced-performance") == 0)
return PPD_PROFILE_UNSET;
return ppd_profile_from_str (str);
}
static const gchar *
map_profile_to_legacy_str (PpdProfile profile)
{
switch (profile) {
case PPD_PROFILE_BALANCED_PERFORMANCE:
case PPD_PROFILE_BALANCED_POWER:
return "balanced";
default:
return ppd_profile_to_str (profile);
}
}
static const char *
get_active_profile (PpdApp *data, gboolean legacy)
{
if (legacy)
return map_profile_to_legacy_str (data->active_profile);
return ppd_profile_to_str (data->active_profile);
}
@ -182,7 +208,7 @@ get_performance_degraded (PpdApp *data)
}
static GVariant *
get_profiles_variant (PpdApp *data)
get_profiles_variant (PpdApp *data, gboolean legacy)
{
GVariantBuilder builder;
guint i;
@ -196,14 +222,24 @@ get_profiles_variant (PpdApp *data)
GVariantBuilder asv_builder;
gboolean cpu, platform;
const gchar *driver = NULL;
const gchar *profile_str = NULL;
/* check if any of the drivers support */
if (!get_profile_available (data, profile))
continue;
/* compatibility for legacy interface */
if (legacy) {
if (profile == PPD_PROFILE_BALANCED_PERFORMANCE)
continue;
profile_str = map_profile_to_legacy_str (profile);
} else {
profile_str = ppd_profile_to_str (profile);
}
g_variant_builder_init (&asv_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&asv_builder, "{sv}", "Profile",
g_variant_new_string (ppd_profile_to_str (profile)));
g_variant_new_string (profile_str));
cpu = driver_profile_support (cpu_driver, profile);
platform = driver_profile_support (platform_driver, profile);
if (cpu)
@ -275,6 +311,12 @@ get_profile_holds_variant (PpdApp *data)
return g_variant_builder_end (&builder);
}
static gboolean
is_legacy_iface (const gchar *iface)
{
return g_strcmp0 (iface, POWER_PROFILES_LEGACY_IFACE_NAME) == 0;
}
static void
send_dbus_event_iface (PpdApp *data,
PropertiesMask mask,
@ -283,6 +325,7 @@ send_dbus_event_iface (PpdApp *data,
{
GVariantBuilder props_builder;
GVariant *props_changed = NULL;
gboolean legacy = is_legacy_iface (iface);
g_assert (data->connection);
@ -295,7 +338,7 @@ send_dbus_event_iface (PpdApp *data,
if (mask & PROP_ACTIVE_PROFILE) {
g_variant_builder_add (&props_builder, "{sv}", "ActiveProfile",
g_variant_new_string (get_active_profile (data)));
g_variant_new_string (get_active_profile (data, legacy)));
}
if (mask & PROP_INHIBITED) {
g_variant_builder_add (&props_builder, "{sv}", "PerformanceInhibited",
@ -308,7 +351,7 @@ send_dbus_event_iface (PpdApp *data,
}
if (mask & PROP_PROFILES) {
g_variant_builder_add (&props_builder, "{sv}", "Profiles",
get_profiles_variant (data));
get_profiles_variant (data, legacy));
}
if (mask & PROP_ACTIONS) {
g_variant_builder_add (&props_builder, "{sv}", "Actions",
@ -545,21 +588,14 @@ release_all_profile_holds (PpdApp *data)
static gboolean
set_active_profile (PpdApp *data,
const char *profile,
PpdProfile target_profile,
GError **error)
{
PpdProfile target_profile;
guint mask = PROP_ACTIVE_PROFILE;
target_profile = ppd_profile_from_str (profile);
if (target_profile == PPD_PROFILE_UNSET) {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
"Invalid profile name '%s'", profile);
return FALSE;
}
if (!get_profile_available (data, target_profile)) {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
"Cannot switch to unavailable profile '%s'", profile);
"Cannot switch to unavailable profile '%s'", ppd_profile_to_str (target_profile));
return FALSE;
}
@ -567,7 +603,7 @@ set_active_profile (PpdApp *data,
return TRUE;
g_debug ("Transitioning active profile from '%s' to '%s' by user request",
ppd_profile_to_str (data->active_profile), profile);
ppd_profile_to_str (data->active_profile), ppd_profile_to_str (target_profile));
if (g_hash_table_size (data->profile_holds) != 0 ) {
g_debug ("Releasing active profile holds");
@ -826,15 +862,16 @@ handle_get_property (GDBusConnection *connection,
gpointer user_data)
{
PpdApp *data = user_data;
gboolean legacy = is_legacy_iface (interface_name);
g_assert (data->connection);
if (g_strcmp0 (property_name, "ActiveProfile") == 0)
return g_variant_new_string (get_active_profile (data));
return g_variant_new_string (get_active_profile (data, legacy));
if (g_strcmp0 (property_name, "PerformanceInhibited") == 0)
return g_variant_new_string ("");
if (g_strcmp0 (property_name, "Profiles") == 0)
return get_profiles_variant (data);
return get_profiles_variant (data, legacy);
if (g_strcmp0 (property_name, "Actions") == 0)
return get_actions_variant (data);
if (g_strcmp0 (property_name, "PerformanceDegraded") == 0) {
@ -859,7 +896,8 @@ handle_set_property (GDBusConnection *connection,
gpointer user_data)
{
PpdApp *data = user_data;
const char *profile;
const char *profile_str;
PpdProfile target_profile;
g_assert (data->connection);
@ -873,8 +911,18 @@ handle_set_property (GDBusConnection *connection,
error))
return FALSE;
g_variant_get (value, "&s", &profile);
return set_active_profile (data, profile, error);
g_variant_get (value, "&s", &profile_str);
if (is_legacy_iface (interface_name))
target_profile = ppd_profile_from_legacy_str (profile_str);
else
target_profile = ppd_profile_from_str (profile_str);
if (target_profile == PPD_PROFILE_UNSET) {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
"Invalid profile name '%s'", profile_str);
return FALSE;
}
return set_active_profile (data, target_profile, error);
}
static void
@ -1003,7 +1051,7 @@ has_required_drivers (PpdApp *data)
!PPD_IS_DRIVER_PLATFORM (data->platform_driver))
return FALSE;
if (!get_profile_available (data, PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER))
if (!get_profile_available (data, PPD_PROFILE_BALANCED_POWER | PPD_PROFILE_POWER_SAVER))
return FALSE;
return TRUE;
@ -1367,8 +1415,8 @@ int main (int argc, char **argv)
data->probed_drivers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
data->actions = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
data->profile_holds = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) profile_hold_free);
data->active_profile = PPD_PROFILE_BALANCED;
data->selected_profile = PPD_PROFILE_BALANCED;
data->active_profile = PPD_PROFILE_BALANCED_POWER;
data->selected_profile = PPD_PROFILE_BALANCED_POWER;
data->log_level = verbose ? G_LOG_LEVEL_DEBUG : G_LOG_LEVEL_MESSAGE;
g_unix_signal_add (SIGTERM, quit_signal_callback, data);

View file

@ -106,7 +106,8 @@
The key named "Profile" (s) will be one of:
- "power-saver" (battery saving profile)
- "balanced" (the default profile)
- "balanced-power" (the default profile, biased towards power savings)
- "balanced-performance" (biased towards performance)
- "performance" (a profile that does not care about noise or battery consumption)
Only one of each type of profile will be listed, with the daemon choosing the

View file

@ -11,4 +11,4 @@
#include "ppd-profile.h"
#define NUM_PROFILES 3
#define NUM_PROFILES 4

View file

@ -151,9 +151,10 @@ ppd_action_amdgpu_panel_update_target (PpdActionAmdgpuPanelPower *self,
case PPD_PROFILE_POWER_SAVER:
target = 3;
break;
case PPD_PROFILE_BALANCED:
case PPD_PROFILE_BALANCED_POWER:
target = 1;
break;
case PPD_PROFILE_BALANCED_PERFORMANCE:
case PPD_PROFILE_PERFORMANCE:
target = 0;
break;

View file

@ -59,7 +59,7 @@ ppd_driver_amd_pstate_constructor (GType type,
construct_params);
g_object_set (object,
"driver-name", "amd_pstate",
"profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER,
"profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED_POWER | PPD_PROFILE_BALANCED_PERFORMANCE | PPD_PROFILE_POWER_SAVER,
NULL);
return object;
@ -155,8 +155,8 @@ profile_to_gov_pref (PpdProfile profile)
{
switch (profile) {
case PPD_PROFILE_POWER_SAVER:
return "powersave";
case PPD_PROFILE_BALANCED:
case PPD_PROFILE_BALANCED_POWER:
case PPD_PROFILE_BALANCED_PERFORMANCE:
return "powersave";
case PPD_PROFILE_PERFORMANCE:
return "performance";
@ -173,7 +173,9 @@ profile_to_epp_pref (PpdProfile profile)
switch (profile) {
case PPD_PROFILE_POWER_SAVER:
return "power";
case PPD_PROFILE_BALANCED:
case PPD_PROFILE_BALANCED_POWER:
return "balance_power";
case PPD_PROFILE_BALANCED_PERFORMANCE:
return "balance_performance";
case PPD_PROFILE_PERFORMANCE:
return "performance";

View file

@ -56,7 +56,7 @@ ppd_driver_intel_pstate_constructor (GType type,
construct_params);
g_object_set (object,
"driver-name", "intel_pstate",
"profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER,
"profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED_POWER | PPD_PROFILE_BALANCED_PERFORMANCE | PPD_PROFILE_POWER_SAVER,
NULL);
return object;
@ -310,7 +310,9 @@ profile_to_epp_pref (PpdProfile profile)
switch (profile) {
case PPD_PROFILE_POWER_SAVER:
return "power";
case PPD_PROFILE_BALANCED:
case PPD_PROFILE_BALANCED_POWER:
return "balance_power";
case PPD_PROFILE_BALANCED_PERFORMANCE:
return "balance_performance";
case PPD_PROFILE_PERFORMANCE:
return "performance";
@ -327,7 +329,8 @@ profile_to_epb_pref (PpdProfile profile)
switch (profile) {
case PPD_PROFILE_POWER_SAVER:
return "15";
case PPD_PROFILE_BALANCED:
case PPD_PROFILE_BALANCED_POWER:
case PPD_PROFILE_BALANCED_PERFORMANCE:
return "6";
case PPD_PROFILE_PERFORMANCE:
return "0";

View file

@ -30,7 +30,7 @@ ppd_driver_placeholder_constructor (GType type,
construct_params);
g_object_set (object,
"driver-name", "placeholder",
"profiles", PPD_PROFILE_POWER_SAVER | PPD_PROFILE_BALANCED,
"profiles", PPD_PROFILE_POWER_SAVER | PPD_PROFILE_BALANCED_POWER,
NULL);
return object;

View file

@ -48,7 +48,7 @@ ppd_driver_platform_profile_constructor (GType type,
construct_params);
g_object_set (object,
"driver-name", "platform_profile",
"profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER,
"profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED_POWER | PPD_PROFILE_POWER_SAVER,
NULL);
return object;
@ -65,7 +65,8 @@ profile_to_acpi_platform_profile_value (PpdDriverPlatformProfile *self,
if (g_strv_contains ((const char * const*) self->profile_choices, "low-power"))
return "low-power";
return "quiet";
case PPD_PROFILE_BALANCED:
case PPD_PROFILE_BALANCED_POWER:
case PPD_PROFILE_BALANCED_PERFORMANCE:
return "balanced";
case PPD_PROFILE_PERFORMANCE:
return "performance";
@ -86,7 +87,7 @@ acpi_platform_profile_value_to_profile (const char *str)
return PPD_PROFILE_POWER_SAVER;
case 'c': /* cool */
case 'b':
return PPD_PROFILE_BALANCED;
return PPD_PROFILE_BALANCED_POWER;
case 'p':
return PPD_PROFILE_PERFORMANCE;
default:

View file

@ -252,7 +252,7 @@ ppd_driver_get_profiles (PpdDriver *driver)
{
PpdDriverPrivate *priv;
g_return_val_if_fail (PPD_IS_DRIVER (driver), PPD_PROFILE_BALANCED);
g_return_val_if_fail (PPD_IS_DRIVER (driver), PPD_PROFILE_BALANCED_POWER);
priv = PPD_DRIVER_GET_PRIVATE (driver);
return priv->profiles;

View file

@ -32,7 +32,8 @@ typedef enum {
/**
* PpdProfile:
* @PPD_PROFILE_POWER_SAVER: "power-saver", the battery saving profile
* @PPD_PROFILE_BALANCED: balanced, the default profile
* @PPD_PROFILE_BALANCED_POWER: balanced, but biased towards power savings
* @PPD_PROFILE_BALANCED_PERFORMANCE: balanced but biased towards performance
* @PPD_PROFILE_PERFORMANCE: as fast as possible, a profile that does
* not care about noise or battery consumption, only available
* on some systems.
@ -40,12 +41,16 @@ typedef enum {
* The different profiles available for users to select.
*/
typedef enum {
PPD_PROFILE_POWER_SAVER = 1 << 0,
PPD_PROFILE_BALANCED = 1 << 1,
PPD_PROFILE_PERFORMANCE = 1 << 2
PPD_PROFILE_POWER_SAVER = 1 << 0,
PPD_PROFILE_BALANCED_POWER = 1 << 1,
PPD_PROFILE_BALANCED_PERFORMANCE = 1 << 2,
PPD_PROFILE_PERFORMANCE = 1 << 3,
} PpdProfile;
#define PPD_PROFILE_ALL (PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER | PPD_PROFILE_PERFORMANCE)
#define PPD_PROFILE_ALL (PPD_PROFILE_POWER_SAVER |\
PPD_PROFILE_BALANCED_POWER |\
PPD_PROFILE_BALANCED_PERFORMANCE |\
PPD_PROFILE_PERFORMANCE)
#define PPD_PROFILE_UNSET (0)
const char *ppd_profile_to_str (PpdProfile profile);

View file

@ -62,6 +62,10 @@ class Tests(dbusmock.DBusTestCase):
PP_PATH = "/org/freedesktop/UPower/PowerProfiles"
PP_INTERFACE = "org.freedesktop.UPower.PowerProfiles"
legacy = False
max_profiles = 4
default_state = "balanced-power"
@classmethod
def setUpClass(cls):
# run from local build tree if we are in one, otherwise use system instance
@ -366,6 +370,13 @@ class Tests(dbusmock.DBusTestCase):
os.remove(os.path.join(acpi_dir, "platform_profile"))
os.removedirs(acpi_dir)
def get_powerprofilesctl(self):
builddir = os.getenv("top_builddir", ".")
tool_path = os.path.join(builddir, "src", "powerprofilesctl")
if self.legacy:
return [tool_path, "--legacy"]
return [tool_path]
def assert_eventually(self, condition, message=None, timeout=5000):
"""Assert that condition function eventually returns True.
@ -449,7 +460,7 @@ class Tests(dbusmock.DBusTestCase):
"""no performance driver"""
self.start_daemon()
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.assertEqual(self.get_dbus_property("PerformanceDegraded"), "")
profiles = self.get_dbus_property("Profiles")
@ -457,7 +468,7 @@ class Tests(dbusmock.DBusTestCase):
self.assertEqual(profiles[1]["Driver"], "placeholder")
self.assertEqual(profiles[1]["PlatformDriver"], "placeholder")
self.assertEqual(profiles[0]["PlatformDriver"], "placeholder")
self.assertEqual(profiles[1]["Profile"], "balanced")
self.assertEqual(profiles[1]["Profile"], self.default_state)
self.assertEqual(profiles[0]["Profile"], "power-saver")
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("power-saver"))
@ -545,7 +556,7 @@ class Tests(dbusmock.DBusTestCase):
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("performance"))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "performance")
@ -592,13 +603,13 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.assertEqual(profiles[0]["Driver"], "multiple")
self.assertEqual(profiles[0]["CpuDriver"], "intel_pstate")
self.assertEqual(profiles[0]["Profile"], "power-saver")
energy_prefs = os.path.join(dir2, "energy_performance_preference")
self.assert_file_eventually_contains(energy_prefs, "balance_performance")
self.assert_file_eventually_contains(energy_prefs, "balance_power")
# Set performance mode
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("performance"))
@ -624,7 +635,7 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.assertEqual(profiles[0]["Driver"], "multiple")
self.assertEqual(profiles[0]["CpuDriver"], "intel_pstate")
self.assertEqual(profiles[0]["PlatformDriver"], "platform_profile")
@ -661,13 +672,13 @@ class Tests(dbusmock.DBusTestCase):
self.assert_file_eventually_contains(gov_path, "powersave")
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.assertEqual(profiles[0]["Driver"], "multiple")
self.assertEqual(profiles[0]["CpuDriver"], "intel_pstate")
self.assertEqual(profiles[0]["Profile"], "power-saver")
self.assert_file_eventually_contains(
os.path.join(dir1, "energy_performance_preference"), "balance_performance"
os.path.join(dir1, "energy_performance_preference"), "balance_power"
)
self.stop_daemon()
@ -699,14 +710,14 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# Error when setting performance mode
with self.assertRaises(gi.repository.GLib.GError):
self.set_dbus_property(
"ActiveProfile", GLib.Variant.new_string("performance")
)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
energy_prefs = os.path.join(dir1, "energy_performance_preference")
self.assert_file_eventually_contains(energy_prefs, "balance_performance\n")
@ -741,7 +752,7 @@ class Tests(dbusmock.DBusTestCase):
self.assertEqual(len(profiles), 2)
self.assertEqual(profiles[0]["Driver"], "placeholder")
self.assertEqual(profiles[0]["PlatformDriver"], "placeholder")
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
energy_prefs = os.path.join(dir1, "energy_performance_preference")
self.assert_file_eventually_contains(energy_prefs, "performance\n")
@ -783,11 +794,11 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.assertEqual(profiles[0]["Driver"], "multiple")
self.assertEqual(profiles[0]["CpuDriver"], "intel_pstate")
self.assertEqual(profiles[0]["PlatformDriver"], "placeholder")
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# Set power-saver mode
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("power-saver"))
@ -877,7 +888,7 @@ class Tests(dbusmock.DBusTestCase):
# Verify that only amd-pstate is loaded
self.start_daemon()
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.assertEqual(profiles[0]["Driver"], "multiple")
self.assertEqual(profiles[0]["CpuDriver"], "amd_pstate")
self.assertEqual(profiles[0]["PlatformDriver"], "placeholder")
@ -936,7 +947,7 @@ class Tests(dbusmock.DBusTestCase):
# Verify that both drivers are loaded
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.assertEqual(profiles[0]["Driver"], "multiple")
self.assertEqual(profiles[0]["CpuDriver"], "amd_pstate")
self.assertEqual(profiles[0]["PlatformDriver"], "platform_profile")
@ -950,8 +961,10 @@ class Tests(dbusmock.DBusTestCase):
self.assertEqual(self.get_dbus_property("ActiveProfile"), "performance")
# test both drivers can switch to balanced
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("balanced"))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.set_dbus_property(
"ActiveProfile", GLib.Variant.new_string(self.default_state)
)
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# test when CPU driver fails to write
self.change_immutable(prefs1, True)
@ -959,7 +972,7 @@ class Tests(dbusmock.DBusTestCase):
self.set_dbus_property(
"ActiveProfile", GLib.Variant.new_string("power-saver")
)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.assertEqual(
self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b"balanced"
)
@ -971,20 +984,20 @@ class Tests(dbusmock.DBusTestCase):
self.set_dbus_property(
"ActiveProfile", GLib.Variant.new_string("power-saver")
)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# make sure CPU was undone since platform failed
self.assertEqual(
self.read_sysfs_file(
"sys/devices/system/cpu/cpufreq/policy0/energy_performance_preference"
),
b"balance_performance",
b"balance_power",
)
self.assertEqual(
self.read_sysfs_file(
"sys/devices/system/cpu/cpufreq/policy1/energy_performance_preference"
),
b"balance_performance",
b"balance_power",
)
self.change_immutable(profile, False)
@ -1027,7 +1040,7 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.assertEqual(profiles[0]["Driver"], "multiple")
self.assertEqual(profiles[0]["CpuDriver"], "amd_pstate")
@ -1036,7 +1049,7 @@ class Tests(dbusmock.DBusTestCase):
energy_prefs = os.path.join(dir2, "energy_performance_preference")
scaling_governor = os.path.join(dir2, "scaling_governor")
self.assert_file_eventually_contains(energy_prefs, "balance_performance")
self.assert_file_eventually_contains(energy_prefs, "balance_power")
self.assert_file_eventually_contains(scaling_governor, "powersave")
# Set performance mode
@ -1090,14 +1103,14 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.assertEqual(profiles[0]["Driver"], "multiple")
self.assertEqual(profiles[0]["CpuDriver"], "amd_pstate")
self.assertEqual(profiles[0]["Profile"], "power-saver")
# This matches what's written by ppd-driver-amd-pstate.c
energy_prefs = os.path.join(dir1, "energy_performance_preference")
self.assert_file_eventually_contains(energy_prefs, "balance_performance")
self.assert_file_eventually_contains(energy_prefs, "balance_power")
scaling_governor = os.path.join(dir1, "scaling_governor")
self.assert_file_eventually_contains(scaling_governor, "powersave")
@ -1136,14 +1149,14 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# Error when setting performance mode
with self.assertRaises(gi.repository.GLib.GError):
self.set_dbus_property(
"ActiveProfile", GLib.Variant.new_string("performance")
)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
energy_prefs = os.path.join(dir1, "energy_performance_preference")
self.assert_file_eventually_contains(energy_prefs, "balance_performance\n")
@ -1182,7 +1195,7 @@ class Tests(dbusmock.DBusTestCase):
self.assertEqual(len(profiles), 2)
self.assertEqual(profiles[0]["Driver"], "placeholder")
self.assertEqual(profiles[0]["PlatformDriver"], "placeholder")
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
energy_prefs = os.path.join(dir1, "energy_performance_preference")
self.assert_file_eventually_contains(energy_prefs, "performance\n")
@ -1285,7 +1298,7 @@ class Tests(dbusmock.DBusTestCase):
os.environ["POWER_PROFILE_DAEMON_FAKE_DRIVER"] = "1"
self.start_daemon()
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.stop_daemon()
del os.environ["POWER_PROFILE_DAEMON_FAKE_DRIVER"]
@ -1323,7 +1336,9 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
# verify balanced updated it
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("balanced"))
self.set_dbus_property(
"ActiveProfile", GLib.Variant.new_string(self.default_state)
)
self.assert_sysfs_attr_eventually_is(edp, amdgpu_panel_power_savings, "1")
# verify power saver updated it
@ -1451,7 +1466,7 @@ class Tests(dbusmock.DBusTestCase):
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
# Was set in platform_profile before we loaded the drivers
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.assertEqual(self.get_dbus_property("PerformanceDegraded"), "")
self.stop_daemon()
@ -1472,7 +1487,7 @@ class Tests(dbusmock.DBusTestCase):
self.assertEqual(profiles[0]["Driver"], "platform_profile")
self.assertEqual(profiles[0]["PlatformDriver"], "platform_profile")
self.assertEqual(profiles[0]["Profile"], "power-saver")
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.assertEqual(
self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b"cool"
)
@ -1483,7 +1498,9 @@ class Tests(dbusmock.DBusTestCase):
)
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("performance"))
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("balanced"))
self.set_dbus_property(
"ActiveProfile", GLib.Variant.new_string(self.default_state)
)
self.assertEqual(
self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b"balanced"
)
@ -1506,7 +1523,7 @@ class Tests(dbusmock.DBusTestCase):
self.assertEqual(profiles[0]["Driver"], "platform_profile")
self.assertEqual(profiles[0]["PlatformDriver"], "platform_profile")
self.assertEqual(profiles[0]["Profile"], "power-saver")
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.assertEqual(
self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b"balanced"
)
@ -1564,14 +1581,14 @@ class Tests(dbusmock.DBusTestCase):
self.call_dbus_method("ReleaseProfile", GLib.Variant("(u)", cookie))
self.assert_eventually(lambda: released_cookie == cookie)
self.assert_eventually(
lambda: self.changed_properties.get("ActiveProfile") == "balanced"
lambda: self.changed_properties.get("ActiveProfile") == self.default_state
)
self.assert_eventually(
lambda: self.changed_properties.get("ActiveProfileHolds") == []
)
profile_holds = self.get_dbus_property("ActiveProfileHolds")
self.assertEqual(len(profile_holds), 0)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# When the profile is changed manually, holds should be released a
self.call_dbus_method(
@ -1583,12 +1600,14 @@ class Tests(dbusmock.DBusTestCase):
)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "performance")
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("balanced"))
self.set_dbus_property(
"ActiveProfile", GLib.Variant.new_string(self.default_state)
)
self.assert_eventually(
lambda: self.changed_properties.get("ActiveProfile") == "balanced"
lambda: self.changed_properties.get("ActiveProfile") == self.default_state
)
self.assertEqual(len(self.get_dbus_property("ActiveProfileHolds")), 0)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# When all holds are released, the last manually selected profile should be activated
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("power-saver"))
@ -1630,11 +1649,16 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
self.assert_eventually(lambda: self.get_dbus_property("ActiveProfile"))
builddir = os.getenv("top_builddir", ".")
tool_path = os.path.join(builddir, "src", "powerprofilesctl")
tool = self.get_powerprofilesctl() + [
"launch",
"-p",
"power-saver",
"sleep",
"3600",
]
with subprocess.Popen(
[tool_path, "launch", "-p", "power-saver", "sleep", "3600"],
tool,
stdout=sys.stdout,
stderr=sys.stderr,
) as launch_process:
@ -1661,7 +1685,7 @@ class Tests(dbusmock.DBusTestCase):
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# Test every order of holding and releasing power-saver and performance
# hold performance and then power-saver, release in the same order
@ -1676,7 +1700,7 @@ class Tests(dbusmock.DBusTestCase):
self.call_dbus_method("ReleaseProfile", GLib.Variant("(u)", performance_cookie))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "power-saver")
self.call_dbus_method("ReleaseProfile", GLib.Variant("(u)", powersaver_cookie))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# hold performance and then power-saver, but release power-saver first
performance_cookie = self.call_dbus_method(
@ -1690,7 +1714,7 @@ class Tests(dbusmock.DBusTestCase):
self.call_dbus_method("ReleaseProfile", GLib.Variant("(u)", powersaver_cookie))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "performance")
self.call_dbus_method("ReleaseProfile", GLib.Variant("(u)", performance_cookie))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# hold power-saver and then performance, release in the same order
powersaver_cookie = self.call_dbus_method(
@ -1704,7 +1728,7 @@ class Tests(dbusmock.DBusTestCase):
self.call_dbus_method("ReleaseProfile", GLib.Variant("(u)", powersaver_cookie))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "performance")
self.call_dbus_method("ReleaseProfile", GLib.Variant("(u)", performance_cookie))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# hold power-saver and then performance, but release performance first
powersaver_cookie = self.call_dbus_method(
@ -1718,7 +1742,7 @@ class Tests(dbusmock.DBusTestCase):
self.call_dbus_method("ReleaseProfile", GLib.Variant("(u)", performance_cookie))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "power-saver")
self.call_dbus_method("ReleaseProfile", GLib.Variant("(u)", powersaver_cookie))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.stop_daemon()
@ -1728,7 +1752,7 @@ class Tests(dbusmock.DBusTestCase):
self.create_platform_profile()
self.start_daemon()
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("power-saver"))
self.stop_daemon()
@ -1756,7 +1780,7 @@ class Tests(dbusmock.DBusTestCase):
self.create_platform_profile()
self.start_daemon()
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.set_dbus_property("ActiveProfile", GLib.Variant.new_string("power-saver"))
self.stop_daemon()
self.remove_platform_profile()
@ -1765,7 +1789,7 @@ class Tests(dbusmock.DBusTestCase):
self.create_empty_platform_profile()
self.start_daemon()
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/")
self.write_file_contents(
@ -1784,7 +1808,7 @@ class Tests(dbusmock.DBusTestCase):
self.obj_polkit.SetAllowed(dbus.Array([], signature="s"))
self.start_daemon()
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
proxy = Gio.DBusProxy.new_sync(
self.dbus,
@ -1811,7 +1835,7 @@ class Tests(dbusmock.DBusTestCase):
self.obj_polkit.SetAllowed(dbus.Array([], signature="s"))
self.start_daemon()
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
with self.assertRaises(gi.repository.GLib.GError) as error:
self.call_dbus_method(
@ -1819,7 +1843,7 @@ class Tests(dbusmock.DBusTestCase):
)
self.assertIn("AccessDenied", str(error.exception))
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
self.assertEqual(len(self.get_dbus_property("ActiveProfileHolds")), 0)
self.stop_daemon()
@ -1854,7 +1878,7 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
profiles = self.get_dbus_property("Profiles")
self.assertEqual(len(profiles), 3)
self.assertEqual(len(profiles), self.max_profiles)
self.assertEqual(self.get_dbus_property("PerformanceDegraded"), "")
self.stop_daemon()
@ -1864,10 +1888,9 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
builddir = os.getenv("top_builddir", ".")
tool_path = os.path.join(builddir, "src", "powerprofilesctl")
tool = self.get_powerprofilesctl() + ["version"]
cmd = subprocess.run([tool_path, "version"], check=True)
cmd = subprocess.run(tool, check=True)
self.assertEqual(cmd.returncode, 0)
def test_powerprofilesctl_list_command(self):
@ -1875,59 +1898,59 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
builddir = os.getenv("top_builddir", ".")
tool_path = os.path.join(builddir, "src", "powerprofilesctl")
tool = self.get_powerprofilesctl() + ["list"]
cmd = subprocess.run([tool_path, "list"], capture_output=True, check=True)
cmd = subprocess.run(tool, capture_output=True, check=True)
self.assertEqual(cmd.returncode, 0)
self.assertIn("* balanced", cmd.stdout.decode("utf-8"))
self.assertIn(f"* {self.default_state}:", cmd.stdout.decode("utf-8"))
def test_powerprofilesctl_set_get_commands(self):
"""Check powerprofilesctl set/get command works"""
self.start_daemon()
builddir = os.getenv("top_builddir", ".")
tool_path = os.path.join(builddir, "src", "powerprofilesctl")
tool = self.get_powerprofilesctl()
self.assertEqual(self.get_dbus_property("ActiveProfile"), "balanced")
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
cmd = subprocess.run([tool_path, "get"], capture_output=True, check=True)
cmd = subprocess.run(tool + ["get"], capture_output=True, check=True)
self.assertEqual(cmd.returncode, 0)
self.assertEqual(cmd.stdout, b"balanced\n")
if self.legacy:
self.assertEqual(cmd.stdout, b"balanced\n")
else:
self.assertEqual(cmd.stdout, b"balanced-power\n")
cmd = subprocess.run(
[tool_path, "set", "power-saver"], capture_output=True, check=True
tool + ["set", "power-saver"], capture_output=True, check=True
)
self.assertEqual(cmd.returncode, 0)
self.assertEqual(self.get_dbus_property("ActiveProfile"), "power-saver")
cmd = subprocess.run([tool_path, "get"], capture_output=True, check=True)
cmd = subprocess.run(tool + ["get"], capture_output=True, check=True)
self.assertEqual(cmd.returncode, 0)
self.assertEqual(cmd.stdout, b"power-saver\n")
def test_powerprofilesctl_error(self):
"""Check that powerprofilesctl returns 1 rather than an exception on error"""
builddir = os.getenv("top_builddir", ".")
tool_path = os.path.join(builddir, "src", "powerprofilesctl")
tool = self.get_powerprofilesctl()
with self.assertRaises(subprocess.CalledProcessError) as error:
subprocess.check_output(
[tool_path, "list"], stderr=subprocess.PIPE, universal_newlines=True
tool + ["list"], stderr=subprocess.PIPE, universal_newlines=True
)
self.assertNotIn("Traceback", error.exception.stderr)
with self.assertRaises(subprocess.CalledProcessError) as error:
subprocess.check_output(
[tool_path, "get"], stderr=subprocess.PIPE, universal_newlines=True
tool + ["get"], stderr=subprocess.PIPE, universal_newlines=True
)
self.assertNotIn("Traceback", error.exception.stderr)
with self.assertRaises(subprocess.CalledProcessError) as error:
subprocess.check_output(
[tool_path, "set", "not-a-profile"],
tool + ["set", "not-a-profile"],
stderr=subprocess.PIPE,
universal_newlines=True,
)
@ -1935,7 +1958,7 @@ class Tests(dbusmock.DBusTestCase):
with self.assertRaises(subprocess.CalledProcessError) as error:
subprocess.check_output(
[tool_path, "list-holds"],
tool + ["list-holds"],
stderr=subprocess.PIPE,
universal_newlines=True,
)
@ -1943,7 +1966,7 @@ class Tests(dbusmock.DBusTestCase):
with self.assertRaises(subprocess.CalledProcessError) as error:
subprocess.check_output(
[tool_path, "launch", "-p", "power-saver", "sleep", "1"],
tool + ["launch", "-p", "power-saver", "sleep", "1"],
stderr=subprocess.PIPE,
universal_newlines=True,
)
@ -1952,7 +1975,7 @@ class Tests(dbusmock.DBusTestCase):
self.start_daemon()
with self.assertRaises(subprocess.CalledProcessError) as error:
subprocess.check_output(
[tool_path, "set", "not-a-profile"],
tool + ["set", "not-a-profile"],
stderr=subprocess.PIPE,
universal_newlines=True,
)
@ -1974,14 +1997,6 @@ class Tests(dbusmock.DBusTestCase):
return prop_str
class LegacyDBusNameTests(Tests):
"""This will repeats all the tests in the Tests class using the legacy dbus name"""
PP = "net.hadess.PowerProfiles"
PP_PATH = "/net/hadess/PowerProfiles"
PP_INTERFACE = "net.hadess.PowerProfiles"
if __name__ == "__main__":
# run ourselves under umockdev
if "umockdev" not in os.environ.get("LD_PRELOAD", ""):

View file

@ -0,0 +1,77 @@
#!/usr/bin/python3
# power-profiles-daemon integration test suite
#
# Run in built tree to test local built binaries, or from anywhere else to test
# system installed binaries.
#
# Copyright: (C) 2011 Martin Pitt <martin.pitt@ubuntu.com>
# (C) 2020 Bastien Nocera <hadess@hadess.net>
# (C) 2021 David Redondo <kde@david-redondo.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
import os
import subprocess
import sys
import unittest
from integration_test import Tests
class LegacyDBusNameTests(Tests):
"""This will repeats all the tests in the Tests class using the legacy dbus name"""
PP = "net.hadess.PowerProfiles"
PP_PATH = "/net/hadess/PowerProfiles"
PP_INTERFACE = "net.hadess.PowerProfiles"
legacy = True
max_profiles = 3
default_state = "balanced"
def test_powerprofilesctl_legacy_commands(self):
"""Check ONLY legacy profile names work"""
self.start_daemon()
tool = self.get_powerprofilesctl()
self.assertEqual(self.get_dbus_property("ActiveProfile"), self.default_state)
# try to set to modern profile name on legacy interface
with self.assertRaises(subprocess.CalledProcessError) as error:
subprocess.check_output(
tool + ["set", "balanced-power"],
stderr=subprocess.PIPE,
universal_newlines=True,
)
self.assertNotIn("Traceback", error.exception.stderr)
# try to set using legacy profile name on legacy interface
cmd = subprocess.run(
tool + ["set", "balanced"], capture_output=True, check=True
)
self.assertEqual(cmd.returncode, 0)
if __name__ == "__main__":
# run ourselves under umockdev
if "umockdev" not in os.environ.get("LD_PRELOAD", ""):
os.execvp("umockdev-wrapper", ["umockdev-wrapper", sys.executable] + sys.argv)
prog = unittest.main(exit=False)
if prog.result.errors or prog.result.failures:
sys.exit(1)
# Translate to skip error
if prog.result.testsRun == len(prog.result.skipped):
sys.exit(77)

View file

@ -83,3 +83,27 @@ if pylint.found()
env: nomalloc,
)
endif
# legacy tests
legacy_integration_tests = files('legacy_integration_test.py')
r = run_command(python3, unittest_inspector, legacy_integration_tests, check: true)
legacy_unit_tests = r.stdout().strip().split('\n')
foreach ut: legacy_unit_tests
test(ut,
python3,
args: [
legacy_integration_tests,
ut,
],
env: envs,
)
endforeach
if pylint.found()
test('pylint-legacy-integration-tests',
pylint,
args: integration_pylint_flags + legacy_integration_tests,
env: nomalloc,
)
endif