Script to get CPU usage in percentage

Hey,

I want to share an amateurish bash script to check CPU usage on containers in percentage.

#!/bin/bash
getCpuTime() {
    cpuStatPath="/sys/fs/cgroup/lxc.payload.$1/cpu.stat"

    if [ -f "$cpuStatPath" ]
    then
        cat /sys/fs/cgroup/lxc.payload.$1/cpu.stat |head -n1 |awk '{print $2}';
    else
        cat /sys/fs/cgroup/cpuacct/lxc.payload.$1/cpuacct.usage
    fi
}

getTimeConvert() {
    cpuStatPath="/sys/fs/cgroup/lxc.payload.$1/cpu.stat"
    if [ -f "$cpuStatPath" ]
    then
        echo "1000000"
    else
        echo "1000000000"
    fi
}

getCpuCores() {
    cpuCoresLxd=$(lxc config show $1 |grep limits.cpu |awk '{print $2}' |tr -d '"' |bc)
    if [[ "$cpuCoresLxd" == *"-"* ]]
    then
      echo "($cpuCoresLxd * -1) + 1" |bc
    fi
}

getPercentage() {
    container=$1
    cpuCoresLxd=$(getCpuCores $container)
    cpu_usage=$(getCpuTime $container)
    sleep 1
    cpu_usage_after=$(getCpuTime $container)
    total_cpu_time=$((cpu_usage_after - cpu_usage))
    timeConvert=$(getTimeConvert $container)
    cpu_percentage=$(echo "scale=2; ($total_cpu_time / $timeConvert) / $cpuCoresLxd * 100" | bc )

    echo "$container - $cpu_percentage%"
}

containers=($(lxc list --format=json | jq -r '.[] | select(.state.status == "Running") | .name'))

for container in "${containers[@]}"
do
    getPercentage ${container} &
done

wait

Works from LXD 4.X. Yesterday i’ve tested it with INCUS and it works as well. If you use incus you just need to change “lxc config show” to “incus config show” on line 51

Hope it helps someone.

root@hostMachine1:~# ./cpu.sh
web01 - 0%
web02 - 0%
cache01 - 9.00%
db02 - 0%
web03 - 0%
db01 - 50.00%
lb01 - 4.00%
queue01 - 24.00%
2 Likes

Thanks for sharing, this is useful to me when running multiple different containers with heavy workloads. I want to point out that if you haven’t configured limits.cpu to your containers, this script will error out. I usually try to limit loads using limits.cpu.allowance instead.

I think I “fixed” it with this:

$ diff -Naur 1.orig.sh 1.sh 
--- 1.orig.sh   2024-01-13 10:44:42.759531544 +0200
+++ 1.sh        2024-01-13 10:45:13.400079103 +0200
@@ -1,4 +1,5 @@
 #!/bin/bash
+
 getCpuTime() {
     cpuStatPath="/sys/fs/cgroup/lxc.payload.$1/cpu.stat"
 
@@ -21,11 +22,7 @@
 }
 
 getCpuCores() {
-    cpuCoresLxd=$(lxc config show $1 |grep limits.cpu |awk '{print $2}' |tr -d '"' |bc)
-    if [[ "$cpuCoresLxd" == *"-"* ]]
-    then
-      echo "($cpuCoresLxd * -1) + 1" |bc
-    fi
+       echo $(nproc)
 }
 
 getPercentage() {

At least the results seem to make sense, and overall CPU percentage is 99 % :slight_smile:

Nice one @konstantin.hristov.

However can you please explain me the getTimeConvert part?

Converts from miliseconds or nanoseconds to seconds. I believe that the difference is in cgroup version