[英]Accurate calculation of CPU usage given in percentage in Linux?
It's a question which has been asked many times, however there is no well supported answer I could find.这是一个被问过很多次的问题,但是我找不到得到很好支持的答案。
Many people suggest the use of top command, but if you run top once (because you have a script for example collecting Cpu usage every 1 second) it will always give the same Cpu usage result ( example 1 , example 2 ).很多人建议使用 top 命令,但是如果您运行 top 一次(因为您有一个脚本,例如每 1 秒收集一次 Cpu 使用率),它总是会给出相同的 Cpu 使用率结果( 示例 1 , 示例 2 )。
A more accurate way to calculate CPU usage, is by reading the values from /proc/stat
, but most of the answers use only the first 4 fields from /proc/stat
to calculate it (one example here ).计算 CPU 使用率的一种更准确的方法是读取
/proc/stat
,但大多数答案仅使用/proc/stat
的前 4 个字段来计算它( 此处有一个示例)。
/proc/stat/
has 10 fields per CPU core as of Linux kernel 2.6.33!从 Linux 内核 2.6.33 开始,
/proc/stat/
每个 CPU 内核有 10 个字段!
I also found this Accurately Calculating CPU Utilization in Linux using /proc/stat question which is pointing out the same issue, -that most other questions only take into consideration 4 out of the many fields- but still the answer given here starts with "I think" (not certain), and except that, it is only concerned about the first 7 fields (out of 10 in /proc/stat/
)我还发现这个Accurately Calculating CPU Utilization in Linux using /proc/stat问题指出了同样的问题,——大多数其他问题只考虑了许多领域中的 4 个——但这里给出的答案仍然以“我think”(不确定),除此之外,它只关注前 7 个字段(
/proc/stat/
的 10 个字段)
This perl script uses all of the fields to calculate the CPU usage, which again I do not think is correct after some further investigation.这个perl 脚本使用所有字段来计算 CPU 使用率,经过进一步调查,我再次认为这是不正确的。
After taking a quick look into the kernel code here , it looks like, for example, guest_nice
and guest fields
are always increasing together with nice
and user
(so they should not be included in the cpu usage calculation, since they are included in nice
and user
fields already)在这里快速查看内核代码后,它看起来像,例如,
guest_nice
和guest fields
总是与nice
和user
一起增加(因此它们不应包含在 cpu 使用率计算中,因为它们包含在nice
和user
字段已经)
/*
* 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;
}
}
So to sum up, what is an accurate way to calculate the CPU usage in Linux and which fields should be considered in the calculations and how (which fields are attributed to the idle time and which fields to non-idle time)?那么总结一下,Linux中CPU使用率的准确计算方法是什么,计算中应该考虑哪些字段以及如何计算(哪些字段属于空闲时间,哪些字段属于非空闲时间)?
According the htop source code, my assumptions looks like they are valid:根据htop源代码,我的假设看起来是有效的:
(see static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this)
function at LinuxProcessList.c ) (见
static inline double LinuxProcessList_scanCPUTime(LinuxProcessList* this)
在功能LinuxProcessList.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...)
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;
And so, from fields listed in the first line of /proc/stat
: (see section 1.8 at documentation )因此,从
/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
Algorithmically, we can calculate the CPU usage percentage like:从算法上讲,我们可以计算 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
The following is a bash script which is based on Vangelis's answer.以下是基于 Vangelis 的回答的 bash 脚本。 It produces output like this:
它产生这样的输出:
total 49.1803
cpu0 14.2857
cpu1 100
cpu2 28.5714
cpu3 100
cpu4 30
cpu5 25
Create a file called get_cpu_usage.sh
创建一个名为
get_cpu_usage.sh
的文件
Run it using the following command: bash get_cpu_usage.sh 0.2
使用以下命令运行它:
bash get_cpu_usage.sh 0.2
The argument is the number of seconds to measure.参数是要测量的秒数。 In this case it's 200 milliseconds.
在这种情况下,它是 200 毫秒。
The contents are:内容是:
#!/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
Hey i was also researching for the topic and found this thread really helpful.嘿,我也在研究这个话题,发现这个帖子真的很有帮助。 I used Vangelis Tasoulas formula to write a small python script for this.
我使用 Vangelis Tasoulas 公式为此编写了一个小的 python 脚本。 Attached is my Python code for the issue.
附件是我针对该问题的 Python 代码。 It loads the cpu usage per cpu_id every second.
它每秒加载每个 cpu_id 的 CPU 使用率。 Maybe its helps others as well.
也许它也可以帮助其他人。 Also comments/suggestions are welcome :-)
也欢迎评论/建议:-)
#!/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")
I was also looking for the same.我也在寻找同样的。 Here is my ruby program based on the Vangelis Tasoulas's answer:
这是我基于 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
The following is a bash script builds on Fidel's answer and arberg's link.以下是基于 Fidel's answer 和 arberg's 链接的 bash 脚本。
I wanted to lower the usage of cat awk grep and date calls and spend less cpu usage trying to figure out the cpu usage.我想降低 cat awk grep 和 date 调用的使用率,并花更少的 CPU 使用量试图找出 CPU 使用率。
Output:输出:
total: 4%
cpu0: 10%
cpu1: 5%
cpu2: 1%
cpu3: 1%
create a bash script using this:使用以下命令创建一个 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.