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