Switch-Router

debian12 top -H 显示 CPU 利用率异常

Published at 2025-03-30 | Last Update 2025-03-30

问题环境现象

环境: debian12 (kernel 6.1.0)

现象: 运行一个多线程程序(测试程序见文末), 其中主线程空闲, 2个子线程繁忙, 使用 top -H 观察其各个线程的 CPU 利用率

可见, 此刻限制的主线程的 CPU 利用率异常地高.

原因分析

top命令来自于procps-ng包, 它通过定时读取/proc/PID文件系统下内核暴露的 tick 数据, 计算 CPU 利用率.

如果不使用-H选项, 则读取的就是整个进程(或者说线程组thread group)的占用近况, 此时读取的文件是/proc/[PID]/stat

如果使用-H选项指定 PID, 则其会读取该 PID 内所有线程(task)的统计数据, 路径为 /proc/[PID]/task/[pid]/stat

比如在我们的例子中, 我们使用以下命令每隔1s读取整个线程组的统计数据

watch -n 1 "cat /proc/10179/stat"

结果为

可以观察到, 红框中标注的数据差不多每次变化200, 说明整个进程的 CPU 占用率应该为 200%. 这也符合 top -p 显示的结果

接下来通过以下命令, 查看各个线程的统计信息

watch -n 1 "cat /proc/10179/task/10179/stat;cat /proc/10179/task/10180/stat;cat /proc/10179/task/10181/stat"

结果为

可以观察到, 只有下面两行红框中标注的数据每次变化差不多100, 而首行几乎不变, 但这与使用 top -H -p 10179 的结果不符

因此, 问题到这里原因很明显了: 该系统自带的top命令实现错了

由于procps-ng是开源代码, 我们可以比较顺利地找到问题引入和修复的版本:

引入版本: https://gitlab.com/procps-ng/procps/-/commit/a37526260917bac624ae6b75fd9f4ea7287d81ad

修复版本: https://gitlab.com/procps-ng/procps/-/commit/bc688d630aeeeda5e003d35bbcfcdba08f21b399

附录

本文使用的测试程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
void *tfn(void *arg)
{
    int a = 0;
    while (1) {
        a++;
    }
    return (void*)0;
}
int main()
{
    pthread_t tid;
    int i = 0;
    printf("main--pid=%d,tid=%lu\n",getpid(),pthread_self());
    for (; i < 2; i++){
        int ret=pthread_create(&tid,NULL,tfn,NULL);
            if(ret!=0){
            fprintf(stderr,"pthread_create error:%s\n",strerror(ret));
            exit(1);
        }
    }
    sleep(6000);
    return 0;
}