[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