[neon/backports-jammy/power-profiles-daemon/Neon/unstable] /: 0.11.1-1 (patches unapplied)
git-ubuntu importer
null at kde.org
Tue Sep 24 23:21:42 BST 2024
Git commit 1c1f589fed62b95948e5f7c460ac10a1e7cdf591 by git-ubuntu importer, on behalf of Sebastien Bacher.
Committed on 24/06/2022 at 16:43.
Pushed by carlosdem into branch 'Neon/unstable'.
0.11.1-1 (patches unapplied)
Imported using git-ubuntu import.
A +25 -0 .ci/fail_skipped_tests.py
A +2 -0 .gitignore
M +5 -2 .gitlab-ci.yml
M +19 -0 NEWS
M +64 -0 README.md
M +8 -0 debian/changelog
M +14 -1 debian/patches/build_older_polkit.patch
M +3 -3 meson.build
M +19 -13 src/power-profiles-daemon.c
M +39 -18 src/powerprofilesctl.in
M +9 -1 src/ppd-action-trickle-charge.c
M +53 -7 src/ppd-driver-intel-pstate.c
M +12 -4 src/ppd-utils.c
M +215 -4 tests/integration-test.py
M +1 -1 tests/meson.build
https://invent.kde.org/neon/backports-jammy/power-profiles-daemon/-/commit/1c1f589fed62b95948e5f7c460ac10a1e7cdf591
diff --git a/.ci/fail_skipped_tests.py b/.ci/fail_skipped_tests.py
new file mode 100755
index 0000000..6349921
--- /dev/null
+++ b/.ci/fail_skipped_tests.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python3
+
+from lxml import etree
+import sys
+
+def format_title(title):
+ """Put title in a box"""
+ box = {
+ 'tl': '╔', 'tr': '╗', 'bl': '╚', 'br': '╝', 'h': '═', 'v': '║',
+ }
+ hline = box['h'] * (len(title) + 2)
+
+ return '\n'.join([
+ f"{box['tl']}{hline}{box['tr']}",
+ f"{box['v']} {title} {box['v']}",
+ f"{box['bl']}{hline}{box['br']}",
+ ])
+
+tree = etree.parse(sys.argv[1])
+for suite in tree.xpath('/testsuites/testsuite'):
+ skipped = suite.get('skipped')
+ if int(skipped) != 0:
+ print(format_title('Tests were skipped when they should not have been. All the tests must be run in the CI'),
+ end='\n\n', flush=True)
+ sys.exit(1)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b8dbfe9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+power-profiles-daemon
+data/net.hadess.PowerProfiles.conf
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 592a89d..e0bd869 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,18 +16,21 @@ variables:
python3-dbusmock
python3-pylint
umockdev
+ e2fsprogs
build_stable:
before_script:
- dnf upgrade -y --nogpgcheck fedora-release fedora-repos*
- dnf update -y && dnf install -y $DEPENDENCIES
+ - mkdir tmpdir/
script:
- meson -Dgtk_doc=true -Dpylint=true _build
- ninja -v -C _build
- ninja -v -C _build install
- ninja -v -C _build uninstall
- - ninja -v -C _build dist
- - meson test -C _build
+ - TMPDIR=$(pwd)/tmpdir meson test -C _build
+ - .ci/fail_skipped_tests.py _build/meson-logs/testlog.junit.xml
+ - TMPDIR=$(pwd)/tmpdir ninja -v -C _build dist
artifacts:
when: always
paths:
diff --git a/NEWS b/NEWS
index 224ebbc..b8488c0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,22 @@
+0.11.1
+------
+
+This release stops power-profiles-daemon from modifying the cpufreq driver when
+driver when the user/administrator has chosen to disable the Intel P-State scaling
+governor (eg. forcing a passive operation mode).
+
+More information is available in the README.
+
+0.11
+----
+
+This release fixes problems on Intel machines when the CPUs didn't support turbo at
+all, or the performance scaling governor was built as default in the kernel.
+
+It also adds better end-user documentation, fixes in the command-line tool to not
+cause bug report tools to popup on not-uncommon errors, and a bug fix for running
+on some systems with controllable charge speeds.
+
0.10.1
------
diff --git a/README.md b/README.md
index 99e102e..8684372 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,41 @@ they are also expected to adjust the behaviour of the desktop depending on the m
such as turning the screen off after inaction more aggressively when in power-saver
mode.
+How to use
+----------
+
+There are interfaces to switch profiles in the latest versions of KDE and GNOME. Those
+desktops also include more thorough integration with its low-power mode. Please check
+the user guides for each of them for details.
+
+power-profiles-daemon also ships with a command-line utility called `powerprofilesctl`
+which can be used for scripting, as it allows getting and setting the active profile,
+listing the available profiles, and launching commands while holding the performance
+or the power-saver profile.
+
+For example, this will be useful to avoid manual switching profiles while compiling
+large projects:
+```sh
+powerprofilesctl launch make
+```
+
+If you're a developer, you might also want to use GLib's [`GPowerProfileMonitor`](https://docs.gtk.org/gio/iface.PowerProfileMonitor.html)
+through C, or one of its bindings, so your application can react to the user requesting
+a low-power mode.
+
+Conflicts
+---------
+
+If `power-profiles-daemon` refuses to start, it's likely that you have [a conflicting
+service installed and running](data/power-profiles-daemon.service.in#L3), or your
+distribution ships [a version of tlp that actively breaks power-profiles-daemon](https://bugzilla.redhat.com/show_bug.cgi?id=2028701#c11),
+or you use the [upstream package](https://github.com/linrunner/TLP/commit/6a9388e1af95051a90a33b4014af1158dfa241f6).
+
+```sh
+systemctl unmask power-profiles-daemon.service
+systemctl start power-profiles-daemon.service
+```
+
Debugging
---------
@@ -62,6 +97,35 @@ If that doesn't work, please file an issue, attach the output of:
sudo G_MESSAGES_DEBUG=all /usr/libexec/power-profiles-daemon -r -v
```
+Operations on Intel-based machines
+----------------------------------
+
+The "driver" for making the hardware act on the user-selected power profile on Intel
+CPU-based machines is based on the [Intel P-State scaling driver](https://www.kernel.org/doc/html/v5.17/admin-guide/pm/intel_pstate.html).
+
+It is only used if a `platform_profile` driver isn't available for the system, and the
+CPU supports hardware-managed P-states (HWP). If HWP isn't supported, or the P-State
+scaling driver is set to `passive` mode.
+
+System without `platform_profile support` but with `active` P-State operation mode:
+```
+$ cat /sys/firmware/acpi/platform_profile_choices
+cat: /sys/firmware/acpi/platform_profile_choices: No such file or directory
+$ cat /sys/devices/system/cpu/intel_pstate/status
+active
+```
+
+If the Intel P-State scaling driver is in `passive` mode, either because the system doesn't
+support HWP, or the administator has disabled it, then the placeholder driver will be
+used, and there won't be a performance mode.
+
+Finally, if the Intel P-State scaling driver is used in `active` mode, the P-State
+scaling governor will be changed to `powersave` as it is the only P-State scaling
+governor that allows for the "Energy vs Performance Hints" to be taken into consideration,
+ie. the only P-State scaling governor that allows power-profiles-daemon to work.
+
+For more information, please refer to the [Intel P-State scaling driver documentation](https://www.kernel.org/doc/html/v5.17/admin-guide/pm/intel_pstate.html).
+
Testing
-------
diff --git a/debian/changelog b/debian/changelog
index 14afa9f..f144c32 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+power-profiles-daemon (0.11.1-1) unstable; urgency=medium
+
+ * New upstream version
+ * debian/patches/build_older_polkit.patch:
+ - refresh the patch to also lower the polkit requirement update
+
+ -- Sebastien Bacher <seb128 at ubuntu.com> Fri, 24 Jun 2022 13:23:07 +0200
+
power-profiles-daemon (0.10.1-3) unstable; urgency=medium
* debian/patches/remove_tlp_conflict.patch:
diff --git a/debian/patches/build_older_polkit.patch b/debian/patches/build_older_polkit.patch
index 6cd50f2..b05b5ae 100644
--- a/debian/patches/build_older_polkit.patch
+++ b/debian/patches/build_older_polkit.patch
@@ -16,7 +16,7 @@ Index: power-profiles-daemon/src/power-profiles-daemon.c
static const char *
get_active_profile (PpdApp *data)
{
-@@ -603,8 +610,8 @@ check_action_permission (PpdApp
+@@ -609,8 +616,8 @@ check_action_permission (PpdApp
GError **error)
{
g_autoptr(GError) local_error = NULL;
@@ -27,3 +27,16 @@ Index: power-profiles-daemon/src/power-profiles-daemon.c
subject = polkit_system_bus_name_new (sender);
result = polkit_authority_check_authorization_sync (data->auth,
+Index: power-profiles-daemon/meson.build
+===================================================================
+--- power-profiles-daemon.orig/meson.build
++++ power-profiles-daemon/meson.build
+@@ -34,7 +34,7 @@ endif
+ gio_dep = dependency('gio-2.0')
+ gudev_dep = dependency('gudev-1.0', version: '>= 234')
+ upower_dep = dependency('upower-glib')
+-polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.114')
++polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.91')
+ polkit_policy_directory = polkit_gobject_dep.get_pkgconfig_variable('policydir')
+
+ gnome = import('gnome')
diff --git a/meson.build b/meson.build
index 675bb10..165f5b0 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
project('power-profiles-daemon', [ 'c' ],
- version: '0.10.1',
+ version: '0.11.1',
license: 'GPLv3+',
default_options: [
'buildtype=debugoptimized',
@@ -34,7 +34,7 @@ endif
gio_dep = dependency('gio-2.0')
gudev_dep = dependency('gudev-1.0', version: '>= 234')
upower_dep = dependency('upower-glib')
-polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.91')
+polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.114')
polkit_policy_directory = polkit_gobject_dep.get_pkgconfig_variable('policydir')
gnome = import('gnome')
@@ -44,7 +44,7 @@ add_global_arguments(common_cflags, language: 'c')
if get_option('pylint')
pylint = find_program('pylint-3', 'pylint3', 'pylint', required: true)
- pylint_flags = ['-d', 'C0116', '-d', 'C0114', '-d', 'W0707']
+ pylint_flags = ['-d', 'C0116', '-d', 'C0114', '-d', 'W0707', '-d', 'W0706' ]
endif
xmllint = find_program('xmllint', required: false)
diff --git a/src/power-profiles-daemon.c b/src/power-profiles-daemon.c
index 7128ac8..ab1b095 100644
--- a/src/power-profiles-daemon.c
+++ b/src/power-profiles-daemon.c
@@ -321,22 +321,25 @@ actions_activate_profile (GPtrArray *actions,
}
}
-static void
-activate_target_profile (PpdApp *data,
- PpdProfile target_profile,
- PpdProfileActivationReason reason)
+static gboolean
+activate_target_profile (PpdApp *data,
+ PpdProfile target_profile,
+ PpdProfileActivationReason reason,
+ GError **error)
{
- g_autoptr(GError) error = NULL;
+ GError *internal_error = NULL;
g_debug ("Setting active profile '%s' for reason '%s' (current: '%s')",
ppd_profile_to_str (target_profile),
ppd_profile_activation_reason_to_str (reason),
ppd_profile_to_str (data->active_profile));
- if (!ppd_driver_activate_profile (data->driver, target_profile, reason, &error)) {
+ if (!ppd_driver_activate_profile (data->driver, target_profile, reason, &internal_error)) {
g_warning ("Failed to activate driver '%s': %s",
ppd_driver_get_driver_name (data->driver),
- error->message);
+ internal_error->message);
+ g_propagate_error (error, internal_error);
+ return FALSE;
}
actions_activate_profile (data->actions, target_profile);
@@ -346,6 +349,8 @@ activate_target_profile (PpdApp *data,
if (reason == PPD_PROFILE_ACTIVATION_REASON_USER ||
reason == PPD_PROFILE_ACTIVATION_REASON_INTERNAL)
save_configuration (data);
+
+ return TRUE;
}
static void
@@ -394,7 +399,8 @@ set_active_profile (PpdApp *data,
mask |= PROP_ACTIVE_PROFILE_HOLDS;
}
- activate_target_profile (data, target_profile, PPD_PROFILE_ACTIVATION_REASON_USER);
+ if (!activate_target_profile (data, target_profile, PPD_PROFILE_ACTIVATION_REASON_USER, error))
+ return FALSE;
data->selected_profile = target_profile;
send_dbus_event (data, mask);
@@ -459,7 +465,7 @@ driver_profile_changed_cb (PpdDriver *driver,
if (new_profile == data->active_profile)
return;
- activate_target_profile (data, new_profile, PPD_PROFILE_ACTIVATION_REASON_INTERNAL);
+ activate_target_profile (data, new_profile, PPD_PROFILE_ACTIVATION_REASON_INTERNAL, NULL);
send_dbus_event (data, PROP_ACTIVE_PROFILE);
}
@@ -484,14 +490,14 @@ release_profile_hold (PpdApp *data,
if (g_hash_table_size (data->profile_holds) == 0 &&
hold_profile != data->selected_profile) {
g_debug ("No profile holds anymore going back to last manually activated profile");
- activate_target_profile (data, data->selected_profile, PPD_PROFILE_ACTIVATION_REASON_PROGRAM_HOLD);
+ activate_target_profile (data, data->selected_profile, PPD_PROFILE_ACTIVATION_REASON_PROGRAM_HOLD, NULL);
mask |= PROP_ACTIVE_PROFILE;
} else if (hold_profile == data->active_profile) {
next_profile = effective_hold_profile (data);
if (next_profile != PPD_PROFILE_UNSET &&
next_profile != data->active_profile) {
g_debug ("Next profile is %s", ppd_profile_to_str (next_profile));
- activate_target_profile (data, next_profile, PPD_PROFILE_ACTIVATION_REASON_PROGRAM_HOLD);
+ activate_target_profile (data, next_profile, PPD_PROFILE_ACTIVATION_REASON_PROGRAM_HOLD, NULL);
mask |= PROP_ACTIVE_PROFILE;
}
}
@@ -572,7 +578,7 @@ hold_profile (PpdApp *data,
PpdProfile target_profile = effective_hold_profile (data);
if (target_profile != PPD_PROFILE_UNSET &&
target_profile != data->active_profile) {
- activate_target_profile (data, target_profile, PPD_PROFILE_ACTIVATION_REASON_PROGRAM_HOLD);
+ activate_target_profile (data, target_profile, PPD_PROFILE_ACTIVATION_REASON_PROGRAM_HOLD, NULL);
mask |= PROP_ACTIVE_PROFILE;
}
}
@@ -867,7 +873,7 @@ start_profile_drivers (PpdApp *data)
/* Set initial state either from configuration, or using the currently selected profile */
apply_configuration (data);
- activate_target_profile (data, data->active_profile, PPD_PROFILE_ACTIVATION_REASON_RESET);
+ activate_target_profile (data, data->active_profile, PPD_PROFILE_ACTIVATION_REASON_RESET, NULL);
send_dbus_event (data, PROP_ALL);
diff --git a/src/powerprofilesctl.in b/src/powerprofilesctl.in
index 9b5e201..fac2529 100755
--- a/src/powerprofilesctl.in
+++ b/src/powerprofilesctl.in
@@ -98,7 +98,7 @@ def get_proxy():
'/net/hadess/PowerProfiles',
'org.freedesktop.DBus.Properties', None)
except:
- raise SystemError
+ raise
return proxy
def _get():
@@ -107,23 +107,26 @@ def _get():
print(profile)
def _set(profile):
- proxy = get_proxy()
- proxy.Set('(ssv)',
- 'net.hadess.PowerProfiles',
- 'ActiveProfile',
- GLib.Variant.new_string(profile))
+ try:
+ proxy = get_proxy()
+ proxy.Set('(ssv)',
+ 'net.hadess.PowerProfiles',
+ 'ActiveProfile',
+ GLib.Variant.new_string(profile))
+ except:
+ raise
def get_profiles_property(prop):
try:
proxy = get_proxy()
except:
- raise SystemError
+ raise
profiles = None
try:
profiles = proxy.Get('(ss)', 'net.hadess.PowerProfiles', prop)
except:
- raise ReferenceError
+ raise
else:
return profiles
@@ -134,8 +137,7 @@ def _list():
degraded = (reason != '')
active = get_proxy().Get('(ss)', 'net.hadess.PowerProfiles', 'ActiveProfile')
except:
- print("Couldn\'t get Profiles: ", sys.exc_info()[0])
- raise SystemError
+ raise
else:
index = 0
for profile in reversed(profiles):
@@ -152,8 +154,7 @@ def _list_holds():
try:
holds = get_profiles_property('ActiveProfileHolds')
except:
- # print("Couldn\'t get ActiveProfileHolds: ", sys.exc_info()[0])
- raise SystemError
+ raise
else:
index = 0
for hold in holds:
@@ -173,7 +174,7 @@ def _launch(args, profile, appid, reason):
'/net/hadess/PowerProfiles',
'net.hadess.PowerProfiles', None)
except:
- raise SystemError
+ raise
cookie = proxy.HoldProfile('(sss)', profile, reason, appid)
@@ -208,16 +209,32 @@ def main(): # pylint: disable=too-many-branches, disable=too-many-statements
elif command == 'version':
version()
elif command == 'get':
- _get()
+ try:
+ _get()
+ except GLib.Error as error:
+ sys.stderr.write(f'Failed to communicate with power-profiles-daemon: {format(error)}\n')
+ sys.exit(1)
elif command == 'set':
if len(args) != 1:
usage_set()
sys.exit(1)
- _set(args[0])
+ try:
+ _set(args[0])
+ except GLib.Error as error:
+ sys.stderr.write(f'Failed to communicate with power-profiles-daemon: {format(error)}\n')
+ sys.exit(1)
elif command == 'list':
- _list()
+ try:
+ _list()
+ except GLib.Error as error:
+ sys.stderr.write(f'Failed to communicate with power-profiles-daemon: {format(error)}\n')
+ sys.exit(1)
elif command == 'list-holds':
- _list_holds()
+ try:
+ _list_holds()
+ except GLib.Error as error:
+ sys.stderr.write(f'Failed to communicate with power-profiles-daemon: {format(error)}\n')
+ sys.exit(1)
elif command == 'launch':
if len(args) == 0:
sys.exit(0)
@@ -256,7 +273,11 @@ def main(): # pylint: disable=too-many-branches, disable=too-many-statements
reason = 'Running ' + appid
if not profile:
profile = 'performance'
- _launch(args, profile, appid, reason)
+ try:
+ _launch(args, profile, appid, reason)
+ except GLib.Error as error:
+ sys.stderr.write(f'Failed to communicate with power-profiles-daemon: {format(error)}\n')
+ sys.exit(1)
if __name__ == '__main__':
main()
diff --git a/src/ppd-action-trickle-charge.c b/src/ppd-action-trickle-charge.c
index 3c573ca..629f21d 100644
--- a/src/ppd-action-trickle-charge.c
+++ b/src/ppd-action-trickle-charge.c
@@ -54,8 +54,16 @@ set_charge_type (PpdActionTrickleCharge *action,
for (l = devices; l != NULL; l = l->next) {
GUdevDevice *dev = l->data;
+ const char *value;
- if (!g_udev_device_has_sysfs_attr (dev, CHARGE_TYPE_SYSFS_NAME))
+ if (g_strcmp0 (g_udev_device_get_sysfs_attr (dev, "scope"), "Device") != 0)
+ continue;
+
+ value = g_udev_device_get_sysfs_attr_uncached (dev, CHARGE_TYPE_SYSFS_NAME);
+ if (!value)
+ continue;
+
+ if (g_strcmp0 (charge_type, value) == 0)
continue;
ppd_utils_write_sysfs (dev, CHARGE_TYPE_SYSFS_NAME, charge_type, NULL);
diff --git a/src/ppd-driver-intel-pstate.c b/src/ppd-driver-intel-pstate.c
index 5725516..5939d77 100644
--- a/src/ppd-driver-intel-pstate.c
+++ b/src/ppd-driver-intel-pstate.c
@@ -13,7 +13,10 @@
#include "ppd-driver-intel-pstate.h"
#define CPUFREQ_POLICY_DIR "/sys/devices/system/cpu/cpufreq/"
+#define DEFAULT_CPU_FREQ_SCALING_GOV "powersave"
+#define PSTATE_STATUS_PATH "/sys/devices/system/cpu/intel_pstate/status"
#define NO_TURBO_PATH "/sys/devices/system/cpu/intel_pstate/no_turbo"
+#define TURBO_PCT_PATH "/sys/devices/system/cpu/intel_pstate/turbo_pct"
struct _PpdDriverIntelPstate
{
@@ -106,15 +109,44 @@ open_policy_dir (void)
return g_dir_open (dir, 0, NULL);
}
+static gboolean
+has_turbo (void)
+{
+ g_autofree char *turbo_pct_path = NULL;
+ g_autofree char *contents = NULL;
+ gboolean has_turbo = TRUE;
+
+ turbo_pct_path = ppd_utils_get_sysfs_path (TURBO_PCT_PATH);
+ if (g_file_get_contents (turbo_pct_path, &contents, NULL, NULL)) {
+ contents = g_strchomp (contents);
+ if (g_strcmp0 (contents, "0") == 0)
+ has_turbo = FALSE;
+ }
+
+ return has_turbo;
+}
+
static gboolean
ppd_driver_intel_pstate_probe (PpdDriver *driver)
{
PpdDriverIntelPstate *pstate = PPD_DRIVER_INTEL_PSTATE (driver);
g_autoptr(GDir) dir = NULL;
g_autofree char *policy_dir = NULL;
+ g_autofree char *pstate_status_path = NULL;
+ g_autofree char *status = NULL;
const char *dirname;
PpdProbeResult ret = PPD_PROBE_RESULT_FAIL;
+ /* Verify that Intel P-State is running in active mode */
+ pstate_status_path = ppd_utils_get_sysfs_path (PSTATE_STATUS_PATH);
+ if (!g_file_get_contents (pstate_status_path, &status, NULL, NULL))
+ goto out;
+ status = g_strchomp (status);
+ if (g_strcmp0 (status, "active") != 0) {
+ g_debug ("Intel P-State is running in passive mode");
+ goto out;
+ }
+
dir = open_policy_dir ();
if (!dir)
goto out;
@@ -122,6 +154,8 @@ ppd_driver_intel_pstate_probe (PpdDriver *driver)
policy_dir = ppd_utils_get_sysfs_path (CPUFREQ_POLICY_DIR);
while ((dirname = g_dir_read_name (dir)) != NULL) {
g_autofree char *path = NULL;
+ g_autofree char *gov_path = NULL;
+ g_autoptr(GError) error = NULL;
path = g_build_filename (policy_dir,
dirname,
@@ -130,6 +164,16 @@ ppd_driver_intel_pstate_probe (PpdDriver *driver)
if (!g_file_test (path, G_FILE_TEST_EXISTS))
continue;
+ /* Force a scaling_governor where the preference can be written */
+ gov_path = g_build_filename (policy_dir,
+ dirname,
+ "scaling_governor",
+ NULL);
+ if (!ppd_utils_write (gov_path, DEFAULT_CPU_FREQ_SCALING_GOV, &error)) {
+ g_warning ("Could not change scaling governor %s to '%s'", dirname, DEFAULT_CPU_FREQ_SCALING_GOV);
+ continue;
+ }
+
pstate->devices = g_list_prepend (pstate->devices, g_steal_pointer (&path));
ret = PPD_PROBE_RESULT_SUCCESS;
}
@@ -137,14 +181,16 @@ ppd_driver_intel_pstate_probe (PpdDriver *driver)
if (ret != PPD_PROBE_RESULT_SUCCESS)
goto out;
- /* Monitor the first "no_turbo" */
- pstate->no_turbo_path = ppd_utils_get_sysfs_path (NO_TURBO_PATH);
- pstate->no_turbo_mon = monitor_no_turbo_prop (pstate->no_turbo_path);
- if (pstate->no_turbo_mon) {
- g_signal_connect (G_OBJECT (pstate->no_turbo_mon), "changed",
- G_CALLBACK (no_turbo_changed), pstate);
+ if (has_turbo ()) {
+ /* Monitor the first "no_turbo" */
+ pstate->no_turbo_path = ppd_utils_get_sysfs_path (NO_TURBO_PATH);
+ pstate->no_turbo_mon = monitor_no_turbo_prop (pstate->no_turbo_path);
+ if (pstate->no_turbo_mon) {
+ g_signal_connect (G_OBJECT (pstate->no_turbo_mon), "changed",
+ G_CALLBACK (no_turbo_changed), pstate);
+ }
+ update_no_turbo (pstate);
}
- update_no_turbo (pstate);
out:
g_debug ("%s p-state settings",
diff --git a/src/ppd-utils.c b/src/ppd-utils.c
index 553a1e0..89b56e3 100644
--- a/src/ppd-utils.c
+++ b/src/ppd-utils.c
@@ -34,6 +34,8 @@ gboolean ppd_utils_write (const char *filename,
g_return_val_if_fail (filename, FALSE);
g_return_val_if_fail (value, FALSE);
+ g_debug ("Writing '%s' to '%s'", value, filename);
+
sysfsfp = fopen (filename, "w");
if (sysfsfp == NULL) {
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
@@ -41,14 +43,20 @@ gboolean ppd_utils_write (const char *filename,
g_debug ("Could not open for writing '%s'", filename);
return FALSE;
}
+ setbuf(sysfsfp, NULL);
ret = fprintf (sysfsfp, "%s", value);
- if (ret < 0) {
+ if (ret <= 0) {
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
+ "Error writing '%s': %s", filename, g_strerror (errno));
+ g_debug ("Error writing '%s': %s", filename, g_strerror (errno));
+ return FALSE;
+ }
+ if (fclose (sysfsfp) != 0) {
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
- "Error writing '%s'", filename);
- g_debug ("Error writing '%s'", filename);
+ "Error closing '%s': %s", filename, g_strerror (errno));
+ g_debug ("Error closing '%s': %s", filename, g_strerror (errno));
return FALSE;
}
- fclose (sysfsfp);
return TRUE;
}
diff --git a/tests/integration-test.py b/tests/integration-test.py
index 22dc42c..2dd3677 100755
--- a/tests/integration-test.py
+++ b/tests/integration-test.py
@@ -33,20 +33,20 @@ try:
from gi.repository import Gio
except ImportError as e:
sys.stderr.write('Skipping tests, PyGobject not available for Python 3, or missing GI typelibs: %s\n' % str(e))
- sys.exit(0)
+ sys.exit(77)
try:
gi.require_version('UMockdev', '1.0')
from gi.repository import UMockdev
except ImportError:
sys.stderr.write('Skipping tests, umockdev not available (https://github.com/martinpitt/umockdev)\n')
- sys.exit(0)
+ sys.exit(77)
try:
import dbusmock
except ImportError:
sys.stderr.write('Skipping tests, python-dbusmock not available (http://pypi.python.org/pypi/python-dbusmock).\n')
- sys.exit(0)
+ sys.exit(77)
PP = 'net.hadess.PowerProfiles'
@@ -239,6 +239,9 @@ class Tests(dbusmock.DBusTestCase):
def read_sysfs_attr(self, device, attribute):
return self.read_sysfs_file(device + '/' + attribute)
+ def get_mtime(self, device, attribute):
+ return os.path.getmtime(self.testbed.get_root_dir() + '/' + device + '/' + attribute)
+
def read_file(self, path):
with open(path, 'rb') as f:
return f.read()
@@ -363,18 +366,24 @@ class Tests(dbusmock.DBusTestCase):
# Create 2 CPUs with preferences
dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
os.makedirs(dir1)
+ with open(os.path.join(dir1, 'scaling_governor'), 'w') as gov:
+ gov.write('powersave\n')
with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs:
prefs.write("performance\n")
dir2 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy1/")
os.makedirs(dir2)
+ with open(os.path.join(dir2, 'scaling_governor'), 'w') as gov:
+ gov.write('powersave\n')
with open(os.path.join(dir2, "energy_performance_preference"),'w') as prefs:
prefs.write("performance\n")
- # Create no_turbo pref
+ # Create Intel P-State configuration
pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/intel_pstate")
os.makedirs(pstate_dir)
with open(os.path.join(pstate_dir, "no_turbo"),'w') as no_turbo:
no_turbo.write("0\n")
+ with open(os.path.join(pstate_dir, "status"),'w') as status:
+ status.write("active\n")
self.start_daemon()
@@ -421,14 +430,25 @@ class Tests(dbusmock.DBusTestCase):
# Create CPU with preference
dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
os.makedirs(dir1)
+ gov_path = os.path.join(dir1, 'scaling_governor')
+ with open(gov_path, 'w') as gov:
+ gov.write('performance\n')
with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs:
prefs.write("performance\n")
+ pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/intel_pstate")
+ os.makedirs(pstate_dir)
+ with open(os.path.join(pstate_dir, "status"),'w') as status:
+ status.write("active\n")
upowerd, obj_upower = self.spawn_server_template(
'upower', {'DaemonVersion': '0.99', 'OnBattery': False}, stdout=subprocess.PIPE)
self.start_daemon()
+ with open(gov_path, 'rb') as f:
+ contents = f.read()
+ self.assertEqual(contents, b'powersave')
+
profiles = self.get_dbus_property('Profiles')
self.assertEqual(len(profiles), 3)
self.assertEqual(profiles[0]['Driver'], 'intel_pstate')
@@ -446,6 +466,89 @@ class Tests(dbusmock.DBusTestCase):
upowerd.wait()
upowerd.stdout.close()
+ def test_intel_pstate_error(self):
+ '''Intel P-State driver in error state'''
+
+ pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/intel_pstate")
+ os.makedirs(pstate_dir)
+ with open(os.path.join(pstate_dir, "status"),'w') as status:
+ status.write("active\n")
+
+ dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
+ os.makedirs(dir1)
+ with open(os.path.join(dir1, 'scaling_governor'), 'w') as gov:
+ gov.write('powersave\n')
+ pref_path = os.path.join(dir1, "energy_performance_preference")
+ old_umask = os.umask(0o333)
+ with open(pref_path,'w') as prefs:
+ prefs.write("balance_performance\n")
+ os.umask(old_umask)
+ # Make file non-writable to root
+ if os.geteuid() == 0:
+ if not GLib.find_program_in_path('chattr'):
+ os._exit(77)
+ subprocess.check_output(['chattr', '+i', pref_path])
+
+ self.start_daemon()
+
+ self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
+
+ # 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')
+
+ contents = None
+ with open(os.path.join(dir1, "energy_performance_preference"), 'rb') as f:
+ contents = f.read()
+ self.assertEqual(contents, b'balance_performance\n')
+
+ self.stop_daemon()
+
+ if os.geteuid() == 0:
+ subprocess.check_output(['chattr', '-i', pref_path])
+
+ def test_intel_pstate_passive(self):
+ '''Intel P-State in passive mode -> pladeholder'''
+
+ dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
+ os.makedirs(dir1)
+ with open(os.path.join(dir1, 'scaling_governor'), 'w') as gov:
+ gov.write('powersave\n')
+ with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs:
+ prefs.write("performance\n")
+
+ # Create Intel P-State configuration
+ pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/intel_pstate")
+ os.makedirs(pstate_dir)
+ with open(os.path.join(pstate_dir, "no_turbo"),'w') as no_turbo:
+ no_turbo.write("0\n")
+ with open(os.path.join(pstate_dir, "status"),'w') as status:
+ status.write("passive\n")
+
+ self.start_daemon()
+
+ profiles = self.get_dbus_property('Profiles')
+ self.assertEqual(len(profiles), 2)
+ self.assertEqual(profiles[0]['Driver'], 'placeholder')
+ self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced')
+
+ contents = None
+ with open(os.path.join(dir1, "energy_performance_preference"), 'rb') as f:
+ contents = f.read()
+ self.assertEqual(contents, b'performance\n')
+
+ # Set performance mode
+ self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
+ self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver')
+
+ contents = None
+ with open(os.path.join(dir1, "energy_performance_preference"), 'rb') as f:
+ contents = f.read()
+ self.assertEqual(contents, b'performance\n')
+
+ self.stop_daemon()
+
def test_dytc_performance_driver(self):
'''Lenovo DYTC performance driver'''
@@ -498,6 +601,41 @@ class Tests(dbusmock.DBusTestCase):
profiles = self.get_dbus_property('Profiles')
self.assertEqual(len(profiles), 2)
+ def test_trickle_charge_system(self):
+ '''Trickle power_supply charge type'''
+
+ fastcharge = self.testbed.add_device('power_supply', 'bq24190-charger', None,
+ [ 'charge_type', 'Trickle', 'scope', 'System' ],
+ []
+ )
+
+ self.start_daemon()
+
+ self.assertIn('trickle_charge', self.get_dbus_property('Actions'))
+
+ # Verify that charge-type stays untouched
+ self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), b'Trickle')
+
+ self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver'))
+ self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), b'Trickle')
+
+ def test_trickle_charge_mode_no_change(self):
+ '''Trickle power_supply charge type'''
+
+ fastcharge = self.testbed.add_device('power_supply', 'MFi Fastcharge', None,
+ [ 'charge_type', 'Fast', 'scope', 'Device' ],
+ []
+ )
+
+ mtime = self.get_mtime(fastcharge, 'charge_type')
+ self.start_daemon()
+
+ self.assertIn('trickle_charge', self.get_dbus_property('Actions'))
+
+ # Verify that charge-type didn't get touched
+ self.assertEqual(self.read_sysfs_attr(fastcharge, 'charge_type'), b'Fast')
+ self.assertEqual(self.get_mtime(fastcharge, 'charge_type'), mtime)
+
def test_trickle_charge_mode(self):
'''Trickle power_supply charge type'''
@@ -794,6 +932,79 @@ class Tests(dbusmock.DBusTestCase):
self.stop_daemon()
+ def test_intel_pstate_noturbo(self):
+ '''Intel P-State driver (balance)'''
+
+ # Create CPU with preference
+ dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/")
+ os.makedirs(dir1)
+ with open(os.path.join(dir1, 'scaling_governor'), 'w') as gov:
+ gov.write('powersave\n')
+ with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs:
+ prefs.write("performance\n")
+
+ # Create Intel P-State configuration
+ pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/intel_pstate")
+ os.makedirs(pstate_dir)
+ with open(os.path.join(pstate_dir, "no_turbo"),'w') as no_turbo:
+ no_turbo.write("1\n")
+ with open(os.path.join(pstate_dir, "turbo_pct"),'w') as no_turbo:
+ no_turbo.write("0\n")
+ with open(os.path.join(pstate_dir, "status"),'w') as status:
+ status.write("active\n")
+
+ self.start_daemon()
+
+ profiles = self.get_dbus_property('Profiles')
+ self.assertEqual(len(profiles), 3)
+ self.assertEqual(self.get_dbus_property('PerformanceDegraded'), '')
+
+ self.stop_daemon()
+
+ 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')
+
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ subprocess.check_output([tool_path, 'list'],
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
+ self.assertNotIn('Traceback', cm.exception.stderr)
+
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ subprocess.check_output([tool_path, 'get'],
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
+ self.assertNotIn('Traceback', cm.exception.stderr)
+
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ subprocess.check_output([tool_path, 'set', 'not-a-profile'],
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
+ self.assertNotIn('Traceback', cm.exception.stderr)
+
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ subprocess.check_output([tool_path, 'list-holds'],
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
+ self.assertNotIn('Traceback', cm.exception.stderr)
+
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ subprocess.check_output([tool_path, 'launch', '-p', 'power-saver', 'sleep', '1'],
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
+ self.assertNotIn('Traceback', cm.exception.stderr)
+
+ self.start_daemon()
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ subprocess.check_output([tool_path, 'set', 'not-a-profile'],
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
+ self.assertNotIn('Traceback', cm.exception.stderr)
+ self.stop_daemon()
+
#
# Helper methods
#
diff --git a/tests/meson.build b/tests/meson.build
index 21d3152..e51e90f 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -4,7 +4,7 @@ envs.set ('top_srcdir', meson.source_root())
python3 = find_program('python3')
unittest_inspector = find_program('unittest_inspector.py')
-r = run_command(unittest_inspector, files('integration-test.py'))
+r = run_command(unittest_inspector, files('integration-test.py'), check: true)
unit_tests = r.stdout().strip().split('\n')
foreach ut: unit_tests
More information about the Neon-commits
mailing list