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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容