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

2024-11-07 08:55:00
admin
原创
32
摘要:问题描述:这个问题已被问过很多次,但是我找不到有力支持的答案。很多人建议使用 top 命令,但是如果你运行一次 top(因为你有一个脚本,例如每 1 秒收集一次 CPU 使用情况),它将始终给出相同的 CPU 使用情况结果(示例 1、示例 2)。计算 CPU 使用率的更准确方法是通过读取中的值/proc/st...

问题描述:

这个问题已被问过很多次,但是我找不到有力支持的答案。

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

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

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

我还发现这个使用 /proc/stat 准确计算 Linux 中的 CPU 利用率问题指出了同样的问题,即大多数其他问题仅考虑了许多字段中的 4 个 - 但这里给出的答案仍然以“我认为”(不确定)开头,除此之外,它只关注前 7 个字段(共 10 个/proc/stat/

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

快速浏览一下此处的内核代码后,它看起来像,例如,guest_nice和总是与和guest fields一起增加(因此它们不应包括在 CPU 使用率计算中,因为它们已经包含在和字段中)nice`userniceuser`

/*
 * 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 使用率,以及在计算中应该考虑哪些字段以及如何计算(哪些字段属于空闲时间,哪些字段属于非空闲时间)?


解决方案 1:

根据htop源代码,我的假设看起来是正确的:

(参见LinuxProcessList.cstatic inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this)中的函数)

// 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...)
unsigned long long int idlealltime = idletime + ioWait;  # ioWait is added in the idleTime
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第 1.8 节)

     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

解决方案 2:

以下是基于 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

解决方案 3:

嘿,我也在研究这个主题,发现这个帖子真的很有帮助。我使用 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('
') 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")                

解决方案 4:

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

解决方案 5:

我也在寻找同样的东西。这是我基于 Vangelis Tasoulas 的答案编写的 ruby​​ 程序:

#!/usr/bin/env ruby
$VERBOSE = true

prev_file = IO.readlines(::File.join('', 'proc', 'stat')).select { |line| line.start_with?('cpu') }
Kernel.sleep(0.05)
file = IO.readlines(::File.join('', 'proc', 'stat')).select { |line| line.start_with?('cpu') }

file.size.times do |i|
    data, prev_data = file[i].split.map(&:to_f), prev_file[i].split.map(&:to_f)

    %w(user nice sys idle iowait irq softirq steal).each_with_index do |el, index|
        eval "@#{el}, @prev_#{el} = #{data[index + 1]}, #{prev_data[index + 1]}"
    end

    previdle, idle = @prev_idle + @prev_iowait, @idle + @iowait
    totald = idle + (@user + @nice + @sys + @irq + @softirq + @steal) -
        (previdle + (@prev_user + @prev_nice + @prev_sys + @prev_irq + @prev_softirq + @prev_steal))

    puts "CPU #{i}: #{((totald - (idle - previdle)) / totald * 100).round(2)} %"
end

解决方案 6:

以下是基于 Fidel 的回答和 arberg 的链接构建的 bash 脚本。

我想降低 cat awk grep 和 date 调用的使用率,并减少 CPU 使用率,以找出 CPU 使用率。

输出:

total: 4%
cpu0: 10%
cpu1: 5%
cpu2: 1%
cpu3: 1%

使用以下命令创建一个 bash 脚本:

#!/bin/bash

# Paramiter one used to set time in sec between reads
sleepDurationSeconds=$1

# read cpu stats to arrays
readarray -t previousStats < <( awk '/^cpu /{flag=1}/^intr/{flag=0}flag' /proc/stat )
sleep $sleepDurationSeconds
readarray -t currentStats < <( awk '/^cpu /{flag=1}/^intr/{flag=0}flag' /proc/stat )

# loop through the arrays
for i in "${!previousStats[@]}"; do
  # Break up arrays 1 line sting into an array element for each item in string
  previousStat_elemant_array=(${previousStats[i]})
  currentStat_elemant_array=(${currentStats[i]})

  # Get all columns from user to steal
  previousStat_colums="${previousStat_elemant_array[@]:1:7}"
  currentStat_colums="${currentStat_elemant_array[@]:1:7}"

  # Replace the column seperator (space) with +
  previous_cpu_sum=$((${previousStat_colums// /+}))
  current_cpu_sum=$((${currentStat_colums// /+}))

  # Get the delta between two reads
  cpu_delta=$((current_cpu_sum - previous_cpu_sum)) 

  # Get the idle time Delta
  cpu_idle=$((currentStat_elemant_array[4]- previousStat_elemant_array[4]))

  # Calc time spent working
  cpu_used=$((cpu_delta - cpu_idle)) 

  # Calc percentage
  cpu_usage=$((100 * cpu_used / cpu_delta))

  # Get cpu used for calc cpu percentage used
  cpu_used_for_calc="${currentStat_elemant_array[0]}"

  if [[ "$cpu_used_for_calc" == "cpu" ]]; then
    echo "total: "$cpu_usage"%"
  else
    echo $cpu_used_for_calc": "$cpu_usage"%"
  fi

done

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用