Mystery problem with wrong CPU frequency reading in htop

Original link: https://irr.ink/2022/2H3Y57Q/

Since a certain day, I don’t know what’s updated, the CPU frequency of htop has suddenly become strange. The specific phenomenon is that the CPU frequency is basically kept at 2600Mhz when it is not loaded (just the highest frequency when the turbo frequency is not turned on). Under normal circumstances, the frequency of the CPU itself should be maintained at about 800Mhz due to the function of intel_pstate when it is not loaded. At first, I thought it was really a problem with the CPU frequency, and I suspected the CPU scheduler, but after changing a few cores, the situation was the same, so it was ruled out that the problem was with the scheduler. There should be a problem with htop reading the frequency, not the CPU itself.

Is there anything other than htop that can read the CPU frequency and compare it to it? Then I went to try KDE’s System Monitor. Add the CPU frequency monitoring entry in the KDE monitor, and you can find that the frequency read by this tool should be almost correct – most CPU frequencies are at 800Mhz at no load. However, now, a very weird phenomenon has happened:

  1. Open htop first, then open the system monitor, the htop frequency is incorrect
  2. Open the system monitor first, then open htop, the htop frequency is correct
  3. On the basis of the previous step, close the system monitor, the htop frequency is not correct

I’m really confused here, I don’t know what’s going on at all. Here we can only think about the principles of these software reading. Then I went to see the issue of htop. I found that reading the CPU frequency mainly depends on two places, one is /proc/cpuinfo , the other is /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq . In my On the machine, the frequency of the former is not correct, while the frequency of the latter is correct (see this issue ). It seems that we can only look at the source code of htop.

In short, after searching around in the code, this commit caught my attention. The general meaning of this commit is to read the CPU frequency from the former first. If the reading speed is too slow (the judgment standard is that the time to read the CPU0 frequency is greater than 500us), the latter will be used in the next 30 reads to obtain the CPU. frequency. Then we will test the reading speed.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
 ❯ time cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
2859898
3439062
3518834
3357022
3600078
3514387
3590909
3578165
3267212
3537751
3488934
3425438
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq 0 . 00 s user 0 . 00 s system 0 % cpu 0 . 213 total

❯ time grep 'cpu MHz' /proc/cpuinfo
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 2600.000
cpu MHz : 3600.089
grep 'cpu MHz' /proc/cpuinfo 0 . 00 s user 0 . 00 s system 13 % cpu 0 . 019 total

I also tested it through debug. The time I read the frequency of CPU0 is as high as 16000us, and htop will naturally read the frequency of the latter, which causes the frequency to display incorrectly.

At the same time, there is another discovery, which can also explain the second phenomenon above. When a process is reading /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq , read this place again:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
 ❯ time cat /sys/ devices /system/ cpu /cpu*/ cpufreq/scaling_cur_freq
3295722
3565060
3588762
3109933
3577284
3595533
3566348
3466786
3431875
3391583
3443595
3590967
cat /sys/ devices /system/ cpu /cpu*/ cpufreq/scaling_cur_freq 0.00 s user 0.00 s system 81 % cpu 0.002 total

Much sooner! This can explain the cause of the second abnormal phenomenon above. When another process is reading, the delay measured by htop is less than 500us, and the correct frequency is obtained.

So now the solution is obvious:

  1. Change the kernel to reduce the delay
  2. Add asynchronous, let htop read successfully and then refresh
  3. Let htop open a subprocess to read frequency to reduce latency
  4. Change the threshold to prevent htop from reading /proc/cpuinfo

Unfortunately, I can’t do method 1. This delay seems to involve the implementation of psate , which is a field I don’t understand at all; methods 2 and 3 are estimated that I will not be able to write and submit a PR, so I don’t need to worry about that. Now; let’s choose the simplest method, change the delay, and change the 500us to 19000us, and it will work. The consequence of this is that the operation of htop will be stuck, but the impact is not very big.

This article is reprinted from: https://irr.ink/2022/2H3Y57Q/
This site is for inclusion only, and the copyright belongs to the original author.