首页 文章

准确计算Linux中以百分比给出的CPU使用率?

提问于
浏览
38

这是一个多次被问过的问题,但是我找不到很好的支持答案 .

很多人建议使用top命令,但如果你运行top一次(因为你有一个脚本,例如每1秒收集一次Cpu使用),它将始终给出相同的Cpu使用结果(example 1example 2) .

计算CPU使用率的更准确方法是通过读取 /proc/stat 中的值,但大多数答案仅使用 /proc/stat 中的前4个字段来计算它(一个示例here) .

从Linux内核2.6.33开始, /proc/stat/ 每个CPU核心有10个字段!

我也发现这个Accurately Calculating CPU Utilization in Linux using /proc/stat问题指出了同样的问题 - 大多数其他问题只考虑了很多领域中的4个 - 但这里给出的答案仍然是"I think"(不确定),除此之外,它是只关注前7个字段( /proc/stat/ 中的10个字段)

This perl脚本使用所有字段来计算CPU使用率,经过一些进一步的调查后我再次认为这是不正确的 .

在快速查看内核代码here后,看起来,例如, guest_niceguest fields 总是与 niceuser 一起增加(因此它们不应包含在cpu使用计算中,因为它们包含在 niceuser 中已经领域)

/*
 * Account guest cpu time to a process.
 * @p: the process that the cpu time gets accounted to
 * @cputime: the cpu time spent in virtual machine since the last update
 * @cputime_scaled: cputime scaled by cpu frequency
 */
static void account_guest_time(struct task_struct *p, cputime_t cputime,
                   cputime_t cputime_scaled)
{
    u64 *cpustat = kcpustat_this_cpu->cpustat;

    /* Add guest time to process. */
    p->utime += cputime;
    p->utimescaled += cputime_scaled;
    account_group_user_time(p, cputime);
    p->gtime += cputime;

    /* Add guest time to cpustat. */
    if (task_nice(p) > 0) {
        cpustat[CPUTIME_NICE] += (__force u64) cputime;
        cpustat[CPUTIME_GUEST_NICE] += (__force u64) cputime;
    } else {
        cpustat[CPUTIME_USER] += (__force u64) cputime;
        cpustat[CPUTIME_GUEST] += (__force u64) cputime;
    }
}

总而言之,什么是计算Linux中CPU使用率的准确方法,以及在计算中应考虑哪些字段以及如何(哪些字段归因于空闲时间以及哪些字段归因于非空闲时间)?

4 回答

  • 54

    根据撰写本文时的htop源代码,我的假设看起来有效:

    (见 void ProcessList_scan(ProcessList* this) 函数ProcessList.c

    // Guest time is already accounted in usertime
    usertime = usertime - guest;                     # As you see here, it subtracts guest from user time
    nicetime = nicetime - guestnice;                 # and guest_nice from nice time
    // Fields existing on kernels >= 2.6
    // (and RHEL's patched kernel 2.4...)
    idlealltime = idletime + ioWait;                 # ioWait is added in the idleTime
    systemalltime = systemtime + irq + softIrq;
    virtalltime = guest + guestnice;
    totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
    

    因此,从 /proc/stat 第一行中列出的字段:(参见第1.1节documentation

    user    nice   system  idle      iowait irq   softirq  steal  guest  guest_nice
    cpu  74608   2520   24433   1117073   6176   4054  0        0      0      0
    

    从算法上讲,我们可以计算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
    
  • 7

    以下是基于Vangelis答案的bash脚本 . 它产生如下输出:

    total 49.1803
    cpu0 14.2857
    cpu1 100
    cpu2 28.5714
    cpu3 100
    cpu4 30
    cpu5 25
    

    创建一个名为 get_cpu_usage.sh 的文件

    使用以下命令运行它: bash get_cpu_usage.sh 0.2

    参数是要测量的秒数 . 在这种情况下,它是200毫秒 .

    内容如下:

    #!/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
    
  • 5

    嘿,我也在研究这个主题,发现这个主题非常有用 . 我使用Vangelis Tasoulas公式为此编写一个小的python脚本 . 附件是我的问题的Python代码 . 它每秒加载每个cpu_id的cpu使用量 . 也许它也有助于其他人 . 欢迎提出意见/建议:-)

    #!/usr/bin/python 
    # -*- coding: utf-8 -*-
    
    '''
    Created on 04.12.2014
    
    @author: plagtag
    '''
    from time import sleep
    import sys
    
    class GetCpuLoad(object):
        '''
        classdocs
        '''
    
    
        def __init__(self, percentage=True, sleeptime = 1):
            '''
            @parent class: GetCpuLoad
            @date: 04.12.2014
            @author: plagtag
            @info: 
            @param:
            @return: CPU load in percentage
            '''
            self.percentage = percentage
            self.cpustat = '/proc/stat'
            self.sep = ' ' 
            self.sleeptime = sleeptime
    
        def getcputime(self):
            '''
            http://stackoverflow.com/questions/23367857/accurate-calculation-of-cpu-usage-given-in-percentage-in-linux
            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")
    
  • 1

    idnt.net对如何使用/ proc / stat cpu数据有很好的描述,包括用于提取cpu的bash脚本和行的描述 . 我只是想在这里链接它,因为我发现它很有 Value .

相关问题