ps vs top:CPU占用率统计的两种不同方式

文章解释了Linux系统中ps和top命令在计算CPU占用率时的不同方法,以及为何会出现统计差异。ps提供的是进程整个生命周期的平均CPU占用率,而top能显示实时的CPU占用变化。了解这些原理有助于设计更精确的监控系统。

如何计算 CPU 占用率?

简单来说,进程的 CPU 占用率指的是 CPU 有多少时间花费在了运行进程上。在 Linux 系统里,进程运行的时间是以jiffies[1]统计的,通过计算jiffies * HZ,就可以得到进程消耗的 CPU 时间,再除以 CPU 的总时间,就可以得到进程的 CPU 占用率:jiffies * HZ / total_time

ps 和 top 的不同之处

pstop是最常用的两种查看 CPU 占用的方式,都可以用来快速找到当前 CPU 占用率高的进程。但实际上这两个工具的统计方式是完全不同的。

我们用下面这个简单的 Go 程序来测试这两个工具的差别:

package main

import (
    "bytes"
    "fmt"
    "strconv"
    "sync"
    "time"
)

var testData = []byte(`testdata`)

func testBuffer(idx int) {
  m := map[string]*bytes.Buffer{}
  for i := 0; i < 100; i += 1 {
    buf, ok := m[strconv.Itoa(i)]
    if !ok {
      buf = new(bytes.Buffer)
    }
    for j := 0; j < 1024; j += 1 {
      buf.Write(testData)
    }
    m[strconv.Itoa(i)] = buf
  }
  fmt.Println("done, ", idx)
  wg.Done()
}

var wg sync.WaitGroup

func main() {
    for i := 0; i < 10; i += 1 {
        wg.Add(1)
        j := i
        go testBuffer(j)
    }
    wg.Wait()
    fmt.Println("sleeping")
    time.Sleep(time.Hour)
}

然后我们运行这个程序,通过topps aux分别查看进程的 CPU 占用情况。

top -n 1:

PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
39753 infini    20   0 14.663g 0.014t   1200 S 611.1 22.2   0:23.53 test-cpu

ps aux:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
infini   39881  767 39.1 26505284 25791892 pts/16 Sl+ 07:04   0:38 ./test-cpu

可以看到,pstop统计的 CPU 占用率是近似的(由于时间点并不完全吻合,统计值也会有轻微差别)。两个工具的差异体现在testBuffer结束后,top统计的 CPU 占用率已经接近于 0,但是ps依然统计到很高的 CPU 占用率:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
infini   39881 82.3 42.4 28638148 27953532 pts/16 Sl+ 07:04   0:40 ./test-cpu

为什么 ps 和 top 的统计值会有差异?

这两个工具的差异来自于各自运行方式的不同:top 只能持续运行一段时间,而 ps 是立刻返回的。这个差异体现在运行top -n 1ps aux时,top是延迟后返回的,而ps是立刻返回的。这两种不同的运行方式就会反映在两个工具的统计算法上。

文章开头我们提到,Linux 的 CPU 时间是按照jiffies统计的,考虑到效率问题,Linux 只会统计总值,不会记录历史数据。对于 ps 来说,由于只能统计到瞬时值,这个瞬时值的统计算法就必然拿不到实时的 CPU 占用率,因为实时的占用率需要通过 (current_cpu_time - last_cpu_time) / time_duration来得到,ps 只能统计一次,所以time_duration0,也就无法计算这个占用率。实际上,ps 统计的是整个进程运行周期内的 CPU 占用率[2]:

(total_cpu_time / total_process_uptime)

对于测试程序这种短时间的占用率上升,刚开始的时候 ps 能够统计到近似准确的平均 CPU 占用率,但是 cpu 占用恢复后,ps 的统计值并不会立刻下降,而是会随着进程运行时间total_process_uptime的增加缓慢下降。

top 命令不同, top 是通过持续运行来更新 CPU 占用率统计的。-n 1这个参数指定 top 运行一个迭代后退出,top命令就可以通过这个延迟来可以完成一个迭代内的 CPU 占用率统计:

(current_cpu_time - last_cpu_time) / iteration_duration

如何持续监控 CPU 占用率?

通常来说,监控系统分为采集和统计两个不同的组件,采集组件只会采集指标数值,统计功能通过数据库/Dashboard 来实现。要监控 CPU 占用率,ps是一个非常符合采集组件行为的统计方式,每次采集都可以拿到“当前”的 CPU 占用率。但是受限于算法本身的统计方式,我们实际采集到的是平均 CPU 占用率,无法反映进程的实时状态。

以 INFINI Console为例,我们运行一个短时间的数据迁移任务负载,然后查看对应 INFINI 网关实例的 CPU 占用监控(payload.instance.system.cpu,通过ps方式统计当前 CPU 占用率)。可以看到,CPU 占用率会以一个曲线上升,在任务结束后会缓慢下降:

如果想持续监控实时 CPU 占用率,我们就需要借鉴top的统计方式,采集原始的进程 CPU 时间,进而通过聚合数据来计算 CPU 占用率。

在 Linux 系统下,pstop命令都会通过/proc/[PID]/stat提供的信息来计算 CPU 占用率[2]:

##  Name      Description
14  utime     CPU time spent in user code, measured in jiffies
15  stime     CPU time spent in kernel code, measured in jiffies
16  cutime    CPU time spent in user code, including time from children
17  cstime    CPU time spent in kernel code, including time from children

获取到每个采样时间的进程信息后,我们就可以通过这个公式来计算采样周期内的 CPU 占用率:

delta(cpu_time) / delta(timestamp)

在 INFINI Console,我们可以通过deriative函数来计算payload.instance.system.user_in_mspayload.instance.system.sys_in_ms相对于timestamp的占比,进而得到准确的 CPU 占用率统计。

New utilization algorithm configuration in Console

这样,我们就可以统计到网关在运行任务负载前后的实时 CPU 占用率:

New utilization algorithm

总结

虽然topps都可以统计 CPU 占用率,但统计算法却完全不同。了解这两种算法的底层原理之后,我们就可以设计出适合监控系统的数据采集和数据统计方式,采集到准确的 CPU 占用率。

参考

  1. Jiffies
  2. Top and ps not showing the same cpu result
<think> 我们已知用户已经了解pstop命令,现在需要其他方法。根据Linux系统监控工具,除了pstop,还有以下常用方法: 1. htop:增强版的top,提供更友好的界面和更多交互功能。 2. pidstat:sysstat工具包的一部分,专门用于监控进程资源使用情况。 3. mpstat:也是sysstat工具包的一部分,可以查看每个CPU核心的使用情况,也可以监控特定进程的CPU使用(需要结合其他工具)。 4. vmstat:虽然主要用于监控虚拟内存,但也可以提供CPU使用的整体情况。 5. /proc文件系统:通过读取/proc/[pid]/stat文件可以获取进程的CPU使用信息。 但是,用户要求的是查看某个特定进程的CPU占用,因此我们重点推荐htop和pidstat,同时介绍/proc文件系统的方法。 ### 方法1: 使用`htop`命令(交互式实时监控) `htop`是`top`的增强版,提供彩色界面、鼠标操作和更直观的进程信息。安装和步骤如下: 1. **安装htop**(如果未预装): ```bash sudo apt install htop # Debian/Ubuntu sudo yum install htop # CentOS/RHEL ``` 2. **启动htop并查找进程**: ```bash htop ``` - 进入界面后,按`F3`或`/`键搜索进程名(如`nginx`)。 - 按`F4`可以按进程名过滤。 - 按`F6`可选择排序字段(例如按`%CPU`排序)。 - 显示信息包括`%CPU`、`%MEM`、进程状态等,与top类似但更易读[^1][^3]。 3. **直接监控指定进程**(通过PID): ```bash htop -p PID1,PID2,... # 多个PID用逗号分隔 ``` ### 方法2: 使用`pidstat`命令(详细统计) `pidstat`是sysstat工具包的一部分,可监控进程的CPU、内存等使用情况,支持周期性输出。安装和使用: 1. **安装sysstat**: ```bash sudo apt install sysstat # Debian/Ubuntu sudo yum install sysstat # CentOS/RHEL ``` 2. **查看特定进程的CPU占用**(例如PID为1234): ```bash pidstat -p 1234 1 5 # 每1秒输出一次,共5次 ``` 输出示例: ``` Linux 5.4.0-80-generic (host) 08/20/2023 _x86_64_ (4 CPU) 03:15:00 PM UID PID %usr %system %guest %wait %CPU CPU Command 03:15:01 PM 1000 1234 1.50 0.20 0.00 0.00 1.70 1 nginx ``` - **关键列**: - `%usr`:用户态CPU占用百分比。 - `%system`:内核态CPU占用百分比。 - `%CPU`:总CPU占用(即`%usr + %system`)[^4]。 3. **按进程名监控**(例如监控所有`nginx`进程): ```bash pidstat -C nginx 1 5 ``` ### 方法3: 通过`/proc`文件系统(底层读取) Linux在`/proc`目录下为每个进程提供实时统计文件: 1. **查找进程的统计信息**(以PID=1234为例): ```bash cat /proc/1234/stat ``` 输出为一行包含多个字段的数据(字段含义见`man proc`),其中: - 第14-17字段(从1开始计数)是进程的CPU时间片计数(单位是时钟嘀嗒,通常100嘀嗒=1秒): - `utime`:用户态运行时间(字段14)。 - `stime`:内核态运行时间(字段15)。 - `cutime`:子进程用户态时间(字段16)。 - `cstime`:子进程内核态时间(字段17)。 2. **计算瞬时CPU占用率**: 需要两次采样计算差值: ```bash # 第一次采样 start_time=$(date +%s) start_ticks=$(awk '{print $14+$15}' /proc/1234/stat) sleep 1 # 等待1秒 # 第二次采样 end_time=$(date +%s) end_ticks=$(awk '{print $14+$15}' /proc/1234/stat) # 计算CPU占用率(百分比) cpu_usage=$(( ( (end_ticks - start_ticks) * 100) / (end_time - start_time) / $(getconf CLK_TCK) )) echo "CPU占用率: $cpu_usage%" ``` - 注意:`CLK_TCK`是每秒时钟嘀嗒数(通常为100),可通过`getconf CLK_TCK`获取。 ### 方法对比 - **htop**:适合交互式操作,界面友好。 - **pidstat**:适合脚本化和周期性监控,输出结构化。 - **/proc**:适合开发自定义监控工具,但使用复杂。 ### 注意事项 - 所有方法中`%CPU`都是相对于总CPU核心数的占用率(如8核系统上100%表示一个核心满载)。 - 监控需权限:非当前用户的进程可能需要`sudo`。 §§相关问题§§ 1. 如何安装和使用`htop`进行高级进程管理? 2. `pidstat`能否同时监控CPU和内存使用? 3. 如何编写脚本定时监控进程的CPU占用? [^1]: htop作为top的升级版,提供更直观的进程监控界面和交互功能。 [^2]: pidstat命令详解,用于监控指定进程的CPU、内存、I/O等资源使用情况。 [^3]: /proc文件系统中进程状态文件的字段含义及计算方法。 [^4]: sysstat工具包的使用,包括pidstat的安装和输出解释。 </think>### 除`ps`和`top`外查看进程CPU占用的方法 在Linux中,除了常用的`ps`和`top`命令,还有多种工具可以查看进程的CPU占用情况。以下是三种实用方法(按推荐度排序): --- ### 方法1: 使用`htop`命令(增强型交互监控) `htop`是`top`的升级版,提供彩色界面、鼠标支持和更直观的进程管理功能: ```bash htop -p <PID> # 监控指定进程 ``` **操作说明**: 1. 安装:`sudo apt install htop` (Debian/Ubuntu) 或 `sudo yum install htop` (CentOS/RHEL) 2. 启动后: - 按`F3`搜索进程名(如`nginx`) - 按`F4`过滤进程 - **CPU列**实时显示占用率(支持多核视图) - 按`F2`进入配置界面调整显示参数[^3] **优势**: - 直观显示进程树结构(按`F5`) - 支持鼠标点击排序 - 直接杀死进程(`F9`) --- ### 方法2: 使用`pidstat`(详细性能统计) ```bash pidstat -p <PID> 1 5 # 每1秒采样1次,共5次 ``` **输出示例**: ``` 03:15:00 PM UID PID %usr %system %guest %CPU CPU Command 03:15:01 PM 1000 1234 1.50 0.20 0.00 1.70 1 nginx ``` **关键列解释**: - `%usr`:用户态CPU占用 - `%system`:内核态CPU占用 - `%CPU`:总CPU占用率(= %usr + %system)[^4] **进阶用法**: ```bash pidstat -p ALL # 监控所有进程 pidstat -C nginx -d # 监控nginx的CPU+磁盘I/O ``` --- ### 方法3: 通过`/proc`文件系统(底层数据读取) 直接解析内核提供的进程信息文件: ```bash # 1. 查看进程的CPU时间片统计 cat /proc/<PID>/stat | awk '{print $14+$15}' # 第14/15列为CPU时间片计数 # 2. 计算实时CPU占用率 start_time=$(date +%s) start_ticks=$(awk '{print $14+$15}' /proc/<PID>/stat) sleep 1 end_ticks=$(awk '{print $14+$15}' /proc/<PID>/stat) cpu_usage=$(( (end_ticks - start_ticks) * 100 / $(getconf CLK_TCK) )) echo "CPU Usage: ${cpu_usage}%" ``` **文件说明**: - `/proc/<PID>/stat`:包含进程的140+个统计字段 - `/proc/stat`:系统级CPU时间统计 - `CLK_TCK`:每秒时钟滴答数(通常100)[^2] --- ### 方法对比表 | 工具 | 实时性 | 安装要求 | 适合场景 | |------------|--------|--------------|--------------------------| | `htop` | ★★★★ | 需手动安装 | 交互式诊断/可视化监控 | | `pidstat` | ★★★☆ | sysstat包 | 周期性采样/生成统计报告 | | `/proc` | ★★★★ | 内核自带 | 脚本开发/自定义监控工具 | --- ### 注意事项 1. **多核CPU计算**: CPU占用率超过100%表示使用多个核心(如400% = 4核满载)[^2] 2. **权限要求**: 监控其他用户的进程需`sudo`权限 3. **容器环境**: 在Docker中建议使用`docker stats <容器ID>`查看容器内进程
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值