/proc & /sys Observability

Every monitoring tool — Prometheus node_exporter, Datadog, Grafana — reads from /proc and /sys. Learning to read these directly means you can diagnose problems on any Linux system with no tools installed, and understand exactly what your monitoring stack is actually measuring.

/proc/stat — CPU Utilization

cat /proc/stat # cpu user nice system idle iowait irq softirq steal guest guest_nice # cpu 123456 789 23456 987654 3456 0 234 0 0 0 # cpu0 61728 400 11728 493827 1728 0 117 0 0 0 # cpu1 61728 389 11728 493827 1728 0 117 0 0 0 # Values are in jiffies (typically 1/100th second = 10ms each) # To get CPU percentage: # Read /proc/stat twice, 1 second apart # delta_idle = idle2 - idle1 # delta_total = (user+nice+system+idle+iowait+irq+softirq)2 - ...1 # CPU% = 100 * (1 - delta_idle / delta_total) # Also in /proc/stat: # ctxt NNN = total context switches since boot # btime NNN = boot time (Unix timestamp) # processes N = total forks since boot # procs_running N = currently running (not sleeping) # procs_blocked N = in uninterruptible sleep (D state)

/proc/meminfo — Memory State

cat /proc/meminfo # MemTotal: 32768000 kB = physical RAM # MemFree: 1234568 kB = completely unused # MemAvailable: 18432000 kB = available for new processes (USE THIS) # Buffers: 512000 kB = filesystem metadata cache # Cached: 14000000 kB = file page cache # Dirty: 123456 kB = modified pages not yet on disk # Writeback: 1234 kB = currently being written to disk # AnonPages: 5000000 kB = anonymous (malloc, stack) # Mapped: 1500000 kB = mmapped files # Shmem: 200000 kB = shared memory # Slab: 987654 kB = kernel slab allocator # SReclaimable: 654321 kB = slab pages that can be freed # SUnreclaim: 333333 kB = slab pages that cannot be freed # CommitLimit: 33554432 kB = max committable memory (overcommit) # Committed_AS: 20000000 kB = total committed (promised) memory # Key formula: # Real free = MemAvailable (not MemFree) # Used by processes = AnonPages + Mapped # Kernel used = Slab + PageTables + KernelStack

/proc/diskstats — Disk I/O Stats

cat /proc/diskstats # 8 0 sda 12345 678 98765 43210 5678 910 45678 21098 0 30000 64308 # ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ # | | | | | | | | | io_ticks # | | | | | | | | time_io_ms # | | | | | | | writes_ms # | | | | | | write_sectors # | | | | | writes # | | | | reads_ms # | | | read_sectors # | | reads_merged # | reads # minor # Key derived metrics: # I/O utilization = io_ticks / total_time (100% = fully saturated) # Read latency = reads_ms / reads (ms per read) # Write latency = writes_ms / writes (ms per write) # These are what iostat -x shows # iostat uses /proc/diskstats: iostat -x 1 # Device r/s w/s rkB/s wkB/s await util% # sda 50 200 6400 51200 8.5 67.3

/proc/schedstat and /proc/PID/schedstat

# Per-CPU scheduler statistics: cat /proc/schedstat # version 15 # cpu0 0 0 0 0 0 0 12345678 9876543 123456 # ^ ^ ^ # | | nr_running_total # | wait_start # run_delay_ns (total time waited for CPU) # Per-process scheduler stats: cat /proc/1234/schedstat # 12345678 9876543 100 # ^ ^ ^ # | | timeslices run # | wait_time_ns (time waiting for CPU) # run_time_ns (time on CPU) # High wait_time relative to run_time = CPU contention # Process wants to run but can't get CPU time # See scheduler info for a process: cat /proc/1234/sched # nginx (1234, #threads: 4) # se.exec_start : 12345678.901234 # se.vruntime : 4567890.123456 # se.sum_exec_runtime : 12345.678901 (ms on CPU) # nr_voluntary_switches : 98765 (voluntarily yielded CPU) # nr_involuntary_switches : 1234 (preempted — ran out of time slice)

/sys/block — Real-Time I/O Monitoring

# Device queue depth and saturation: cat /sys/block/sda/queue/nr_requests # queue depth cat /sys/block/sda/stat # same as diskstats # Instantaneous queue depth (pending I/Os): cat /sys/block/sda/inflight # reads writes # 0 3 ← 3 writes currently in flight # CPU frequency scaling (thermal throttling check): for cpu in /sys/devices/system/cpu/cpu*/; do echo -n "$(basename $cpu): " cat ${cpu}cpufreq/scaling_cur_freq 2>/dev/null || echo "no cpufreq" done # cpu0: 2400000 (2.4GHz — may be lower than max if throttling) # cpu1: 3200000 (3.2GHz — at max) # Check for CPU throttling events: cat /sys/devices/system/cpu/cpu0/thermal_throttle/core_throttle_count