Sign in to follow this  
kakashisensei

Need advice for making plugin for CPU speed control (similiar to throttlestop)

5 posts in this topic Last Reply

Recommended Posts

Posted (edited)

I have a very uncommon issue, but it may pertain to others here. I am running unraid on an old sandybridge i7 laptop, using an engineering sample cpu. Because of the ES cpu, the laptop bios doesn't pass over the correct turbo boost ratios to OS. The cpu will not go past 2ghz under full utilization (its base frequency is 2.4ghz and turbo up to 3.5ghz). In unraid, cpu will not go past 2ghz and that carries over to all virtual environments. I have looked at Tips and Tweaks to control governance of p_state driver and turbo speed on/off, but that doesn't resolve the issue.This severely limits performance I need for plex transcoding and a windows VM I use for tv streaming.

 

In bare metal windows, I can use throttlestop to correct this. Having looked into how throttlestop works, I see that it is simply writing to the CPU MSR (model specific register) to a specific register for requested speed with the hex value for cpu speed multiplier (in my case 0x23 for 35x). This causes the cpu to behave properly and turbo boost correctly, and it still drops down to idle states as well. Throttlestop does not have a linux version, and the creator won't make one or release the source. But he has explained what throttlestop is doing with CPU MSR to do the things the application does.

 

I want to try my hand at creating a unraid plugin with similar basic throttlestop functionality. First would just be to control cpu speed by setting the requested cpu multiplier ratio. There is a utility that can read / write to CPU MSR in linux called msr tools (https://01.org/msr-tools). This plugin would basically need to keep spam writing to the CPU MSR. It is not simply write once at boot and forget. Another potentially useful function would be user controlled idle at % utilization. There should be a MSR for cpu utilization % (C0 state) and can change the requested speed based off that, forcing low power 800mhz state during low utilization.

 

Unfortunately, I am a noob with linux and have very limited scripting experience. But I want to try my hand at this and see how far I can get. I was hoping to use an existing plugin as a basis to learn. Something like a plugin that uses third party utilities that constantly monitors and write to memory register or change variable setting. One that I am looking at now is Tips and Tweaks, but unsure if it is constantly writing. I am not even sure exactly how to get MSR tools working in unraid yet. Since apt-get install packages doesnt work in slackware, I assume I would need to make a slackware pkg from the source.

 

Can anyone help me get pointed in the right direction? Much appreciated!

 

 

Edited by kakashisensei

Share this post


Link to post

Update

I resolved the issue on an ubuntu test platform and migrating that over to unraid. It was a real easy fix as I only need to write to one cpu register (0x19A) to turn off clock control modulation. I do not need to keep writing to the register for requested cpu multiplier (0x199). Apparently the intel pstate driver for linux works correctly with my cpu, it just needed clock control modulation off. This is unlike windows, where it needs to keep writing to that register. Now I am getting max turbo boost speeds. This is the cpu speed readout with a VM running cpu benches.

 

 

cpufix.png

Share this post


Link to post
Posted (edited)

Since it was an easy fix, I won't try to make a plugin for cpu throttle and frequency control. But I will share all my findings for anyone willing to try.

 

- The necessary utility is MSR Tools, as that allows to read and write to CPU MSR. Since there is no installer package on unraid, I copied the driver files over from the pkg install on ubuntu. Those are "rdmsr" and "wrmsr" in /usr/sbin. These can only be used by root. You also need to do modprobe msr to generate msr files for your cpu. These will make msr files for each of your cpu cores located at /dev/cpu/X/msr where X is a folder for each cpu core number.

 

- Once you have that working, you can use rdmsr and wrmsr commands to the CPU MSR. Rdmsr is for reading, Wrmsr is for writing. All CPU MSR registers contain 2 8-bit data strings. But with MSR Tools, only 0x198 returns the full two strings when using the read function. The important registers are:

 

0x198   

Returns current cpu speed multipler. It appears as 2 8-bit strings concatenated. The important data is the hex value of the multiplier at the end of the 2nd string. This is read only.

Example:

rdmsr -pN 0x198    (where N is the cpu core number)

returns something like 0000292700002800  (where the 28 is hex value of the multiplier, in this case 40x in decimal)

 

0x199  

MSR for the requested cpu speed multiplier. This is the important register to force the cpu to change to the requested speed.

Example:

wrmsr -p0 0x199 0xAA   (writing to cpu core 0, where AA is the hex value for the decimal ratio you want to force)

 

0x19A

This is the MSR for clock modulation being on or off. This was the one causing issues for me. At bootup, the value is 0x1A. I had to write 0x00 to turn it off and that fixed the whole issue for me.

Example:

wrmsr -p0 0x19A 0x00 

 

0x1AD

This is the MSR for the max turbo ratio. Not sure if it is changeable, it was always the same for me. Might only be changeable for Extreme intel cpus. The hex value for the multiplier ratio was at the beginning of the second 8-bit string for me.

 

0x194

This is for voltage control. I do not know much about this as I didn't want to mess with it. There are resources if you look up Throttlestop discussions about it. Take a look at the link in the next post for the original script with voltage control.

 

0x1AC

This is voltage for turbo I think. Don't know much either.

 

 

I tested writing 0x199 with a fixed ratio in a while loop, but that didnt seem to work. My guess is that it is fighting with the p state driver. You may need to disable that and have no frequency scaling driver enabled. Also that while loop created a constant 15-30% cpu utilization. In the link below, the original script had writing 0x19A to 0x00 in a infinite loop, but I didn't need to do that for my setup.

 

There should be a register with C0%. Not sure which one. This is the C0 state utilization. If the % is low, the cpu is barely being utilized. This could be used as a user defined threshold for forcing low power frequency state to reduce heat and energy consumption. This is how Throttlestop does its power save feature.

 

 

 

 

 

 

Edited by kakashisensei

Share this post


Link to post

I made a script to change the 0x19A register to 0x00 at startup. It was modified from the script here https://forums.gentoo.org/viewtopic-t-914154-start-25.html

It has alot more on voltage changing and disabling the cpu frequency scaling driver. Although I think its for the acpi freq driver and not the p state driver.

#!/bin/bash

setclockmod() {
   for i in $cpulist; do
       wrmsr -p$i 0x19A 0x00
   done
}

loadchecks() {
   [[ $(id -u) = "0" ]] || { echo "Not running as root, aborting!"; exit 1; }
   modprobe msr
   test -c /dev/cpu/0/msr || {  echo "msr module not loaded, aborting!"; exit 1; }
   which wrmsr &>/dev/null || { echo "Could not find wrmsr, aborting!"; exit 1; }
   which rdmsr &>/dev/null || { echo "Could not find rdmsr, aborting!"; exit 1; }

   cpulist=$(grep processor /proc/cpuinfo | awk '{print $3}')
}

loadchecks
setclockmod

exit

 

However, I had issues where the script, rdmsr, and wrmsr files kept getting deleted from unraid boot drive after each bootup. I had the script in /usr/local/bin and the driver files are in /usr/sbin. Does anyone know how to stop that?

 

Instead I worked around by placing the script and driver files in a user share, and used the User Scripts plugin to copy those files to the appropriate locations, chmod +x , and run the main script at the startup of the array.

Share this post


Link to post
37 minutes ago, kakashisensei said:

However, I had issues where the script, rdmsr, and wrmsr files kept getting deleted from unraid boot drive after each bootup. I had the script in /usr/local/bin and the driver files are in /usr/sbin. Does anyone know how to stop that?

The unraid boot drive is mounted at /boot, the individual disks are mounted at /mnt/diskX.

 

Unraid runs from RAM, the boot drive just holds the compressed OS and loads it to RAM at boot time. Any modifications to the OS need to be done with scripts pointing to persistent locations that run each boot, as you found out.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  


Copyright © 2005-2018 Lime Technology, Inc.
unRAID® is a registered trademark of Lime Technology, Inc.