Merge pull request #30 from DEvil0000/improvement/configure_cTDP

Improvement/configure cTDP
This commit is contained in:
Francesco Palmarini
2018-08-13 13:38:01 -07:00
committed by GitHub
3 changed files with 59 additions and 4 deletions

View File

@@ -26,6 +26,9 @@ I have found that under load my CPU was not always hitting max turbo frequency,
I have run **[Geekbench 4](https://browser.geekbench.com/v4/cpu/8656840)** and now I can get a score of 5391/17265! On balance_performance I can reach only 4672/16129, so **15% improvement** in single core and 7% in multicore, not bad ;) I have run **[Geekbench 4](https://browser.geekbench.com/v4/cpu/8656840)** and now I can get a score of 5391/17265! On balance_performance I can reach only 4672/16129, so **15% improvement** in single core and 7% in multicore, not bad ;)
### setting cTDP (EXPERIMENTAL)
On a lot of modern CPUs from Intel one can configure the TDP up or down based on predefined profiles. This is what this option does. For a i7-8650U normal would be 15W, up profile is setting it to 25W and down to 10W. You can lookup the values of your CPU at the Intel product website.
## Requirements ## Requirements
A stripped down version of the python module `python-periphery` is now built-in and it is used for accessing the MCHBAR register by memory mapped I/O. You also need `dbus` and `gobject` python bindings for listening to dbus signals on resume from sleep/hibernate. A stripped down version of the python module `python-periphery` is now built-in and it is used for accessing the MCHBAR register by memory mapped I/O. You also need `dbus` and `gobject` python bindings for listening to dbus signals on resume from sleep/hibernate.

View File

@@ -15,6 +15,8 @@ PL2_Tdp_W: 44
PL2_Duration_S: 0.002 PL2_Duration_S: 0.002
# Max allowed temperature before throttling # Max allowed temperature before throttling
Trip_Temp_C: 85 Trip_Temp_C: 85
# Set cTDP to normal=0, down=1 or up=2 (EXPERIMENTAL)
cTDP: 0
## Settings to apply while connected to AC power ## Settings to apply while connected to AC power
[AC] [AC]
@@ -32,6 +34,8 @@ PL2_Duration_S: 0.002
Trip_Temp_C: 95 Trip_Temp_C: 95
# Set HWP energy performance hints to 'performance' on high load (EXPERIMENTAL) # Set HWP energy performance hints to 'performance' on high load (EXPERIMENTAL)
HWP_Mode: False HWP_Mode: False
# Set cTDP to normal=0, down=1 or up=2 (EXPERIMENTAL)
cTDP: 0
[UNDERVOLT] [UNDERVOLT]
# CPU core voltage offset (mV) # CPU core voltage offset (mV)

View File

@@ -33,6 +33,7 @@ VOLTAGE_PLANES = {
} }
TRIP_TEMP_RANGE = (40, 97) TRIP_TEMP_RANGE = (40, 97)
C_TDP_RANGE = (0, 2)
power = {'source': None, 'method': 'polling'} power = {'source': None, 'method': 'polling'}
@@ -58,6 +59,33 @@ def writemsr(msr, val):
else: else:
raise e raise e
# returns the value between from_bit and to_bit as unsigned long
def readmsr(msr, from_bit = 0, to_bit = 63):
if from_bit > to_bit:
print('wrong readmsr bit params')
sys.exit(1)
n = ['/dev/cpu/{:d}/msr'.format(x) for x in range(cpu_count())]
if not os.path.exists(n[0]):
try:
subprocess.check_call(('modprobe', 'msr'))
except subprocess.CalledProcessError:
print('[E] Unable to load the msr module.')
sys.exit(1)
try:
for c in n:
f = os.open(c, os.O_RDONLY)
os.lseek(f, msr, os.SEEK_SET)
val = struct.unpack('Q', os.read(f, 8))[0]
os.close(f)
extractor = int(''.join(["0"]*(63-to_bit) + ["1"]*(to_bit+1-from_bit) + ["0"]*from_bit), 2)
return (val & extractor) >> from_bit
except (IOError, OSError) as e:
if e.errno == EPERM or e.errno == EACCES:
print('[E] Unable to read from MSR. Try to disable Secure Boot.')
sys.exit(1)
else:
raise e
def is_on_battery(): def is_on_battery():
with open(SYSFS_POWER_PATH) as f: with open(SYSFS_POWER_PATH) as f:
@@ -65,9 +93,11 @@ def is_on_battery():
def calc_time_window_vars(t): def calc_time_window_vars(t):
# 0.000977 is the time unit of this CPU
time_unit = 1.0/2**readmsr(0x606, 16, 19)
for Y in range(2**5): for Y in range(2**5):
for Z in range(2**2): for Z in range(2**2):
if t <= (2**Y) * (1. + Z / 4.) * 0.000977: if t <= (2**Y) * (1. + Z / 4.) * time_unit:
return (Y, Z) return (Y, Z)
raise ValueError('Unable to find a good combination!') raise ValueError('Unable to find a good combination!')
@@ -126,17 +156,26 @@ def calc_reg_values(config):
regs[power_source]['MSR_TEMPERATURE_TARGET'] = trip_offset << 24 regs[power_source]['MSR_TEMPERATURE_TARGET'] = trip_offset << 24
# 0.125 is the power unit of this CPU # 0.125 is the power unit of this CPU
PL1 = int(round(config.getfloat(power_source, 'PL1_Tdp_W') / 0.125)) power_unit = 1.0/2**readmsr(0x606, 0, 3)
PL1 = int(round(config.getfloat(power_source, 'PL1_Tdp_W') / power_unit))
Y, Z = calc_time_window_vars(config.getfloat(power_source, 'PL1_Duration_s')) Y, Z = calc_time_window_vars(config.getfloat(power_source, 'PL1_Duration_s'))
TW1 = Y | (Z << 5) TW1 = Y | (Z << 5)
PL2 = int(round(config.getfloat(power_source, 'PL2_Tdp_W') / 0.125)) PL2 = int(round(config.getfloat(power_source, 'PL2_Tdp_W') / power_unit))
Y, Z = calc_time_window_vars(config.getfloat(power_source, 'PL2_Duration_s')) Y, Z = calc_time_window_vars(config.getfloat(power_source, 'PL2_Duration_s'))
TW2 = Y | (Z << 5) TW2 = Y | (Z << 5)
regs[power_source]['MSR_PKG_POWER_LIMIT'] = PL1 | (1 << 15) | (TW1 << 17) | (PL2 << 32) | (1 << 47) | ( regs[power_source]['MSR_PKG_POWER_LIMIT'] = PL1 | (1 << 15) | (TW1 << 17) | (PL2 << 32) | (1 << 47) | (
TW2 << 49) TW2 << 49)
# cTDP
try:
c_tdp_target_value = int(config.getfloat(power_source, 'cTDP'))
valid_c_tdp_target_value = min(C_TDP_RANGE[1], max(C_TDP_RANGE[0], c_tdp_target_value))
regs[power_source]['MSR_CONFIG_TDP_CONTROL'] = valid_c_tdp_target_value
except configparser.NoOptionError:
pass
return regs return regs
@@ -162,8 +201,17 @@ def power_thread(config, regs, exit_event):
power['source'] = 'BATTERY' if is_on_battery() else 'AC' power['source'] = 'BATTERY' if is_on_battery() else 'AC'
# set temperature trip point # set temperature trip point
if readmsr(0xce, 30, 30) != 1:
print("setting temperature target is not supported by this CPU")
else:
writemsr(0x1a2, regs[power['source']]['MSR_TEMPERATURE_TARGET']) writemsr(0x1a2, regs[power['source']]['MSR_TEMPERATURE_TARGET'])
# set cTDP
if readmsr(0xce, 33, 34) < 2:
print("cTDP setting not supported by this cpu")
else:
writemsr(0x64b, regs[power['source']]['MSR_CONFIG_TDP_CONTROL'])
# set PL1/2 on MSR # set PL1/2 on MSR
writemsr(0x610, regs[power['source']]['MSR_PKG_POWER_LIMIT']) writemsr(0x610, regs[power['source']]['MSR_PKG_POWER_LIMIT'])
# set MCHBAR register to the same PL1/2 values # set MCHBAR register to the same PL1/2 values