Merge upstream
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -29,7 +29,7 @@ wheels/
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
#*.spec
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
54
README.md
54
README.md
@@ -7,7 +7,7 @@ On systems where the EC doesn't reset the values (ex: ASUS Zenbook UX430UNR), th
|
||||
|
||||
### Tested hardware
|
||||
Other users have confirmed that the tool is also working for these laptops:
|
||||
- Lenovo T480, T480s, X1C5, X1C6, T580, L480, T470, X280, ThinkPad Anniversary Edition 25, E590 w/ RX 550X, P43s, E480, E580
|
||||
- Lenovo T480, T480s, X1C5, X1C6, T580, L490, L480, T470, X280, ThinkPad Anniversary Edition 25, E590 w/ RX 550X, P43s, E480, E580
|
||||
- Dell XPS 9365, 9370, Latitude 7390 2-in-1
|
||||
- Microsoft Surface Book 2
|
||||
|
||||
@@ -24,7 +24,7 @@ The tool supports **undervolting** the CPU by configuring voltage offsets for CP
|
||||
The tool now supports overriding the **IccMax** by configuring the maximum allowed current for CPU, cache and GPU planes. The tool will re-apply IccMax on resume from standby and hibernate. You can now either use the `ICCMAX` key in config to set global values or the `ICCMAX.AC` and `ICCMAX.BATTERY` keys to selectively set current values for the two power profiles. **NOTE:** the values specified in the config file are the actual current limit of your system, so those are not a offset from the default values as for the undervolt. As such, you should first find your system default values with the `--monitor` command.
|
||||
|
||||
### 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 lenovo_fix config file : https://github.com/erpalma/throttled/blob/master/etc/lenovo_fix.conf#L39 .
|
||||
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 lenovo_fix config file : https://github.com/erpalma/throttled/blob/master/etc/lenovo_fix.conf#L41 .
|
||||
|
||||
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 ;)
|
||||
|
||||
@@ -35,7 +35,16 @@ On a lot of modern CPUs from Intel one can configure the TDP up or down based on
|
||||
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.
|
||||
|
||||
### Writing to MSR and PCI BAR
|
||||
Right now it is mandatory to **disable Secure Boot** (in BIOS) in order to avoid [Kernel Lockdown](https://lwn.net/Articles/706637/). In particular Lockdown restricts access to MSR and PCI BAR (via /dev/mem) which are required by this tool.
|
||||
Some time ago a feature called [Kernel Lockdown](https://lwn.net/Articles/706637/) was added to Linux. Kernel Lockdown automatically enables some security measures when Secure Boot is enabled, among them restricted access to MSR and PCI BAR via /dev/mem, which this tool requires. There are two ways to get around this: You can either disable Secure Boot in your firmware settings, or disable the Kernel Lockdown LSM.
|
||||
|
||||
The LSM can be disabled this way: Check the contents of the file `/sys/kernel/security/lsm` (example contents: `capability,lockdown,yama`). Take the contents of the file, remove `lockdown` and add the rest as a kernel parameter, like this: `lsm=capability,yama`. Reboot and Kernel Lockdown will be disabled!
|
||||
|
||||
As of Linux 5.9, kernel messages will be logged whenever the script writes to MSR registers. These aren't a problem for now, but there's some indication that future kernels may restrict MSR writes from userspace by default. This is being tracked by issue #215. The messages will look something like:
|
||||
```
|
||||
[ 324.833543] msr: Write to unrecognized MSR 0x1a2 by python3
|
||||
Please report to x86@kernel.org
|
||||
```
|
||||
|
||||
Note that some kernels (e.g. [linux-hardened](https://www.archlinux.org/packages/extra/x86_64/linux-hardened/)) will prevent from writing to `/dev/mem` too. Specifically, you need a kernel with `CONFIG_DEVMEM` and `CONFIG_X86_MSR` set.
|
||||
|
||||
### Thermald
|
||||
@@ -63,8 +72,8 @@ sudo rc-service lenovo_fix start
|
||||
### Debian/Ubuntu
|
||||
```
|
||||
sudo apt install git build-essential python3-dev libdbus-glib-1-dev libgirepository1.0-dev libcairo2-dev python3-venv python3-wheel
|
||||
git clone https://github.com/erpalma/lenovo-throttling-fix.git
|
||||
sudo ./lenovo-throttling-fix/install.sh
|
||||
git clone https://github.com/erpalma/throttled.git
|
||||
sudo ./throttled/install.sh
|
||||
```
|
||||
If you own a X1C6 you can also check a tutorial for Ubuntu 18.04 [here](https://mensfeld.pl/2018/05/lenovo-thinkpad-x1-carbon-6th-gen-2018-ubuntu-18-04-tweaks/).
|
||||
|
||||
@@ -90,8 +99,8 @@ sudo systemctl enable --now throttled
|
||||
If you prefer to install from source, you can use the following commands.
|
||||
```
|
||||
sudo dnf install python3-cairo-devel cairo-gobject-devel gobject-introspection-devel dbus-glib-devel python3-devel make libX11-devel
|
||||
git clone https://github.com/erpalma/lenovo-throttling-fix.git
|
||||
sudo ./lenovo-throttling-fix/install.sh
|
||||
git clone https://github.com/erpalma/throttled.git
|
||||
sudo ./throttled/install.sh
|
||||
```
|
||||
Feedback about Fedora installation is welcome.
|
||||
|
||||
@@ -99,8 +108,8 @@ Feedback about Fedora installation is welcome.
|
||||
User *brycecordill* reported that the following dependencies are required for installing in openSUSE, tested on openSUSE 15.0 Leap.
|
||||
```
|
||||
sudo zypper install gcc make python3-devel dbus-1-glib-devel python3-cairo-devel cairo-devel python3-gobject-cairo gobject-introspection-devel
|
||||
git clone https://github.com/erpalma/lenovo-throttling-fix.git
|
||||
sudo ./lenovo-throttling-fix/install.sh
|
||||
git clone https://github.com/erpalma/throttled.git
|
||||
sudo ./throttled/install.sh
|
||||
```
|
||||
|
||||
### Gentoo
|
||||
@@ -112,6 +121,14 @@ systemctl enable throttled.service
|
||||
systemctl start throttled.service
|
||||
```
|
||||
|
||||
### Solus
|
||||
```
|
||||
sudo eopkg it -c system.devel
|
||||
sudo eopkg it git python3-devel dbus-glib-devel python3-cairo-devel libcairo-devel python3-gobject-devel
|
||||
git clone https://github.com/erpalma/throttled.git
|
||||
sudo ./throttled/install.sh
|
||||
```
|
||||
|
||||
### Void
|
||||
|
||||
The installation itself will create a runit service as lenovo_fix, enable it and start it. Before installation, make sure dbus is running `sv up dbus`.
|
||||
@@ -119,9 +136,9 @@ The installation itself will create a runit service as lenovo_fix, enable it and
|
||||
```
|
||||
sudo xbps-install -Sy gcc git python3-devel dbus-glib-devel libgirepository-devel cairo-devel python3-wheel pkg-config make
|
||||
|
||||
git clone https://github.com/erpalma/lenovo-throttling-fix.git
|
||||
git clone https://github.com/erpalma/throttled.git
|
||||
|
||||
sudo ./lenovo-throttling-fix/install.sh
|
||||
sudo ./throttled/install.sh
|
||||
```
|
||||
|
||||
### Uninstall
|
||||
@@ -154,7 +171,7 @@ On Arch you should probably use `pacman -R lenovo-throttling-fix-git` instead.
|
||||
### Update
|
||||
If you update the tool you should manually check your config file for changes or additional features and modify it accordingly. The update process is then as simple as:
|
||||
```
|
||||
cd lenovo-throttling-fix
|
||||
cd throttled
|
||||
git pull
|
||||
sudo ./install.sh
|
||||
sudo systemctl restart lenovo_fix.service
|
||||
@@ -281,5 +298,18 @@ This is an example output:
|
||||
.....
|
||||
```
|
||||
|
||||
## Autoreload
|
||||
Auto reload config on changes (unless it's deleted) can be enabled/disabled in the config
|
||||
|
||||
```
|
||||
[General]
|
||||
Autoreload = True
|
||||
```
|
||||
|
||||
## A word about manufacturer provided tooling
|
||||
Tools provided by your notebook manufacturer like [Dell Power Manager](https://www.dell.com/support/contents/us/en/04/article/product-support/self-support-knowledgebase/software-and-downloads/dell-power-manager) tend to persist their settings to the system board. If you ever had it running under Windows and activated a cool/quiet/silent/saving profile, this setting will still be active when running linux, throttling your system.
|
||||
|
||||
> On my Dell Latitude 5591, not even a BIOS reset to manufacturar default killed the active `Quiet` profile
|
||||
|
||||
## Disclaimer
|
||||
This script overrides the default values set by Lenovo. I'm using it without any problem, but it is still experimental so use it at your own risk.
|
||||
|
||||
2
etc/lenovo_fix.conf
Normal file → Executable file
2
etc/lenovo_fix.conf
Normal file → Executable file
@@ -3,6 +3,8 @@
|
||||
Enabled: True
|
||||
# SYSFS path for checking if the system is running on AC power
|
||||
Sysfs_Power_Path: /sys/class/power_supply/AC*/online
|
||||
# Auto reload config on changes
|
||||
Autoreload: True
|
||||
|
||||
## Settings to apply while connected to Battery power
|
||||
[BATTERY]
|
||||
|
||||
@@ -39,6 +39,7 @@ cp -n requirements.txt lenovo_fix.py mmio.py "$INSTALL_DIR"
|
||||
cd "$INSTALL_DIR"
|
||||
/usr/bin/python3 -m venv venv
|
||||
. venv/bin/activate
|
||||
pip install wheel
|
||||
pip install -r requirements.txt
|
||||
|
||||
if pidof systemd 2>&1 1>/dev/null; then
|
||||
|
||||
@@ -30,7 +30,8 @@ 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_PERFORMANCE_VALUE = 0x20
|
||||
HWP_DEFAULT_VALUE = 0x80
|
||||
HWP_INTERVAL = 60
|
||||
|
||||
|
||||
@@ -77,7 +78,7 @@ supported_cpus = {
|
||||
'Kaby Lake (R)': (0x8E, 0x9E),
|
||||
'Coffee Lake': (0x9E,),
|
||||
'Cannon Lake': (0x66,),
|
||||
'Comet Lake': (0xA6,),
|
||||
'Comet Lake': (0xA5, 0xA6),
|
||||
}
|
||||
|
||||
|
||||
@@ -517,16 +518,17 @@ def calc_reg_values(platform_info, config):
|
||||
return regs
|
||||
|
||||
|
||||
def set_hwp():
|
||||
def set_hwp(performance_mode):
|
||||
# set HWP energy performance preference
|
||||
cur_val = readmsr(0x774, cpu=0)
|
||||
new_val = (cur_val & 0xFFFFFFFF00FFFFFF) | (HWP_VALUE << 24)
|
||||
hwp_mode = HWP_PERFORMANCE_VALUE if performance_mode else HWP_DEFAULT_VALUE
|
||||
new_val = (cur_val & 0xFFFFFFFF00FFFFFF) | (hwp_mode << 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
|
||||
log('[D] HWP - write "{:#02x}" - read "{:#02x}" - match {}'.format(HWP_VALUE, read_value, match))
|
||||
match = OK if hwp_mode == read_value else ERR
|
||||
log('[D] HWP - write "{:#02x}" - read "{:#02x}" - match {}'.format(hwp_mode, read_value, match))
|
||||
|
||||
|
||||
def set_disable_bdprochot():
|
||||
@@ -541,6 +543,23 @@ def set_disable_bdprochot():
|
||||
log('[D] BDPROCHOT - write "{:#02x}" - read "{:#02x}" - match {}'.format(0, read_value, match))
|
||||
|
||||
|
||||
def get_config_write_time():
|
||||
try:
|
||||
return os.stat(args.config).st_mtime
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
|
||||
def reload_config():
|
||||
config = load_config()
|
||||
regs = calc_reg_values(get_cpu_platform_info(), config)
|
||||
undervolt(config)
|
||||
set_icc_max(config)
|
||||
set_hwp(config.getboolean('AC', 'HWP_Mode', fallback=False))
|
||||
log('[I] Reloading changes.')
|
||||
return config, regs
|
||||
|
||||
|
||||
def power_thread(config, regs, exit_event):
|
||||
try:
|
||||
mchbar_mmio = MMIO(0xFED159A0, 8)
|
||||
@@ -550,6 +569,8 @@ def power_thread(config, regs, exit_event):
|
||||
mchbar_mmio = None
|
||||
|
||||
next_hwp_write = 0
|
||||
last_config_write_time = get_config_write_time() \
|
||||
if config.getboolean('GENERAL', 'Autoreload', fallback=False) else None
|
||||
while not exit_event.is_set():
|
||||
# log thermal status
|
||||
if args.debug:
|
||||
@@ -558,6 +579,13 @@ def power_thread(config, regs, exit_event):
|
||||
for key, value in core_thermal_status.items():
|
||||
log('[D] core {} thermal status: {} = {}'.format(index, key.replace("_", " "), value))
|
||||
|
||||
# Reload config on changes (unless it's deleted)
|
||||
if config.getboolean('GENERAL', 'Autoreload', fallback=False):
|
||||
config_write_time = get_config_write_time()
|
||||
if config_write_time and last_config_write_time != config_write_time:
|
||||
last_config_write_time = config_write_time
|
||||
config, regs = reload_config()
|
||||
|
||||
# switch back to sysfs polling
|
||||
if power['method'] == 'polling':
|
||||
power['source'] = 'BATTERY' if is_on_battery(config) else 'AC'
|
||||
@@ -628,7 +656,7 @@ def power_thread(config, regs, exit_event):
|
||||
or (power['method'] == 'polling' and not is_on_battery(config))
|
||||
)
|
||||
):
|
||||
set_hwp()
|
||||
set_hwp(enable_hwp_mode)
|
||||
next_hwp_write = time() + HWP_INTERVAL
|
||||
|
||||
else:
|
||||
@@ -791,14 +819,15 @@ def main():
|
||||
log('[I] Throttled is disabled in config file... Quitting. :(')
|
||||
return
|
||||
|
||||
undervolt(config)
|
||||
set_icc_max(config)
|
||||
set_hwp(config.getboolean('AC', 'HWP_Mode', fallback=False))
|
||||
|
||||
exit_event = Event()
|
||||
thread = Thread(target=power_thread, args=(config, regs, exit_event))
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
undervolt(config)
|
||||
set_icc_max(config)
|
||||
|
||||
# handle dbus events for applying undervolt/IccMax on resume from sleep/hybernate
|
||||
def handle_sleep_callback(sleeping):
|
||||
if not sleeping:
|
||||
|
||||
0
openrc/lenovo_fix
Normal file → Executable file
0
openrc/lenovo_fix
Normal file → Executable file
0
package/PKGBUILD
Normal file → Executable file
0
package/PKGBUILD
Normal file → Executable file
@@ -1,3 +1,3 @@
|
||||
configparser==3.8.1
|
||||
dbus-python==1.2.8
|
||||
PyGObject==3.32.2
|
||||
configparser==5.0.0
|
||||
dbus-python==1.2.16
|
||||
PyGObject==3.38.0
|
||||
|
||||
6
systemd/lenovo_fix.service
Normal file → Executable file
6
systemd/lenovo_fix.service
Normal file → Executable file
@@ -1,13 +1,11 @@
|
||||
[Unit]
|
||||
Description=Stop Intel throttling
|
||||
Description=Stop Intel throttling
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/throttled --conf /etc/throttled.conf
|
||||
ExecStart=/opt/lenovo_fix/venv/bin/python3 /opt/lenovo_fix/lenovo_fix.py
|
||||
# Setting PYTHONUNBUFFERED is necessary to see the output of this service in the journal
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
2
throttled.spec
Normal file → Executable file
2
throttled.spec
Normal file → Executable file
@@ -2,7 +2,7 @@
|
||||
%define debug_package %{nil}
|
||||
|
||||
Name: throttled
|
||||
Version: 0.7
|
||||
Version: 0.8
|
||||
Release: 2
|
||||
Summary: Workaround for Intel throttling issues in Linux
|
||||
License: MIT
|
||||
|
||||
Reference in New Issue
Block a user