Discussion Custom CPPC and other thoughts

Soulkeeper

Diamond Member
Nov 23, 2001
6,712
142
106
I recently modified my linux kernel to use custom CPPC numbers for each core, and use intel's preferred core scheduler code because AMD hasn't implemented that yet.
I wrote a program to stress each core with affinity and measure MHz and power usage and generate my own CPPC numbers.

The factory numbers reported to the os essentially become worthless once you modify your curve offsets.

Code:
CPU:0 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.100000 max_avg: 5.066667 avg_highest: 4.894227 avg_avg: 4.891066 w_avg: 16.299639
CPU:1 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.025000 max_avg: 5.008333 avg_highest: 4.842415 avg_avg: 4.841027 w_avg: 13.917639
CPU:2 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.000000 max_avg: 5.000000 avg_highest: 4.833374 avg_avg: 4.832275 w_avg: 13.477283
CPU:3 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.050000 max_avg: 5.033333 avg_highest: 4.880210 avg_avg: 4.876766 w_avg: 14.034264
CPU:4 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.150000 max_avg: 5.133333 avg_highest: 5.002861 avg_avg: 4.998986 w_avg: 16.302015
CPU:5 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.000000 max_avg: 5.000000 avg_highest: 4.830933 avg_avg: 4.824229 w_avg: 13.229335
CPU:6 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.025000 max_avg: 5.025000 avg_highest: 4.903685 avg_avg: 4.900039 w_avg: 14.734373
CPU:7 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.025000 max_avg: 5.025000 avg_highest: 4.887772 avg_avg: 4.884295 w_avg: 14.408365
CPU:8 samples: 3 min_lowest: 2.880000 min_avg: 3.360000 max_highest: 5.100000 max_avg: 5.050000 avg_highest: 4.911133 avg_avg: 4.903595 w_avg: 13.478444
CPU:9 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.000000 max_avg: 5.000000 avg_highest: 4.857170 avg_avg: 4.849847 w_avg: 13.423134
CPU:10 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 4.975000 max_avg: 4.975000 avg_highest: 4.785836 avg_avg: 4.780011 w_avg: 14.585408
CPU:11 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 4.975000 max_avg: 4.975000 avg_highest: 4.830589 avg_avg: 4.824020 w_avg: 14.657932
CPU:12 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.025000 max_avg: 5.016667 avg_highest: 4.840999 avg_avg: 4.838628 w_avg: 12.877928
CPU:13 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.000000 max_avg: 5.000000 avg_highest: 4.868457 avg_avg: 4.862312 w_avg: 13.372452
CPU:14 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.125000 max_avg: 5.091667 avg_highest: 4.934036 avg_avg: 4.931505 w_avg: 13.465855
CPU:15 samples: 3 min_lowest: 3.600000 min_avg: 3.600000 max_highest: 5.025000 max_avg: 5.008333 avg_highest: 4.839930 avg_avg: 4.838426 w_avg: 13.173962
RANKED:
freq_min_lowest: 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1
freq_min_avg: 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1
freq_max_highest: 2, 5, 10, 4, 0, 10, 5, 5, 2, 10, 14, 14, 5, 10, 1, 5
freq_max_avg: 2, 8, 10, 4, 0, 10, 5, 5, 3, 10, 14, 14, 7, 10, 1, 8
freq_avg_highest: 4, 9, 12, 6, 0, 13, 3, 5, 2, 8, 15, 14, 10, 7, 1, 11
freq_avg_avg: 4, 9, 12, 6, 0, 13, 3, 5, 2, 8, 15, 14, 10, 7, 1, 11
freq_avg_avg_cppc: 224, 208, 208, 224, 240, 192, 224, 224, 224, 208, 176, 192, 208, 224, 240, 208
freq_per_watts_cppc: 160, 208, 224, 208, 160, 224, 192, 208, 224, 224, 176, 192, 240, 224, 240, 240
All Core averages:
min_lowest: 3.555000 min_avg: 3.585000 max_highest: 5.037500 max_avg: 5.025521 avg_highest: 4.871477 avg_avg: 4.867314 w_avg_avg: 14.089877 f_per_watt: 0.346974

Basically if I rank them by efficiency I get something like:
freq_per_watts_cppc: 160, 208, 224, 208, 160, 224, 192, 208, 224, 224, 176, 192, 240, 224, 240, 240

If I rank by average MHz only:
freq_avg_avg_cppc: 224, 208, 208, 224, 240, 192, 224, 224, 224, 208, 176, 192, 208, 224, 240, 208

default:
236, 231, 211, 226, 236, 206, 221, 216, 196, 166, 191, 186, 171, 181, 201, 176

My PBO2 curve offsets are (all negative):
8, 13, 15, 21, 18, 26, 30, 27, 28, 30, 18, 27, 27, 28, 28, 28

I have not done any extensive benchmarking, but from the little I have done performance seems to be impacted slightly (0.5-2%).
Since the boost steps are so small this makes sense.
 
  • Like
Reactions: moinmoin

Soulkeeper

Diamond Member
Nov 23, 2001
6,712
142
106
I was also speculating on why some cores just refuse to boost nomatter what bios settings you use, and i've come to the conclusion that AMD is using some kinda quality ranking internally for each core.

IE hypothetical equation:
f(x) = Vmax * (1 - Q) ^ (F - S)

Vmax = max available vcore(ie: 1.500v)
Q = internal quality number, measured at the factory per core
F = calculated fitness factor, takes into account temperature and load avg (likely more)
S = scalar offset factor (pbo scalar in the bios)

Essentially similar to an exponential decay formula.
The selected voltage at any given time (potentially every 1ms) is dithered down based on a formula (and thus the MHz assosciated with it), in order to keep the transistors from frying.

The best analogy I can come up with is connecting a wire accross a 9v battery's terminals. If you do it for a short time it'll get warm but won't damage the wire. Now, if you have different guage wires, that short time is different between them. Hence the different "Q" needed and different boosting behavior per core.

Basically our overclocks are not really limited by our sample's silicon lottery and cooling in the traditional sense, but more limited by what is measured during production (likely only for a limited range ie: upto the max supported boost clock) plus a safety margin with an acceptable failure rate for all samples in mind.
Anything above what is tested is basically projected. A predicted curve using a slope. The voltage/freq "tables" are generated in realtime with formulas using fixed variables. So if you have a dog core that just refuses to boost it's Q might be so bad it assigns 1.60v instead of 1.50v like your other cores. You'd have to either massively raise your voltage on all cores to hit that, or massively lower your temps to get F down.

Of course this is all speculation, I just wish things could be confirmed or the operation of these Ryzen were less of a "black box".
 
Last edited:
  • Like
Reactions: moinmoin

moinmoin

Diamond Member
Jun 1, 2017
4,952
7,661
136
I recently modified my linux kernel to use custom CPPC numbers for each core, and use intel's preferred core scheduler code because AMD hasn't implemented that yet.
That's some really cool experimentation! By modifying you mean editing the sources and rebuilding the kernel? Have you done that on your own or are there places documenting and discussing this?
 

Soulkeeper

Diamond Member
Nov 23, 2001
6,712
142
106
That's some really cool experimentation! By modifying you mean editing the sources and rebuilding the kernel? Have you done that on your own or are there places documenting and discussing this?

Yes, I often modify kernel or other programs' source. But I got the idea to use itmt from someone else that had done so.
 

Soulkeeper

Diamond Member
Nov 23, 2001
6,712
142
106
One thing that really bothers me is that it's impossible to validate stability when using PBO and curve offsets.
Infact I was just editing a text file and the system just rebooted ... after hours with no issues, no mce errors, etc.
You just can't force cores into their multiple voltage/mhz states to verify they even work and the amd algorithms might just do so once in a blue moon.
I can run 12+ hours, and have, of stress testing and core cycling. Nothing is enough.

tbh, I don't like PBO or any of this complicated stuff.
It's a shame we can't just control voltages per core (similar to curve offset's menu) and do our own manual overclocking. These algs are way too complicated/unpredictable and hidden.
 
Last edited:

Soulkeeper

Diamond Member
Nov 23, 2001
6,712
142
106
I think the only real solution to this would be an AMD sponsored bootable image that is able to cycle all possible core/mhz/voltage combinations like memtest. PBO is perpetually unstable for pretty much anyone who uses it. You can't trust something that can't be tested.
If I can save up some $ i'm going to run water cooling with a fixed all core oc. Losing 10% on the single threaded boost is a small price to pay for a stable system.