web-dev-qa-db-de.com

Genaue Berechnung der CPU-Auslastung in Prozent unter Linux?

Es ist eine Frage, die oft gestellt wurde, aber es gibt keine fundierte Antwort, die ich finden könnte.

Viele Leute schlagen die Verwendung des Befehls top vor, aber wenn Sie top einmal ausführen (weil Sie ein Skript haben, das beispielsweise alle 1 Sekunde die CPU-Auslastung erfasst), wird immer das gleiche Ergebnis für die CPU-Auslastung angezeigt ( 1 , Beispiel 2 ).

Eine genauere Methode zur Berechnung der CPU-Auslastung ist das Lesen der Werte aus /proc/stat. Die meisten Antworten verwenden jedoch nur die ersten 4 Felder aus /proc/stat, Um sie zu berechnen (ein Beispiel hier ).

/proc/stat/ Hat ab Linux-Kernel 2.6.33 10 Felder pro CPU-Kern!

Ich fand auch diese Frage zur genauen Berechnung der CPU-Auslastung unter Linux mit/proc/stat , die auf dasselbe Problem hinweist, das die meisten anderen Fragen nur berücksichtigen Überlegung 4 von den vielen Feldern - aber die hier gegebene Antwort beginnt mit "Ich denke" (nicht sicher), und außer dass es nur um die ersten 7 Felder geht (von 10 in /proc/stat/)

Dieses Perl-Skript verwendet alle Felder, um die CPU-Auslastung zu berechnen, was nach einigen weiteren Untersuchungen meines Erachtens ebenfalls nicht korrekt ist.

Nach einem kurzen Blick in den Kernel-Code hier sieht es zum Beispiel so aus, als wären guest_Nice Und guest fields Wird immer zusammen mit Nice und user erhöht (daher sollten sie nicht in die Berechnung der CPU-Auslastung einbezogen werden, da sie bereits in den Feldern Nice und user enthalten sind )

/*
 * 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;
    }
}

Zusammenfassend lässt sich sagen, wie die CPU-Auslastung unter Linux genau berechnet werden kann und welche Felder in den Berechnungen berücksichtigt werden sollten und wie (welche Felder werden der Leerlaufzeit und welche Felder der Nicht-Leerlaufzeit zugeordnet).

49

Laut dem htop Quellcode zum Zeitpunkt des Schreibens, scheinen meine Annahmen gültig zu sein:

(Siehe void ProcessList_scan(ProcessList* this) function at 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;

Und so aus den Feldern in der ersten Zeile von /proc/stat: (siehe Abschnitt 1.8 unter Dokumentation )

     user    Nice   system  idle      iowait irq   softirq  steal  guest  guest_Nice
cpu  74608   2520   24433   1117073   6176   4054  0        0      0      0

Algorithmisch können wir den Prozentsatz der CPU-Auslastung wie folgt berechnen:

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

Das Folgende ist ein Bash-Skript, das auf der Antwort von Vangelis basiert. Es erzeugt eine Ausgabe wie diese:

total 49.1803
cpu0 14.2857
cpu1 100
cpu2 28.5714
cpu3 100
cpu4 30
cpu5 25

Erstelle eine Datei mit dem Namen get_cpu_usage.sh

Führen Sie es mit dem folgenden Befehl aus: bash get_cpu_usage.sh 0.2

Das Argument ist die Anzahl der zu messenden Sekunden. In diesem Fall sind es 200 Millisekunden.

Die Inhalte sind:

#!/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, ich habe auch nach dem Thema gesucht und fand diesen Thread wirklich hilfreich. Ich habe die Vangelis Tasoulas-Formel verwendet, um ein kleines python Skript dafür zu schreiben. Im Anhang befindet sich mein Python Code für das Problem. Es lädt jede Sekunde die CPU-Auslastung pro CPU_ID Vielleicht hilft es auch anderen. Auch Kommentare/Vorschläge sind willkommen :-)

#!/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 hat eine gute Beschreibung für die Verwendung der/proc/stat-CPU-Daten, enthält ein Bash-Skript zum Extrahieren der CPU und eine Beschreibung der Zeilen. Ich wollte es nur hier verlinken, da ich es wertvoll fand.

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