new HWP handling (see #121)

This commit is contained in:
erpalma
2019-06-10 12:13:26 +02:00
parent 952128dc21
commit 95aa5b1e02

View File

@@ -2,8 +2,6 @@
from __future__ import print_function
import argparse
import configparser
import dbus
import glob
import gzip
import os
@@ -11,17 +9,19 @@ import re
import struct
import subprocess
import sys
from collections import defaultdict
from dbus.mainloop.glib import DBusGMainLoop
from errno import EACCES, EPERM
from gi.repository import GLib
from mmio import MMIO, MMIOError
from multiprocessing import cpu_count
from platform import uname
from threading import Event, Thread
from time import time
import configparser
import dbus
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
from mmio import MMIO, MMIOError
DEFAULT_SYSFS_POWER_PATH = '/sys/class/power_supply/AC*/online'
VOLTAGE_PLANES = {'CORE': 0, 'GPU': 1, 'CACHE': 2, 'UNCORE': 3, 'ANALOGIO': 4}
CURRENT_PLANES = {'CORE': 0, 'GPU': 1, 'CACHE': 2}
@@ -29,6 +29,9 @@ TRIP_TEMP_RANGE = [40, 97]
UNDERVOLT_KEYS = ('UNDERVOLT', 'UNDERVOLT.AC', 'UNDERVOLT.BATTERY')
ICCMAX_KEYS = ('ICCMAX', 'ICCMAX.AC', 'ICCMAX.BATTERY')
power = {'source': None, 'method': 'polling'}
HWP_VALUE = 0x20
HWP_INTERVAL = 60
platform_info_bits = {
'maximum_non_turbo_ratio': [8, 15],
@@ -150,21 +153,6 @@ def readmsr(msr, from_bit=0, to_bit=63, cpu=None, flatten=False):
raise e
def cpu_usage_pct(exit_event, interval=1.0):
last_idle = last_total = 0
for i in range(2):
with open('/proc/stat') as f:
fields = [float(column) for column in f.readline().strip().split()[1:]]
idle, total = fields[3], sum(fields)
idle_delta, total_delta = idle - last_idle, total - last_total
last_idle, last_total = idle, total
if i == 0:
exit_event.wait(interval)
return 100.0 * (1.0 - idle_delta / total_delta)
def get_value_for_bits(val, from_bit=0, to_bit=63):
mask = sum(2 ** x for x in range(from_bit, to_bit + 1))
return (val & mask) >> from_bit
@@ -501,20 +489,16 @@ def calc_reg_values(platform_info, config):
return regs
def set_hwp(pref):
# set HWP energy performance hints
assert pref in ('performance', 'balance_performance', 'default', 'balance_power', 'power')
CPUs = [
'/sys/devices/system/cpu/cpu{:d}/cpufreq/energy_performance_preference'.format(x) for x in range(cpu_count())
]
for i, c in enumerate(CPUs):
with open(c, 'wb') as f:
f.write(pref.encode())
if args.debug:
with open(c) as f:
read_value = f.read().strip()
match = OK if pref == read_value else ERR
print('[D] HWP for cpu{:d} - write "{:s}" - read "{:s}" - match {}'.format(i, pref, read_value, match))
def set_hwp():
# set HWP energy performance preference
cur_val = readmsr(0x774, cpu=0)
new_val = (cur_val & 0xFFFFFFFF00FFFFFF) | (HWP_VALUE << 24)
writemsr(0x774, new_val)
if args.debug:
read_value = readmsr(0x774, from_bit=24, to_bit=31)[0]
match = OK if HWP_VALUE == read_value else ERR
print('[D] HWP - write "{:#02x}" - read "{:#02x}" - match {}'.format(HWP_VALUE, read_value, match))
def power_thread(config, regs, exit_event):
@@ -523,6 +507,7 @@ def power_thread(config, regs, exit_event):
except MMIOError:
fatal('Unable to open /dev/mem. Try to disable Secure Boot.')
next_hwp_write = 0
while not exit_event.is_set():
# print thermal status
if args.debug:
@@ -586,15 +571,18 @@ def power_thread(config, regs, exit_event):
wait_t = config.getfloat(power['source'], 'Update_Rate_s')
enable_hwp_mode = config.getboolean('AC', 'HWP_Mode', fallback=False)
if power['source'] == 'AC' and enable_hwp_mode:
cpu_usage = cpu_usage_pct(exit_event, interval=wait_t)
# set full performance mode only when load is greater than this threshold (~ at least 1 core full speed)
performance_mode = cpu_usage > 100.0 / (cpu_count() * 1.25)
# check again if we are on AC, since in the meantime we might have switched to BATTERY
if (power['method'] == 'dbus' and power['source'] == 'AC') or (
power['method'] == 'polling' and not is_on_battery(config)
):
set_hwp('performance' if performance_mode else 'balance_performance')
# set HWP less frequently. Just to be safe since (e.g.) TLP might reset this value
if (
enable_hwp_mode
and next_hwp_write <= time()
and (
(power['method'] == 'dbus' and power['source'] == 'AC')
or (power['method'] == 'polling' and not is_on_battery(config))
)
):
set_hwp()
next_hwp_write = time() + HWP_INTERVAL
else:
exit_event.wait(wait_t)