在Linux中准确计算以百分比表示的CPU使用率?

11 浏览
0 Comments

在Linux中准确计算以百分比表示的CPU使用率?

这是一个经常被问到的问题,但我找不到一个有充分支持的答案。\n很多人建议使用top命令,但如果你运行一次top命令(比如因为你有一个脚本每秒收集CPU使用率),它将始终给出相同的CPU使用率结果(参考示例1,示例2)。\n一个更准确的计算CPU使用率的方法是从/proc/stat读取值,但大多数答案只使用/proc/stat的前4个字段来计算(一个例子在这里)。\nLinux内核2.6.33版本之后,每个CPU核心的/proc/stat有10个字段!\n我还发现了这个问题:使用/proc/stat在Linux中准确计算CPU利用率,它指出了同样的问题,-大多数其他问题只考虑了其中4个字段-但仍然给出的答案以“我认为”开头(不确定),而且除此之外,它只关注了/proc/stat中的前7个字段(共有10个字段)。\n这个Perl脚本使用所有字段来计算CPU使用率,但经过进一步调查,我认为这也不正确。\n在这里快速查看内核代码后,看起来例如guest_nice和guest字段总是与nice和user一起增加(所以它们不应该被包括在CPU使用率计算中,因为它们已经包含在nice和user字段中)\n在Linux中准确计算CPU使用率的方法是什么,应该如何考虑这些字段以及如何计算(哪些字段归因于空闲时间,哪些字段归因于非空闲时间)?

0
0 Comments

问题的出现原因是原作者想要准确计算Linux系统中CPU的使用率,但是发现之前使用的Vangelis Tasoulas的公式并不准确。为了解决这个问题,原作者编写了一个小的Python脚本来计算CPU使用率,并将代码附在了回答中。

以下是原作者编写的Python代码:

#!/usr/bin/python 
# -*- coding: utf-8 -*-
'''
Created on 04.12.2014
: plagtag
'''
from time import sleep
import sys
class GetCpuLoad(object):
    '''
    classdocs
    '''
    def __init__(self, percentage=True, sleeptime = 1):
        '''
         class: GetCpuLoad
        : 04.12.2014
        : plagtag
        : 
        :
        : CPU load in percentage
        '''
        self.percentage = percentage
        self.cpustat = '/proc/stat'
        self.sep = ' ' 
        self.sleeptime = sleeptime
    def getcputime(self):
        '''
        http://stackoverflow.com/questions/23367857
        read in cpu information from file
        The meanings of the columns are as follows, from left to right:
            0cpuid: number of cpu
            1user: normal processes executing in user mode
            2nice: niced processes executing in user mode
            3system: processes executing in kernel mode
            4idle: twiddling thumbs
            5iowait: waiting for I/O to complete
            6irq: servicing interrupts
            7softirq: servicing softirqs
        #the formulas from htop 
             user    nice   system  idle      iowait irq   softirq  steal  guest  guest_nice
        cpu  74608   2520   24433   1117073   6176   4054  0        0      0      0
        Idle=idle+iowait
        NonIdle=user+nice+system+irq+softirq+steal
        Total=Idle+NonIdle # first line of file for all cpus
        CPU_Percentage=((Total-PrevTotal)-(Idle-PrevIdle))/(Total-PrevTotal)
        '''
        cpu_infos = {} #collect here the information
        with open(self.cpustat,'r') as f_stat:
            lines = [line.split(self.sep) for content in f_stat.readlines() for line in content.split('\n') if line.startswith('cpu')]
            #compute for every cpu
            for cpu_line in lines:
                if '' in cpu_line: cpu_line.remove('')#remove empty elements
                cpu_line = [cpu_line[0]]+[float(i) for i in cpu_line[1:]]#type casting
                cpu_id,user,nice,system,idle,iowait,irq,softrig,steal,guest,guest_nice = cpu_line
                Idle=idle+iowait
                NonIdle=user+nice+system+irq+softrig+steal
                Total=Idle+NonIdle
                #update dictionionary
                cpu_infos.update({cpu_id:{'total':Total,'idle':Idle}})
            return cpu_infos
    def getcpuload(self):
        '''
        CPU_Percentage=((Total-PrevTotal)-(Idle-PrevIdle))/(Total-PrevTotal)
        '''
        start = self.getcputime()
        #wait a second
        sleep(self.sleeptime)
        stop = self.getcputime()
        cpu_load = {}
        for cpu in start:
            Total = stop[cpu]['total']
            PrevTotal = start[cpu]['total']
            Idle = stop[cpu]['idle']
            PrevIdle = start[cpu]['idle']
            CPU_Percentage=((Total-PrevTotal)-(Idle-PrevIdle))/(Total-PrevTotal)*100
            cpu_load.update({cpu: CPU_Percentage})
        return cpu_load
if __name__=='__main__':
    x = GetCpuLoad()
    while True:
        try:
            data = x.getcpuload()
            print data
        except KeyboardInterrupt:
            sys.exit("Finished")                

然而,不幸的是,这个方法似乎并不准确,原作者在问题中提到了这个问题,并附上了他在Stack Overflow上的问题链接。

0
0 Comments

准确计算Linux中给出的CPU使用率的原因是,通过读取/proc/stat文件可以获取系统中每个CPU核心的使用情况,包括用户态、系统态、空闲态等状态的时间。然后根据两个时间点的数据,计算出CPU的利用率。

解决方法是通过编写一个bash脚本,使用以下步骤:

1. 获取脚本的参数,即测量的时间间隔。

2. 获取当前时间点的日期和/proc/stat文件的内容。

3. 通过sleep命令等待指定的时间间隔。

4. 获取当前时间点的日期和/proc/stat文件的内容。

5. 使用grep命令过滤出包含"cpu"的行,并使用awk命令提取出各个字段的值。

6. 计算出两个时间点的各个字段的差值,得到CPU的利用率。

7. 如果是总体的利用率,则输出"total "和利用率值;否则,输出CPU核心的编号和利用率值。

以下是完整的脚本代码:

#!/bin/sh
sleepDurationSeconds=$1
previousDate=$(date +%s%N | cut -b1-13)
previousStats=$(cat /proc/stat)
sleep $sleepDurationSeconds
currentDate=$(date +%s%N | cut -b1-13)
currentStats=$(cat /proc/stat)    
cpus=$(echo "$currentStats" | grep -P 'cpu' | awk -F " " '{print $1}')
for cpu in $cpus
do
    currentLine=$(echo "$currentStats" | grep "$cpu ")
    user=$(echo "$currentLine" | awk -F " " '{print $2}')
    nice=$(echo "$currentLine" | awk -F " " '{print $3}')
    system=$(echo "$currentLine" | awk -F " " '{print $4}')
    idle=$(echo "$currentLine" | awk -F " " '{print $5}')
    iowait=$(echo "$currentLine" | awk -F " " '{print $6}')
    irq=$(echo "$currentLine" | awk -F " " '{print $7}')
    softirq=$(echo "$currentLine" | awk -F " " '{print $8}')
    steal=$(echo "$currentLine" | awk -F " " '{print $9}')
    guest=$(echo "$currentLine" | awk -F " " '{print $10}')
    guest_nice=$(echo "$currentLine" | awk -F " " '{print $11}')
    previousLine=$(echo "$previousStats" | grep "$cpu ")
    prevuser=$(echo "$previousLine" | awk -F " " '{print $2}')
    prevnice=$(echo "$previousLine" | awk -F " " '{print $3}')
    prevsystem=$(echo "$previousLine" | awk -F " " '{print $4}')
    previdle=$(echo "$previousLine" | awk -F " " '{print $5}')
    previowait=$(echo "$previousLine" | awk -F " " '{print $6}')
    previrq=$(echo "$previousLine" | awk -F " " '{print $7}')
    prevsoftirq=$(echo "$previousLine" | awk -F " " '{print $8}')
    prevsteal=$(echo "$previousLine" | awk -F " " '{print $9}')
    prevguest=$(echo "$previousLine" | awk -F " " '{print $10}')
    prevguest_nice=$(echo "$previousLine" | awk -F " " '{print $11}')    
    PrevIdle=$((previdle + previowait))
    Idle=$((idle + iowait))
    PrevNonIdle=$((prevuser + prevnice + prevsystem + previrq + prevsoftirq + prevsteal))
    NonIdle=$((user + nice + system + irq + softirq + steal))
    PrevTotal=$((PrevIdle + PrevNonIdle))
    Total=$((Idle + NonIdle))
    totald=$((Total - PrevTotal))
    idled=$((Idle - PrevIdle))
    CPU_Percentage=$(awk "BEGIN {print ($totald - $idled)/$totald*100}")
    if [[ "$cpu" == "cpu" ]]; then
        echo "total "$CPU_Percentage
    else
        echo $cpu" "$CPU_Percentage
    fi
done

使用以上脚本,可以通过命令`bash get_cpu_usage.sh 0.2`来运行,并且输出每个CPU核心的利用率以及总体的利用率。

0
0 Comments

准确计算Linux中的CPU使用率的问题出现的原因是代码中的计算方法存在问题。解决方法是修改计算方法,按照正确的算法进行计算。

根据htop源代码中的函数`static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this)`可以看出,我的假设是正确的:

// Guest time is already accounted in usertime
usertime = usertime - guest;                             
nicetime = nicetime - guestnice;                         
// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
unsigned long long int idlealltime = idletime + ioWait;  
unsigned long long int systemalltime = systemtime + irq + softIrq;
unsigned long long int virtalltime = guest + guestnice;
unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;

根据`/proc/stat`文件的第一行的字段,我们可以算出CPU的使用率百分比:

PrevIdle = previdle + previowait
Idle = idle + iowait
PrevNonIdle = prevuser + prevnice + prevsystem + previrq + prevsoftirq + prevsteal
NonIdle = user + nice + system + irq + softirq + steal
PrevTotal = PrevIdle + PrevNonIdle
Total = Idle + NonIdle
# differentiate: actual value minus the previous one
totald = Total - PrevTotal
idled = Idle - PrevIdle
CPU_Percentage = (totald - idled)/totald

作者提供了一个基于这个答案创建的小例子程序,可以在github.com/scaidermern/top-processes上找到。可以免费使用,它的许可证是CC0。

根据这个帖子unix.stackexchange.com/a/303224,我认为iowait状态是不可中断的状态,所以更实际的做法是将其计入“非空闲”状态,而不是计入空闲状态。

根据这个帖子,根据这个帖子,根据这个帖子,应该将guest和guest_nice添加到NonIdle中。正如在Vangelus的回答中所提到的,Guest time is already accounted in usertime

但是,这种方法不起作用,我的CPU使用率是80%,但结果显示为1.0到8.0。

0