C'est une question qui a été posée à plusieurs reprises, mais il n'y a pas de réponse bien étayée que je puisse trouver.
Beaucoup de gens suggèrent l’utilisation de top commande, mais si vous exécutez top une fois (parce que vous avez un script qui collecte par exemple l’utilisation du Cpu toutes les secondes), il donnera toujours le même résultat d’utilisation du Cpu ( exemple 1 , exemple 2 ).
Un moyen plus précis de calculer l'utilisation du processeur consiste à lire les valeurs de /proc/stat
, mais la plupart des réponses utilisent uniquement les 4 premiers champs de /proc/stat
pour le calculer (un exemple ici ).
/proc/stat/
a 10 champs par noyau de processeur à partir du noyau 2.6.33!
J'ai aussi trouvé cette question Calculant avec précision l'utilisation du processeur sous Linux à l'aide de/proc/stat question soulignant le même problème, à savoir que la plupart des autres questions ne prennent en compte que 4 des nombreux champs, mais toujours le même. La réponse donnée ici commence par "je pense" (pas certain), et à part cela, il ne s'intéresse qu'aux 7 premiers champs (sur 10 dans /proc/stat/
)
This Le script Perl utilise tous les champs pour calculer l'utilisation du processeur, ce qui, encore une fois, ne me semble pas correct après une enquête plus approfondie.
Après avoir jeté un coup d’œil au code du noyau ici , on dirait, par exemple, guest_Nice
et guest fields
augmentent toujours avec Nice
et user
(ils ne doivent donc pas être inclus dans le calcul de l’utilisation du processeur, car ils sont inclus dans Nice
et user
champs déjà)
/*
* 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;
}
}
Donc, pour résumer, quel est un moyen précis de calculer l'utilisation du processeur sous Linux et quels champs doivent être pris en compte dans les calculs et comment (quels champs sont attribués au temps d'inactivité et quels champs au temps d'inactivité)?
Selon le code source htop au moment de la rédaction, mes hypothèses semblent être valides:
(voir void ProcessList_scan(ProcessList* this)
fonction à 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;
Et ainsi, à partir des champs listés dans la première ligne de /proc/stat
: (voir la section 1.8 à la section documentation )
user Nice system idle iowait irq softirq steal guest guest_Nice
cpu 74608 2520 24433 1117073 6176 4054 0 0 0 0
Algorithmiquement, nous pouvons calculer le pourcentage d'utilisation du processeur comme:
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
Ce qui suit est un script bash basé sur la réponse de Vangelis. Il produit une sortie comme ceci:
total 49.1803
cpu0 14.2857
cpu1 100
cpu2 28.5714
cpu3 100
cpu4 30
cpu5 25
Créez un fichier nommé get_cpu_usage.sh
Exécutez-le à l'aide de la commande suivante: bash get_cpu_usage.sh 0.2
L'argument est le nombre de secondes à mesurer. Dans ce cas, c'est 200 millisecondes.
Le contenu est:
#!/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, je faisais aussi des recherches sur le sujet et trouvais ce fil vraiment utile. J'ai utilisé la formule Vangelis Tasoulas pour écrire un petit script python pour cela. Ci-joint, mon code Python pour le problème. Il charge l'utilisation du processeur par unité de processeur toutes les secondes Peut-être que ça aide les autres aussi. Les commentaires/suggestions sont les bienvenus :-)
#!/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 décrit bien l’utilisation des données de l’unité centrale de processeur/proc/stat et inclut un script bash pour extraire l’unité centrale de traitement et la description des lignes. Je voulais juste le lier ici, car je le trouvais précieux.
#!/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