web-dev-qa-db-fra.com

Calcul précis de l'utilisation du processeur donné en pourcentage sous Linux?

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é)?

49
Vangelis Tasoulas

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
60
Vangelis Tasoulas

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
9
Fidel

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")                
6
PlagTag

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.

1
arberg
#!/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
0
S.Goswami