Set Max TDP of Intel H-series CPU

I am searching for some program which deals with setting the max TDP of the CPU like we do in Intel XTU on Windows. I am able to undervolt the CPU with this project. I can also monitor the TDP of the CPU using this excellent project. I have searched the Internet for any such program but couldn't find one.

EDIT 1:

My system has a Core i7-9750H CPU with max TDP set by OEM at 60 Watts, running on Ubuntu 18.04LTS with kernel 4.18.20-041820-generic.

EDIT 2

I have updated my kernel to 5.3.0-46-generic (signed) and the output of sudo turbostat --Summary --interval 5 --show Avg_MHz,Busy%,Bzy_MHz,IRQ,PkgTmp,PkgWatt,GFXWatt is as follows:

...
cpu0: MSR_RAPL_POWER_UNIT: 0x000a0e03 (0.125000 Watts, 0.000061 Joules, 0.000977 sec.)
cpu0: MSR_PKG_POWER_INFO: 0x00000168 (45 W TDP, RAPL 0 - 0 W, 0.000000 sec.)
cpu0: MSR_PKG_POWER_LIMIT: 0x42835800dd8230 (UNlocked)
cpu0: PKG Limit #1: ENabled (70.000000 Watts, 28.000000 sec, clamp ENabled)
cpu0: PKG Limit #2: ENabled (107.000000 Watts, 0.002441* sec, clamp DISabled)
...

And the output of rdmsr --bitfield 14:0 -d 0x610 is 560. Which means that the max output is 0.125 * 560 = 70 Watts

The output of sudo rdmsr 0x610 is 42835800dd8230.

Could you please elaborate more regarding the calculation @doug-smythies


For your processor, Core i7 9750H, the default TDP is 45 Watts. If your proccessor supports it, you can adjust TDP.

Method 1

For this example a i5-9600K is used. First I use turbostat (linux-tools-common package) to see what TDP is now, and what the scale factor is:
doug@s18:~$ sudo turbostat --Summary --interval 5 --show Avg_MHz,Busy%,Bzy_MHz,IRQ,PkgTmp,PkgWatt,GFXWatt
...
cpu0: MSR_RAPL_POWER_UNIT: 0x000a0e03 (0.125000 Watts, 0.000061 Joules, 0.000977 sec.)
cpu0: MSR_PKG_POWER_INFO: 0x000002f8 (95 W TDP, RAPL 0 - 0 W, 0.000000 sec.)
cpu0: MSR_PKG_POWER_LIMIT: 0x4283e800dd8320 (UNlocked)
cpu0: PKG Limit #1: ENabled (100.000000 Watts, 28.000000 sec, clamp ENabled)
cpu0: PKG Limit #2: ENabled (125.000000 Watts, 0.002441* sec, clamp DISabled)
...

So, we know the scale factor is 0.125 watts, and someone seems to have already adjusted the power limit up to 100 watts from the default 95, but let's check by reading the MSR directly:

root@s18:/home/doug# rdmsr --bitfield 14:0 0x610
320

root@s18:/home/doug# rdmsr --bitfield 14:0 -d 0x610
800

notice that I read the register twice, once in hexidecimal (base 16) and once in decimal (base 10).

And 800 * 0.125 = 100 watts.

Now, say I wanted to make it 50 watts, first read the register again, but keep everything:

root@s18:/home/doug# rdmsr 0x610
4283e800dd8320

and now change the appropriate bit fields (14 to 0 from above). For the least significant 16 bits, we have:

8    3    2    0
1000 0011 0010 0000

take out the 0x320 (800 base 10) and put in 50 / 0.125 = 400 = 0x190:

8    1    9    0
1000 0001 1001 0000

root@s18:/home/doug# wrmsr 0x610 0x4283e800DD8190
root@s18:/home/doug# rdmsr 0x610
4283e800dd8190

And check it with turbostat:

doug@s18:~$ sudo ~/turbostat --Summary --interval 5 --show Avg_MHz,Busy%,Bzy_MHz,IRQ,PkgTmp,PkgWatt,GFXWatt
...
cpu0: MSR_RAPL_POWER_UNIT: 0x000a0e03 (0.125000 Watts, 0.000061 Joules, 0.000977 sec.)
cpu0: MSR_PKG_POWER_INFO: 0x000002f8 (95 W TDP, RAPL 0 - 0 W, 0.000000 sec.)
cpu0: MSR_PKG_POWER_LIMIT: 0x4283e800dd8190 (UNlocked)
cpu0: PKG Limit #1: ENabled (50.000000 Watts, 28.000000 sec, clamp ENabled)
cpu0: PKG Limit #2: ENabled (125.000000 Watts, 0.002441* sec, clamp DISabled)
... And now test it:
Avg_MHz Busy%   Bzy_MHz IRQ     PkgTmp  PkgWatt GFXWatt
0       0.02    921     205     29      1.90    0.00
0       0.03    834     195     29      1.90    0.00
14      0.42    3440    384     29      2.06    0.00
0       0.03    800     196     29      1.90    0.00
0       0.03    812     190     29      1.90    0.00
0       0.03    800     212     29      1.90    0.00  <<< System idle
0       0.03    811     204     29      1.90    0.00
3148    72.23   4358    9875    63      97.48   0.00  <<< Heavy load applied
3612    82.93   4355    11226   65      111.60  0.00  <<< Lots of power being used
3609    82.94   4351    11182   65      111.50  0.00
3120    83.35   3743    11145   45      72.32   0.00
2833    83.58   3389    11141   45      49.79   0.00  <<< Power limited to 50 watts
2838    83.58   3395    11179   45      49.85   0.00
2836    83.58   3393    11191   45      49.89   0.00
2837    83.58   3394    11119   46      49.90   0.00
2839    83.58   3397    11160   46      49.94   0.00
2838    83.58   3395    11148   46      49.91   0.00
2838    83.58   3395    11160   46      49.94   0.00
2838    83.58   3395    11284   46      49.94   0.00
654     19.28   3390    2807    32      12.97   0.00
0       0.03    803     202     32      1.90    0.00
0       0.03    802     172     32      1.90    0.00

Reference: Intel SDM

Method 2

There is actually a much easier way:

Look to determine if this method can be used:

doug@s18:~$ grep . /sys/class/powercap/intel-rapl/intel-rapl:0/*
/sys/class/powercap/intel-rapl/intel-rapl:0/constraint_0_max_power_uw:95000000
/sys/class/powercap/intel-rapl/intel-rapl:0/constraint_0_name:long_term
/sys/class/powercap/intel-rapl/intel-rapl:0/constraint_0_power_limit_uw:100000000
/sys/class/powercap/intel-rapl/intel-rapl:0/constraint_0_time_window_us:27983872
/sys/class/powercap/intel-rapl/intel-rapl:0/constraint_1_max_power_uw:0
/sys/class/powercap/intel-rapl/intel-rapl:0/constraint_1_name:short_term
/sys/class/powercap/intel-rapl/intel-rapl:0/constraint_1_power_limit_uw:125000000
/sys/class/powercap/intel-rapl/intel-rapl:0/constraint_1_time_window_us:2440
grep: /sys/class/powercap/intel-rapl/intel-rapl:0/device: Is a directory
/sys/class/powercap/intel-rapl/intel-rapl:0/enabled:1
/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj:259409601961
grep: /sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:0: Is a directory
grep: /sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:1: Is a directory
grep: /sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:2: Is a directory
/sys/class/powercap/intel-rapl/intel-rapl:0/max_energy_range_uj:262143328850
/sys/class/powercap/intel-rapl/intel-rapl:0/name:package-0
grep: /sys/class/powercap/intel-rapl/intel-rapl:0/power: Is a directory
grep: /sys/class/powercap/intel-rapl/intel-rapl:0/subsystem: Is a directory

Notice the enable line and the current value (which is as it was above):

    /sys/class/powercap/intel-rapl/intel-rapl:0/constraint_0_power_limit_uw:100000000
/sys/class/powercap/intel-rapl/intel-rapl:0/enabled:1

Now change it and check:

doug@s18:~$ echo "93500000" | sudo tee /sys/class/powercap/intel-rapl/intel-rapl:0/constraint_0_power_limit_uw
doug@s18:~$ cat /sys/class/powercap/intel-rapl/intel-rapl:0/constraint_0_power_limit_uw
93500000

And also check with turbostat:

doug@s18:~$ sudo ./turbostat --Summary --interval 5 --show Avg_MHz,Busy%,Bzy_MHz,IRQ,PkgTmp,PkgWatt,GFXWatt
...
cpu0: MSR_PKG_POWER_LIMIT: 0x4203e800dc82ec (UNlocked)
cpu0: PKG Limit #1: ENabled (93.500000 Watts, 28.000000 sec, clamp DISabled)
...

Note that on another computer,even though the processor is an unlocked and the locations shows as root writable, this stuff does not work (either method):

doug@s15:~$ ls -l /sys/class/powercap/intel-rapl/intel-rapl:0/enabled
-rw-r--r-- 1 root root 4096 Apr 26 08:00 /sys/class/powercap/intel-rapl/intel-rapl:0/enabled
doug@s15:~$ echo 1 | sudo tee /sys/class/powercap/intel-rapl/intel-rapl:0/enabled
1
tee: '/sys/class/powercap/intel-rapl/intel-rapl:0/enabled': Function not implemented