Why is the p-state status MSR on ryzen not changing?

13

I am trying to detect the current p-state of my cpu. I have noticed that the p-state status MSR (C001_0063) always returns 2 on my ryzen 1700x system, even if the core is clearly not in that state. I think it used to work with the initial bios (v0403) that my motherboard came with, but that's not available for download anymore1.

My cpu is overclocked2 to 3.8GHz. I used cpufreq-set to fix the speed and cpufreq-info to verify:

analyzing CPU 0:
  driver: acpi-cpufreq
  CPUs which run at the same hardware frequency: 0
  CPUs which need to have their frequency coordinated by software: 0
  maximum transition latency: 4294.55 ms.
  hardware limits: 2.20 GHz - 3.80 GHz
  available frequency steps: 3.80 GHz, 2.20 GHz
  available cpufreq governors: ondemand, conservative, performance, schedutil
  current policy: frequency should be within 3.80 GHz and 3.80 GHz.
                  The governor "performance" may decide which speed to use
                  within this range.
  current CPU frequency is 3.80 GHz (asserted by call to hardware).

Following is a little test program that shows the value of the register for core #0, along with the effective speed relative to P0 state. Needs root privileges. For me, it constantly prints pstate: 2, speed: 99% under load.

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char** argv)
{
    uint64_t aperf_old = 0;
    uint64_t mperf_old = 0;
    int fd;

    fd = open("/dev/cpu/0/msr", O_RDONLY);
    uint64_t pstate_limits;
    pread(fd, &pstate_limits, sizeof(pstate_limits), 0xC0010061);
    printf("pstate ranges: %d to %d\n", (int)(pstate_limits & 0x07), (int)((pstate_limits >> 4) & 0x07));

    for(;;)
    {
        uint64_t pstate;
        uint64_t pstate_req;
        uint64_t aperf;
        uint64_t mperf;
        pread(fd, &pstate_req, sizeof(pstate_req), 0xC0010062);
        pread(fd, &pstate, sizeof(pstate), 0xC0010063);
        pread(fd, &aperf, sizeof(aperf), 0x000000E8);
        pread(fd, &mperf, sizeof(mperf), 0x000000E7);
        printf("pstate: %d, requested: %d", (int)(pstate & 0x07), (int)(pstate_req & 0x07));
        if (mperf_old != 0 && mperf_old != mperf)
        {
            printf(", speed: %d%%", (int)(100 * (aperf - aperf_old) / (mperf - mperf_old)));
        }
        putchar('\n');
        mperf_old = mperf;
        aperf_old = aperf;
        sleep(1);
    }
}

A similar approach used to work on my FX-8350. What am I doing wrong? Test results also welcome.

System information:

  • Cpu: ryzen 1700x, P0 & P1 is 3.8GHz3, P2 is 2.2GHz
  • Motherboard: Asus Prime X370-A, bios 3401
  • Operating system: debian 7.1, kernel 4.9.0

Update: I have changed the code to print the requested pstate and that register is changing as expected. The actual cpu speed is changing too, as confirmed by various benchmarks.


1 For some obscure reason, the bios backup function is disabled, so I couldn't make a copy before updating.

2 I will run a test at defaults when I get a chance.

3 No idea why it's duplicated.

linux
cpu
hardware
amd-processor
power-saving
asked on Stack Overflow Dec 20, 2017 by Jester • edited Dec 21, 2017 by Jester

1 Answer

0

It may not be related, however I have heard that some people have successfully had their Ryzen 7s replaced by AMD, due to p states causing system stability issues in Unix or Unix like systems. Although from commentary on the matter, especially from ASrock forum points towards a driver/firmware issue, I have read elsewhere that AMD may be taking some responsibility with early batches of chips. That said from what I know of P and C states, some states are requested by the operating system, or host vertulisation environment. So a patch could be done from within?

answered on Stack Overflow Oct 17, 2019 by piman007

User contributions licensed under CC BY-SA 3.0