Получить нагрузку на процессор для каждого ядра в сценарии оболочки

$ cat ip.txt 
test1,test2,test3
test4,test5
test6,test7,test8,test9,test10
test11,test12,test13,test14
test15

$ perl -F, -ane 'print "$F[0]"; print ",".join(";",@F[1..$#F]) if($#F > 0)' ip.txt 
test1,test2;test3
test4,test5
test6,test7;test8;test9;test10
test11,test12;test13;test14
test15


Другой способ:

perl -F'/(,)/,$_,2' -ane '$F[2] =~ s/,/;/g; print @F'
  • /(,)/,$_,2 разделить $_ (строка ввода) на две части на основе , Поскольку используется (,), он захватывает и разделитель, в результате чего получается три элемента, как объяснено ниже
  • $F[0] получает первое поле, $F[1] получит ,, если присутствует
  • $F[2] получит оставшиеся поля, если присутствуют


Еще один способ, эмулирующий sed 's/,/; /2g'

perl -pe '$c=0; s/,/++$c<2 ? $& : ";"/ge' ip.txt
  • инициализируем счетчик для каждой строки
  • при замене проверяем значение счетчика по мере необходимости
  • модификатор e позволяет использовать Perl код в секции замены
2
30.09.2016, 09:45
5 ответов

Оказалось, что некоторые MIB, установленные на RedHat, предоставляют всю необходимую информацию. Поскольку моя цель - предоставить эти значения под OID через SNMP, я могу использовать SNMP и обработать информацию.

Среднее значение для всех процессоров вычисляется как 100-idle:

function allCpuLoad {
    # get system idle value from
    # snmpget -v2c -cmdaf localhost UCD-SNMP-MIB::ssCpuIdle.0
    # UCD-SNMP-MIB::ssCpuIdle.0 = INTEGER: 93
    # and compute load by substracting it from 100.0 
    snmpget -v2c -cmdaf localhost UCD-SNMP-MIB::ssCpuIdle.0|cut -f4 -d' '| awk '{printf "%d", 100 - $1}'
}

Мы можем использовать snmpwalk для получения нагрузки всех отдельных процессоров, а затем извлечь максимальное значение:

function maxCpuLoad {
    # get load of all cpus
    # snmpwalk -v2c -cmdaf localhost HOST-RESOURCES-MIB::hrProcessorLoad
    # HOST-RESOURCES-MIB::hrProcessorLoad.196608 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196609 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196610 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196611 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196612 = INTEGER: 6
    # HOST-RESOURCES-MIB::hrProcessorLoad.196613 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196614 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196615 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196616 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196617 = INTEGER: 27
    # HOST-RESOURCES-MIB::hrProcessorLoad.196618 = INTEGER: 4
    # HOST-RESOURCES-MIB::hrProcessorLoad.196619 = INTEGER: 0
    # HOST-RESOURCES-MIB::hrProcessorLoad.196620 = INTEGER: 1
    # HOST-RESOURCES-MIB::hrProcessorLoad.196621 = INTEGER: 0
    # HOST-RESOURCES-MIB::hrProcessorLoad.196622 = INTEGER: 0
    # HOST-RESOURCES-MIB::hrProcessorLoad.196623 = INTEGER: 1
    # and get maximum value only
    snmpwalk -v2c -cmdaf localhost HOST-RESOURCES-MIB::hrProcessorLoad|cut -f 4 -d' '|sort -n -r|head -n1
}
1
27.01.2020, 21:54
mpstat -P ALL -u | tail -n +5 | awk '{print (100-$12)}'

объяснение:

mpstat

сообщает статистику процессора

-P ALL

для всех ядер

-u

показывает использование (статистика из / proc вместо текущих измерений)

tail -n +5 

начинается со строки 5

awk '{print (100-$12)}'

выведите 12-е значение каждой строки, вычтенной из 100

1
27.01.2020, 21:54

Есть несколько способов выполнить подсекундный опрос загрузка процессора либо с помощью утилиты, такой как dstat (пример ниже), либо путем прямого опроса / proc / stat (пример также ниже).

Давайте рассмотрим плюсы и минусы обоих, прежде чем переходить к техническим примеры.

Чтобы использовать dstat, вам нужно будет запустить быстрый crontab (* / 1 * * * *) и передать результат в файл статистики, который вы можете проверить. Положительным моментом является то, что ваши таймауты SNMP не превышаются проблема, обратная сторона, это не совсем мгновенно, и запуск crontab, когда вы на самом деле не ищете эти данные, оказывает влияние. Воздействие может быть незначительным, но все же Это здесь.

Чтобы использовать / proc / stat, вы должны дважды опросить содержимое / proc / stat. Содержимое / proc / stat накапливается с момента загрузки. Таким образом, результаты первого и второго опроса необходимо вычесть друг из друга, а затем можно будет выполнить расчет для текущей нагрузки. Обратной стороной является то, что для выполнения этого расчета должна быть какая-то задержка. В приведенном ниже примере я уменьшил задержку до долей секунды. Это отвечало бы вашим потребностям, однако образцы данных настолько близки друг к другу, что я не уверен, насколько абсолютна их точность.

Использование dstat; Добавьте эту строку в / etc / crontab:

*/1  *  *  *  *  root    echo $((100-`dstat -c -C0 --noheaders --nocolor 1 1 | grep -v "\-\|u" | awk 'NR == 2' | tr -s " " | cut -d \  -f 4`)) > /tmp/cpuload

Это обновляется только раз в минуту. Если вы хотите более частые обновления, добавьте вторую строку и добавьте к команде предисловие sleep 30, например

*/1  *  *  *  *   root    sleep 30; echo $((100-`dstat -c -C0 --noheaders --nocolor 1 1 | grep -v "\-\|u" | awk 'NR == 2' | tr -s " " | cut -d \  -f 4`)) > /tmp/cpuload

. Можно использовать (злоупотреблять) cron еще дальше и получить результаты менее чем за секунду, но это совершенно другая тема.

объяснение:

dstat -c -C 0 --noheaders --nocolor 1 0

-c показать только данные процессора

-C выбрать cpu0. изменить нумерацию для выбора другого процессора

- noheaders --nocolor (подразумевается --noupdate) упростить то, что мы видим

1 задержка в одну секунду при чтении статистики

1 выход после второго чтения статистики. Давая ему время успокоиться после заклинания.

grep -v "- \ | u"

удалить строки без данных

awk 'NR == 2'

выбрать вторую строку.

tr -s ""

обрезать лишние пробелы, которые хорошо смотрятся на экране, но не для системного использования

cut -d \ -f 4

-d \ (после \ (escape) пробел, очерченная строка -f 4 выберите холостой ход. да, визуально это 3, но пробел в начале строки считается полем, отбрасывая счетчик полей.

$ (())

bash арифметические операции, вычитание простоя системы из 100.

Использование / proc / stat;

Сохранить как cpuload.sh;

#!/bin/bash

#Calculation delay. Without a delay, there is no way to determine current 
#values. The content or /proc/stat is cumulitative from last boot.  
# in seconds; sleep must be able to support float values
dly=3

function calculate {

#load arrays
IFS=' ' read -r -a firstarr <<< "$1"
IFS=' ' read -r -a secondarr <<< "$2"

#clear name fields in array so that calculations don't get messy
firstarr[0]=0 ;
secondarr[0]=0 ;

#clear values 
firsttotcpu=0
secondtotcpu=0

#calculate the begining interrupt counts
for f in ${firstarr[@]}; 
    do 
        let firsttotcpu+=$f; 
done
firstidle=$((${firstarr[4]}+${firstarr[5]})); 

#calculate the ending interrupt counts
for l in ${secondarr[@]}; 
    do
        let secondtotcpu+=$l; 
    done; 
secondidle=$((${secondarr[4]}+${secondarr[5]})); 

#calculate the relative change counts
insttotcpu=$(( secondtotcpu - firsttotcpu ))
instidle=$(( secondidle - firstidle ))

#calculate the utilization percentage. must be done external to bash as it's a
#floating calculation
cpu_load=$( echo | awk -v tot=$insttotcpu -v idl=$instidle ' { print ( ( ( tot - idl ) / tot ) * 100 ) } ' )

echo -n $cpu_load " " 


} 
export -f calculate

#main execution

oldIFS=$IFS

IFS=$'\n' cpu_start=( $( grep cpu /proc/stat ) );

#must delay to get difference
sleep $dly

IFS=$'\n' cpu_end=( $( grep cpu /proc/stat ) );

cpucount=${#cpu_start[@]}

#uncomment this for loop to enable printing the cpu name above the percentages
#for i in ${cpu_start[@]};
#    do
#        IFS=' ' read -r -a name <<< "$i"
#        echo -n ${name[0]} " "
#done
#echo ""

for (( i=0; i<$cpucount; i++ ))
    do
        calculate "${cpu_start[$i]}" "${cpu_end[$i]}"

done

echo ""

IFS=$oldIFS
3
27.01.2020, 21:54

Другой способ получить исходные значения - использовать grep cpu0 / proc / stat . Там вы видите количество отметок в каждом состоянии. Выполните man proc , чтобы узнать подробности интерпретации. Если вы хотите получить процентное соотношение, вы должны сложить их вместе и разделить, например, в соответствии с предложением Джона В. Гилла .

2
27.01.2020, 21:54

Вот пример сценария на основе bash (, использующий /proc/stat)с пояснениями. он может работать так быстро, как вам нужно. Сохраните как /tmp/cpuLoad.sh, затем «chmod +x /tmp/cpuLoad.sh» и последний раз запустите :/tmp/cpuLoad.sh

#!/bin/bash

interval=0.25; ##loop interval in seconds

##so settings below
lCpus=(); ##store last readings
lCount=0; ## loop counter

while :; do {

    cCpu=(); ##current cpu
    cCpus=(); ##all cpus
    values=$(grep -E "cpu[0-9]+\s" /proc/stat);
    for value in $values; do {
        if [[ $value =~ ^cpu[0-9]+ ]]; then
            if [[ ${#cCpu[@]} > 0 ]]; then
                cCpus[${cCpu[1]}]="${cCpu[@]}"
            fi

            cCpu[0]=$value; ##name
            cCpu[1]=${#cCpus[@]}; ##cpu index
            cCpu[2]=0; ##cpu idle ticks
            cCpu[3]=0; ##cpu busy ticks
            i=0; ## column index

        else
            ((i=i+1));
            if ([ $i == 4 ] || [ $i == 5 ]); then
                # position 4 is the idle, position 5 is the i/o wait (also idle introduced 2.5.41) src https://www.idnt.net/en-US/kb/941772
                ((cCpu[2]=cCpu[2] + value));
            else
                ((cCpu[3]=cCpu[3] + value));
            fi
        fi
    } done

    ##include the last cpu
    cCpus[${cCpu[1]}]="${cCpu[@]}"

    output="Loop $lCount";
    x=0;
    for cpu in "${cCpus[@]}"; do {
        if [[ $lCount > 0 ]]; then
        
            cCpu=($cpu);
            lCpu=(${lCpus[$x]});
            dTotal=$(((${cCpu[2]} + ${cCpu[3]}) - (${lCpu[2]} + ${lCpu[3]})));
            dUsed=$((dTotal - (${cCpu[2]} - ${lCpu[2]})));
            if [[ $dTotal == 0 ]]; then
                dTotal=1; ##dividing by 0 is never a good idea
            fi
            output="$output, ${cCpu[0]}: $((100 * dUsed / dTotal))%";
        fi
        ##store the reading so we can do a delta next round
        lCpus[$x]=$cpu;
        ((x=x+1));
        
    } done
    
    if [[ $lCount > 0 ]]; then
        echo $output;
    fi
    
    sleep $interval;
    ((lCount=lCount+1));
    
} done
1
14.09.2021, 10:49

Теги

Похожие вопросы