How to Calculate CPU Utilization Percentage from a Single Read of /proc/stat in Linux


2 views

The first line of /proc/stat provides cumulative CPU time counters since system boot, divided into various states:

cpu  67891300 39035 6949171 2849641614 118251644 365498 2341854 0 0 0

The columns represent (in order):

  • user: normal processes in user mode
  • nice: niced processes in user mode
  • system: processes in kernel mode
  • idle: idle time (includes iowait on older kernels)
  • iowait: waiting for I/O
  • irq: servicing interrupts
  • softirq: servicing softirqs
  • steal: stolen time (virtualized environments)
  • guest: running guest OS
  • guest_nice: running niced guest

While accurate percentage calculation typically requires two samples, you can estimate current utilization with these steps:

# Sample Python implementation
def calculate_cpu_util(stat_line):
    fields = [int(x) for x in stat_line.split()[1:]]
    # Calculate total non-idle time
    non_idle = fields[0] + fields[1] + fields[2] + fields[4] + fields[5] + fields[6]
    # Calculate total time (including idle)
    total = sum(fields[:7])
    # Return percentage (0-100)
    return (non_idle / total) * 100 if total > 0 else 0

This approach makes several assumptions:

  1. All CPU states are accounted for in the sum of fields
  2. I/O wait should be considered as non-idle time (varies by use case)
  3. The percentage represents utilization since system boot

For more accurate results when only one sample is available:

# Bash implementation
read -r cpu user nice system idle iowait irq softirq steal guest guest_nice <<< $(head -n1 /proc/stat)
total=$((user + nice + system + idle + iowait + irq + softirq + steal))
used=$((total - idle - iowait)) # Exclude idle and iowait
echo "CPU Usage: $((100 * used / total))%"

When implementing this in production:

  • Cache the previous sample when possible
  • Handle counter overflow (unlikely on modern systems)
  • Consider SMP systems (per-core stats available in /proc/stat)
  • Account for containerized environments (different accounting methods)

The Linux kernel exposes CPU statistics through the /proc/stat pseudo-file, which provides a wealth of information about system resource usage. The first line represents aggregate CPU activity across all cores, with subsequent lines showing per-core statistics.

# Example /proc/stat output
cpu  67891300 39035 6949171 2849641614 118251644 365498 2341854 0

The columns represent different CPU states (in units of USER_HZ, typically 100Hz):

  • user: Normal processes in user mode
  • nice: Niced processes in user mode
  • system: Processes in kernel mode
  • idle: Idle time (includes iowait on older kernels)
  • iowait: Waiting for I/O completion
  • irq: Hardware interrupt servicing
  • softirq: Software interrupt servicing
  • steal: Time stolen by hypervisor

Here's a Python implementation to calculate CPU usage percentage from a single read of /proc/stat:

def get_cpu_utilization():
    with open('/proc/stat') as f:
        line = f.readline()
    
    fields = [float(column) for column in line.strip().split()[1:]]
    
    # Calculate total time (excluding guest and guest_nice which are included in user/nice)
    total_time = sum(fields[:8])
    
    # Calculate idle time (idle + iowait)
    idle_time = fields[3] + fields[4]
    
    # Calculate non-idle time
    non_idle_time = total_time - idle_time
    
    # Calculate percentage
    utilization = (non_idle_time / total_time) * 100
    
    return round(utilization, 2)

Several factors affect the accuracy of this approach:

  • For multi-core systems, you might want to calculate per-core utilization
  • The values represent time since boot, so for most use cases you'll want to sample twice with a delay
  • On modern kernels, iowait is not counted as idle time
  • Virtualization environments may show significant steal time

If you absolutely must calculate from a single read, you can estimate utilization by comparing against the system uptime:

import time

def estimate_cpu_utilization():
    with open('/proc/stat') as f:
        stat_line = f.readline()
    with open('/proc/uptime') as f:
        uptime_seconds = float(f.readline().split()[0])
    
    fields = [float(col) for col in stat_line.strip().split()[1:8]]
    total_jiffies = sum(fields)
    jiffies_per_second = total_jiffies / uptime_seconds
    
    idle_jiffies = fields[3] + fields[4]
    utilization = 100 * (1 - (idle_jiffies / total_jiffies))
    
    return round(utilization, 2)

For production monitoring systems, consider these optimizations:

  • Cache the /proc/stat file handle if reading frequently
  • Use binary parsing for better performance
  • Consider using the psutil library which handles these calculations internally