ps vs 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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值