Jelajahi Sumber

add power profile-based undervolting (fix #79)

erpalma 6 tahun lalu
induk
melakukan
c7e292e282
3 mengubah file dengan 42 tambahan dan 17 penghapusan
  1. 1 1
      README.md
  2. 13 1
      etc/lenovo_fix.conf
  3. 28 15
      lenovo_fix.py

+ 1 - 1
README.md

@@ -23,7 +23,7 @@ I will keep this list updated.
 I suggest you to use the excellent **[s-tui](https://github.com/amanusk/s-tui)** tool to check and monitor the CPU usage, frequency, power and temperature under load!
 
 ### Undervolt
-The script now also supports **undervolting** the CPU by configuring voltage offsets for CPU, cache, GPU, System Agent and Analog I/O planes. The script will re-apply undervolt on resume from standby and hibernate by listening to DBus signals.
+The script now also supports **undervolting** the CPU by configuring voltage offsets for CPU, cache, GPU, System Agent and Analog I/O planes. The script will re-apply undervolt on resume from standby and hibernate by listening to DBus signals. You can now either use the `UNDERVOLT` key in config to set global values or the `UNDERVOLT.AC` and `UNDERVOLT.BATTERY` keys to selectively set undervolt values for the two power profiles.
 
 ### HWP override (EXPERIMENTAL)
 I have found that under load my CPU was not always hitting max turbo frequency, in particular when using one/two cores only. For instance, when running [prime95](https://www.mersenne.org/download/) (1 core, test #1) my CPU is limited to about 3500 MHz over the theoretical 4000 MHz maximum. The reason is the value for the HWP energy performance [hints](http://manpages.ubuntu.com/manpages/artful/man8/x86_energy_perf_policy.8.html). By default TLP sets this value to `balance_performance` on AC in order to reduce the power consumption/heat in idle. By setting this value to `performance` I was able to reach 3900 MHz in the prime95 single core test, achieving a +400 MHz boost. Since this value forces the CPU to full speed even during idle, a new experimental feature allows to automatically set HWP to performance under load and revert it to balanced when idle. This feature can be enabled (in AC mode *only*) by setting to `True` the `HWP_Mode` parameter in the config file.

+ 13 - 1
etc/lenovo_fix.conf

@@ -40,7 +40,19 @@ HWP_Mode: False
 # Set cTDP to normal=0, down=1 or up=2 (EXPERIMENTAL)
 cTDP: 0
 
-[UNDERVOLT]
+[UNDERVOLT.BATTERY]
+# CPU core voltage offset (mV)
+CORE: 0
+# Integrated GPU voltage offset (mV)
+GPU: 0
+# CPU cache voltage offset (mV)
+CACHE: 0
+# System Agent voltage offset (mV)
+UNCORE: 0
+# Analog I/O voltage offset (mV)
+ANALOGIO: 0
+
+[UNDERVOLT.AC]
 # CPU core voltage offset (mV)
 CORE: 0
 # Integrated GPU voltage offset (mV)

+ 28 - 15
lenovo_fix.py

@@ -23,11 +23,9 @@ from threading import Event, Thread
 from time import time
 
 DEFAULT_SYSFS_POWER_PATH = '/sys/class/power_supply/AC*/online'
-
 VOLTAGE_PLANES = {'CORE': 0, 'GPU': 1, 'CACHE': 2, 'UNCORE': 3, 'ANALOGIO': 4}
-
 TRIP_TEMP_RANGE = [40, 97]
-
+UNDERVOLT_KEYS = ('UNDERVOLT', 'UNDERVOLT.AC', 'UNDERVOLT.BATTERY')
 power = {'source': None, 'method': 'polling'}
 
 platform_info_bits = {
@@ -245,7 +243,9 @@ def calc_undervolt_mv(msr_value):
 
 def undervolt(config):
     for plane in VOLTAGE_PLANES:
-        write_offset_mv = config.getfloat('UNDERVOLT', plane, fallback=0.0)
+        write_offset_mv = config.getfloat(
+            'UNDERVOLT.{:s}'.format(power['source']), plane, fallback=config.getfloat('UNDERVOLT', plane, fallback=0.0)
+        )
         write_value = calc_undervolt_msr(plane, write_offset_mv)
         writemsr(0x150, write_value)
         if args.debug:
@@ -286,16 +286,29 @@ def load_config():
                     )
                 )
 
-    for plane in VOLTAGE_PLANES:
-        value = config.getfloat('UNDERVOLT', plane)
-        valid_value = min(0, value)
-        if value != valid_value:
-            config.set('UNDERVOLT', plane, str(valid_value))
-            print(
-                '[!] Overriding invalid "UNDERVOLT" value in "{:s}" voltage plane: {:.0f} -> {:.0f}'.format(
-                    plane, value, valid_value
-                )
-            )
+    # fix any invalid value (ie. < 0) in the undervolt settings
+    for key in UNDERVOLT_KEYS:
+        for plane in VOLTAGE_PLANES:
+            if key in config:
+                value = config.getfloat(key, plane)
+                valid_value = min(0, value)
+                if value != valid_value:
+                    config.set(key, plane, str(valid_value))
+                    print(
+                        '[!] Overriding invalid "{:s}" value in "{:s}" voltage plane: {:.0f} -> {:.0f}'.format(
+                            key, plane, value, valid_value
+                        )
+                    )
+
+    # handle the case where only one of UNDERVOLT.AC, UNDERVOLT.BATTERY keys exists
+    # by forcing the other key to all zeros (ie. no undervolt)
+    if any(key in config for key in UNDERVOLT_KEYS[1:]):
+        for key in UNDERVOLT_KEYS[1:]:
+            if key not in config:
+                config.add_section(key)
+            for plane in VOLTAGE_PLANES:
+                value = config.getfloat(key, plane, fallback=0.0)
+                config.set(key, plane, str(value))
 
     return config
 
@@ -595,7 +608,7 @@ def main():
     bus = dbus.SystemBus()
 
     # add dbus receiver only if undervolt is enabled in config
-    if any(config.getfloat('UNDERVOLT', plane) != 0 for plane in VOLTAGE_PLANES):
+    if any(config.getfloat(key, plane, fallback=0) != 0 for plane in VOLTAGE_PLANES for key in UNDERVOLT_KEYS):
         bus.add_signal_receiver(
             handle_sleep_callback, 'PrepareForSleep', 'org.freedesktop.login1.Manager', 'org.freedesktop.login1'
         )