it-swarm.com.ru

Точный расчет использования процессора в процентах в Linux?

Это вопрос, который задавался много раз, однако я не нашел ни одного надежного ответа.

Многие люди предлагают использовать команду top, но если вы запустите top один раз (потому что у вас есть скрипт, например, собирающий использование процессора каждую 1 секунду), он всегда даст тот же результат использования процессора ( пример 1 , пример 2 ).

Более точный способ вычислить загрузку ЦП - прочитать значения из /proc/stat, но в большинстве ответов используются только первые 4 поля из /proc/stat для расчета (один пример здесь ).

/proc/stat/ имеет 10 полей на ядро ​​процессора начиная с ядра Linux 2.6.33!

Я также нашел этот точный расчет загрузки ЦП в Linux с использованием/proc/stat вопрос, который указывает на ту же проблему, - что большинство других вопросов принимают во внимание только 4 из многих полей - но все же Ответ, приведенный здесь, начинается с "Я думаю" (не уверен), и, кроме того, он касается только первых 7 полей (из 10 в /proc/stat/)

This Скрипт Perl использует все поля для вычисления загрузки ЦП, что, опять же, я не считаю правильным после некоторого дальнейшего исследования.

После быстрого просмотра кода ядра здесь это выглядит, например, как guest_Nice а также guest fields всегда увеличиваются вместе с Nice и ​​user (поэтому их не следует включать в расчет использования процессора, поскольку они включены в 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;
    }
}

Итак, чтобы подвести итог, каков точный способ расчета загрузки ЦП в Linux и какие поля следует учитывать в вычислениях и как (какие поля относятся к времени простоя, а какие к времени простоя)?

49
Vangelis Tasoulas

Согласно исходному коду htop на момент написания, мои предположения выглядят так:

(см. 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;

И так, из полей, перечисленных в первой строке /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

Алгоритмически мы можем рассчитать процент использования процессора, например:

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

Ниже приведен скрипт 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
9
Fidel

Привет, я также исследовал эту тему и нашел эту тему действительно полезной. Я использовал формулу Вангелиса Тасуласа для написания небольшого сценария python для этого. Прикреплен мой код Python для этой проблемы. Он загружает использование ЦП на cpu_id каждую секунду). Может быть, это помогает другим. Также приветствуются комментарии/предложения :-)

#!/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 имеет хорошее описание того, как использовать данные процессора/proc/stat, включает bash-скрипт для извлечения процессора и описание строк. Я просто хотел связать это здесь, так как я нашел это ценным.

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