それは何度も尋ねられてきた質問ですが、私が見つけることができる十分にサポートされた答えはありません。
多くの人がtopコマンドの使用を提案していますが、topを1回実行すると(たとえば、1秒ごとにCPU使用率を収集するスクリプトがあるため)、常に同じCPU使用率結果が得られます( example 1 、 例2 )。
CPU使用率を計算するより正確な方法は、/proc/stat
から値を読み取ることですが、ほとんどの答えは/proc/stat
の最初の4つのフィールドのみを使用して計算します(1つの例 ここ )。
/proc/stat/
には、Linuxカーネル2.6.33の時点でCPUコアごとに10個のフィールドがあります!
私もこれを見つけました / proc/statを使用したLinuxでのCPU使用率の正確な計算 同じ問題を指摘している質問-他のほとんどの質問は多くのフィールドのうち4つだけを考慮していますが、ここで与えられる答えは「確信」から始まりますが、それ以外は、最初の7つのフィールド(/proc/stat/
の10個のうち)のみに関係します。
これ Perlスクリプトは、すべてのフィールドを使用してCPU使用率を計算しますが、これはさらに調査した結果、正しいとは思いません。
カーネルコードを簡単に見てみると here のようになります。たとえば、guest_Nice
とguest fields
は常にNice
とuser
とともに増加しています(したがって、これらは既にNice
およびuser
フィールドに含まれているため、CPU使用量の計算に含まれます)
/*
* 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使用率を計算する正確な方法は何ですか?また、計算でどのフィールドを考慮する必要があり、どのフィールドがアイドル時間に起因し、どのフィールドが非アイドル時間に起因するのでしょうか?
執筆時点の htop ソースコードによると、私の仮定は有効であるように見えます。
( ProcessList.c のvoid ProcessList_scan(ProcessList* 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...)
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.8 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
以下は、ヴァンゲリスの答えに基づいた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
ちょっと私もトピックの研究をしていて、このスレッドは本当に役に立ちました。このために、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")
idnt.net には、/ proc/stat cpuデータの使用方法に関する適切な説明があり、CPUと行の説明を抽出するためのbashスクリプトが含まれています。貴重だと思ったので、ここにリンクしたかっただけです。
#!/usr/bin/Ruby -w
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