Undervolting a Helios 300 Laptop in Linux

I have an Acer Predator Helios 300 laptop. It’s thin, and packs pretty decent hardware, notably an Intel i7-770HQ processor, and NVIDIA GTX 1060 6GB dedicated GPU. Unfortunately, and not surprisingly, the cooling system on this laptop can’t quite keep up with the power the hardware offers.

Since I use Linux primarily, I had to figure out a solution to undervolt the processor. A quick search pulled up this descriptive blog post by Matthew Thode named Undervolting your CPU for fun and profit. The important piece of information from this post was the small Python snippet for calculating the offset, which will be useful a bit later:

format(0xFFE00000&( (round(-110*1.024)&0xFFF) <<21), '08x')

So, how to actually undervolt? I eventually found this GitHub repository by Miha Eleršič which provides instructions. I didn’t want to guess voltage offsets to try to find the best values at the time, and since I was going to re-install my Linux environment anyway, I decided to just roll a quick Windows installation to have access to ThrottleStop. After some prime95, BSoDs, and time later, I was able to learn that a -160 (rounded) voltage offset was the lowest I could go.

In ThrottleStop.ini, the undervolt value -160 is reported to be 0xEB800000. I only undervolted the CPU Core and CPU Cache, and their labels in ThrottleStop.ini were FIVRVoltage00 and FIVRVoltage20 respectively. I figured it would be a good idea to get the FIVRVoltage values for the other controls as well. Analog I/O is 40, Intel GPU is 10, ad System Agent is 30. Referring to the GitHub repository above, it mentions that the index of the Voltage Plane can be figured out from the FIVRVoltage values. The second number after FIVRVoltage isn’t useful here, so the end-result is that CPU Core is 0, Intel GPU is 1, CPU Cache is 2, System Agent is 3, Analog I/O is 4, and it’s assumed that Digital I/O is 5, and these numbers are the voltage plane index. This matches perfectly with the notes on the GitHub repository.

Now to find out how to get a usable value. The above GitHub repository gives a one-liner Python snippet that ideally should provide the correct offset, but unfortunately this gives me an error related to the name mv not being defined. Back to Matthew Thode’s Undervolting your CPU for fun and profit blog post. The Python snippet mentioned there and around the top of this post works fine. As to how I plugged in my values to that snippet, I replaced 0xFFE00000 with the voltage offset I obtained from ThrottleStop.ini, which is 0xEB800000. Next, I looked at -110, and replaced it with -160. So my snippet looked like this:

format(0xEB800000&( (round(-160*1.024)&0xFFF) <<21), '08x')

This gives me the value eb800000. Now I begin to work with the next snippet:


Going by the information provided in the blog post: 80000 is the constant. The number after that is the voltage plane index, which above is 0, or the CPU Core. Next is another constant, 1, and after that is something to read/write, which is also 1. The values after that are the actual voltage offset. The only parts of that value that need changing are the voltage plane index and the actual voltage offset, which provides me the snippets 0x80000011E1800000 and 0x80000211E1800000 which is setting a -160 voltage offset on the voltage planes 0 and 2, or CPU Core and CPU Cache respectively.

Now the final step is to apply this value. This will be applied through writing a MSR register. This requires the program wrmsr, which is provided by the msr-tools package in popular Linux distributions. In-short, the above calculated values are to be written to the 0x150 MSR register. The following commands do just that, first to the CPU Core:

wrmsr '0x150' '0x80000011EB800000'

… and next to the CPU Cache:

wrmsr '0x150' '0x80000211EB800000'

Changes are applied instantly and can persist through reboots as long as a cold boot doesn't occur. Naturally, I'd like this to apply consistently after reboots, so I created the following systemd script:

Description=CPU Core and CPU Cache Undervolt

ExecStart='/usr/sbin/wrmsr' '0x150' '0x80000011EB800000'
ExecStart='/usr/sbin/wrmsr' '0x150' '0x80000211EB800000'


... and set it to run on start.

So now I can enjoy a -160 voltage offset undervolt on my CPU while running Linux. This reduces temperatures, and more importantly, allows my processor cores to remain in Turbo Boost significantly longer without being limited by power and thermal limits. prime95 would kick me out of Turbo Boost within a few seconds without the undervolt. Now, I remain in Turbo Boost clocks the entire time I run prime95.