Как получить использование процессора для каждого ядра с помощью сценария bash с использованием стандартных инструментов * nix

Я пишу скрипт bash для печати статистики системы в моей строке состояния dwm с помощью xsetroot . Все работает так, как ожидалось. То, что я в настоящее время отсутствует, – это простой способ, который просто использует стандартные инструменты *nix , чтобы дать мне текущую нагрузку для каждого ядра в моей системе (у меня есть 4 ядра). Я не могу понять, как это сделать, например, с помощью top . Все остальные сообщения, которые я нашел на этом сайте, до сих пор имеют дело со средней нагрузкой. Кто-нибудь делал это раньше?

Основная причина, по которой я хочу это для каждого ядра, – иметь дешевый и грубый инструмент, чтобы проверить, работает ли в программе какой-то код, который я написал параллельно (например, для каждого цикла).

Это создает массив bash, элементами которого являются нагрузки для каждого процессора:

 loads=($(mpstat -P ALL 1 1 | awk '/Average:/ && $2 ~ /[0-9]/ {print $3}')) 

Поскольку массивы bash нумеруются начиная с нуля, загрузка второго CPU будет напечатана с помощью:

 echo ${loads[1]} 

Для этого требуется утилита mpstat . Чтобы установить его на подобную debian системе, запустите:

 apt-get install sysstat 

Как это работает

Несколько подробный вывод, созданный mpstat выглядит так:

 $ mpstat -P ALL 1 1 Linux 3.2.0-4-amd64 (MyMachine) 08/30/2014 _x86_64_ (2 CPU) 10:12:35 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle 10:12:36 PM all 1.49 0.00 1.49 0.00 0.00 0.00 0.00 0.00 97.01 10:12:36 PM 0 0.00 0.00 2.02 0.00 0.00 0.00 0.00 0.00 97.98 10:12:36 PM 1 1.96 0.00 1.96 0.00 0.00 0.00 0.00 0.00 96.08 Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle Average: all 1.49 0.00 1.49 0.00 0.00 0.00 0.00 0.00 97.01 Average: 0 0.00 0.00 2.02 0.00 0.00 0.00 0.00 0.00 97.98 Average: 1 1.96 0.00 1.96 0.00 0.00 0.00 0.00 0.00 96.08 

где -P ALL сообщает mpstat чтобы показать все cpus, и аргументы 1 1 говорят ему, чтобы печатать выходные данные каждую секунду и останавливаться после первой секунды.

Чтобы выбрать только те значения, которые мы хотим, эта команда awk используется:

 awk '/Average:/ && $2 ~ /[0-9]/ {print $3}' 

Это выбирает только конечные строки (те, которые начинаются со Average: и, среди них, выбирают только те, чей второй столбец является числовым. Для этих строк печатается третий столбец (загрузка процессора).

Из-за использования круглых скобок вывод из mpstat awk захватывается в массив bash.

Вычисление среднего значения для основного использования из /proc/stat

Лучшее решение, которое я выбрал до сих пор, использует bc для учета арифметики с плавающей запятой:

 # Calculate average cpu usage per core. # user nice system idle iowait irq softirq steal guest guest_nice # cpu0 30404 2382 6277 554768 6061 0 19 0 0 0 A=($(sed -n '2,5p' /proc/stat)) # user + nice + system + idle B0=$((${A[1]} + ${A[2]} + ${A[3]} + ${A[4]})) B1=$((${A[12]} + ${A[13]} + ${A[14]} + ${A[15]})) B2=$((${A[23]} + ${A[24]} + ${A[25]} + ${A[26]})) B3=$((${A[34]} + ${A[35]} + ${A[36]} + ${A[37]})) sleep 2 # user + nice + system + idle C=($(sed -n '2,5p' /proc/stat)) D0=$((${C[1]} + ${C[2]} + ${C[3]} + ${C[4]})) D1=$((${C[12]} + ${C[13]} + ${C[14]} + ${C[15]})) D2=$((${C[23]} + ${C[24]} + ${C[25]} + ${C[26]})) D3=$((${C[34]} + ${C[35]} + ${C[36]} + ${C[37]})) # cpu usage per core E0=$(echo "scale=1; (100 * ($B0 - $D0 - ${A[4]} + ${C[4]}) / ($B0 - $D0))" | bc) E1=$(echo "scale=1; (100 * ($B1 - $D1 - ${A[15]} + ${C[15]}) / ($B1 - $D1))" | bc) E2=$(echo "scale=1; (100 * ($B2 - $D2 - ${A[26]} + ${C[26]}) / ($B2 - $D2))" | bc) E3=$(echo "scale=1; (100 * ($B3 - $D3 - ${A[37]} + ${C[37]}) / ($B3 - $D3))" | bc) echo $E0 echo $E1 echo $E2 echo $E3 

Среднее значение cpu на ядро ​​может быть непосредственно вычислено из /proc/stat (Credits to @mikeserv для подсказки для использования /proc/stat .):

 # Here we make use of bash direct array assignment A0=($(sed '2q;d' /proc/stat)) A1=($(sed '3q;d' /proc/stat)) A2=($(sed '4q;d' /proc/stat)) A3=($(sed '5q;d' /proc/stat)) # user + nice + system + idle B0=$((${A0[1]} + ${A0[2]} + ${A0[3]} + ${A0[4]})) B1=$((${A1[1]} + ${A1[2]} + ${A1[3]} + ${A1[4]})) B2=$((${A2[1]} + ${A2[2]} + ${A2[3]} + ${A2[4]})) B3=$((${A3[1]} + ${A3[2]} + ${A3[3]} + ${A3[4]})) sleep 0.2 C0=($(sed '2q;d' /proc/stat)) C1=($(sed '3q;d' /proc/stat)) C2=($(sed '4q;d' /proc/stat)) C3=($(sed '5q;d' /proc/stat)) # user + nice + system + idle D0=$((${C0[1]} + ${C0[2]} + ${C0[3]} + ${C0[4]})) D1=$((${C1[1]} + ${C1[2]} + ${C1[3]} + ${C1[4]})) D2=$((${C2[1]} + ${C2[2]} + ${C2[3]} + ${C2[4]})) D3=$((${C3[1]} + ${C3[2]} + ${C3[3]} + ${C3[4]})) # cpu usage per core E0=$(((100 * (B0 - D0 - ${A0[4]} + ${C0[4]})) / (B0 - D0))) E1=$(((100 * (B1 - D1 - ${A1[4]} + ${C1[4]})) / (B1 - D1))) E2=$(((100 * (B2 - D2 - ${A2[4]} + ${C2[4]})) / (B2 - D2))) E3=$(((100 * (B3 - D3 - ${A3[4]} + ${C3[4]})) / (B3 - D3))) echo $E0 echo $E1 echo $E2 echo $E3 

или даже короче, широко используя назначение прямого массива bash:

 # Here we make use of bash direct array assignment by assigning line # 2 to 4 to one array A=($(sed -n '2,5p' /proc/stat)) # user + nice + system + idle B0=$((${A[1]} + ${A[2]} + ${A[3]} + ${A[4]})) B1=$((${A[12]} + ${A[13]} + ${A[14]} + ${A[15]})) B2=$((${A[23]} + ${A[24]} + ${A[25]} + ${A[26]})) B3=$((${A[34]} + ${A[35]} + ${A[36]} + ${A[37]})) sleep 0.2 # user + nice + system + idle C=($(sed -n '2,5p' /proc/stat)) D0=$((${C[1]} + ${C[2]} + ${C[3]} + ${C[4]})) D1=$((${C[12]} + ${C[13]} + ${C[14]} + ${C[15]})) D2=$((${C[23]} + ${C[24]} + ${C[25]} + ${C[26]})) D3=$((${C[34]} + ${C[35]} + ${C[36]} + ${C[37]})) # cpu usage per core E0=$((100 * (B0 - D0 - ${A[4]} + ${C[4]}) / (B0 - D0))) E1=$((100 * (B1 - D1 - ${A[15]} + ${C[15]}) / (B1 - D1))) E2=$((100 * (B2 - D2 - ${A[26]} + ${C[26]}) / (B2 - D2))) E3=$((100 * (B3 - D3 - ${A[37]} + ${C[37]}) / (B3 - D3))) echo $E0 echo $E1 echo $E2 echo $E3 

top решения

Это также может быть достигнуто без установки дополнительного инструмента только top (я использовал это в более позднем сообщении .) По умолчанию top индекс показывает только среднюю загрузку процессора, когда он запущен, но при нажатии 1 будет отображаться весь cpus. Чтобы иметь возможность использовать вывод top cpu, когда мы используем его в режиме пакетного вывода, нам нужно будет сделать это по умолчанию при запуске top . Это можно сделать, используя файл ~/.toprc . К счастью, это может быть автоматически создано: Начните top нажатие 1 и нажмите W который сгенерирует файл ~/.toprc в вашей домашней папке. Когда вы теперь используете top -bn 1 | grep -F '%Cpu' top -bn 1 | grep -F '%Cpu' вы увидите, что top теперь выводит все ваши ядра. Теперь у нас уже есть все, что нужно для этой работы. Вся необходимая мне информация находится в столбце 3 массива, который будет выводить top .

Существует только одна проблема: когда использование процессора для ядра достигает 100% массив, который выводит команды, перемещает столбец с текущей нагрузкой из столбца 3 в столбец 2 . Следовательно, с awk '{print $3}' вы увидите us, как вывод для столбца 3 . Если с тобой все в порядке, оставь это. Если бы у вас не было awk print column 2 . Это будет просто : Решение, которое позволяет избежать всех этих ошибок:

 top -bn 2 | grep -F '%Cpu' | tail -n 4 | gawk '{print $2 $3}' | tr -s '\n\:\,[:alpha:]' ' ' 

он выводит вывод всех строк новой строки \n , и букв [:alpha:] и удаляет все, кроме одного пробела -s .

Я придумал это решение, и оно работает для меня.

 echo print `top -n 1 | tr -s " " | cut -d$" " -f10 | tail -n +8 | head -n -1 | paste -sd+ | bc`/ `nproc` | python 

Источник (напишите): https://mohammadg.com/programming/how-to-get-overall-cpu-utilization-from-the-bash-command-line/

вы можете увидеть частоту для каждого ядра следующим образом:

 $ cat /proc/cpuinfo