4.5 KiB
cputild - CPU Idle Time Monitor
Overview
cputild is a lightweight daemon that continuously monitors CPU utilization by reading from /proc/stat and writes the current CPU usage percentage to /tmp/cputild. It's designed to run as a background service on Linux systems, providing real-time CPU metrics suitable for other tools to consume.
Features
- Continuous Monitoring: Reads CPU statistics every second
- Accurate Calculation: Uses jiffies-based delta calculation for precise utilization
- Signal Handling: Gracefully responds to
SIGINT(Ctrl+C) for clean shutdown - Daemon Ready: Includes systemd service configuration for production use
- Efficient I/O: Reopens files on each iteration for volatile data sources
Requirements
- Operating System: Linux (requires
/proc/statsupport) - Build Tools: CMake 3.31+, GCC or compatible C11 compiler
- Systemd: For service management (optional)
Building the Project
Prerequisites
sudo apt install cmake build-essential # Debian/Ubuntu
sudo yum install cmake gcc # Fedora/CentOS
Build Process
# Using the install script (recommended for production)
./install.sh
# Or manual build
mkdir build && cd build
cmake -S ../.. -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build .
# Optional: sudo cmake --install ../.. --prefix /usr/local
Build Options
The CMakeLists.txt supports multiple build types:
- Debug (default): For development and debugging
- Release: Optimized without debug symbols
- RelWithDebInfo (used by install.sh): Optimized with debug info
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
Installation
Automated Installation
The provided install.sh script handles the complete installation process:
./install.sh
This script will:
- Create a temporary build directory
- Configure and build the project with
CMake - Install the binary to
/usr/local/bin/cputild - Copy and enable the systemd service
- Reload systemd daemon
Manual Installation
sudo cmake --install build --prefix /usr/local
sudo cp cputild.service /etc/systemd/system/cputild.service
sudo systemctl daemon-reload
sudo systemctl enable cputild.service
sudo systemctl start cputild.service
Systemd Service
Service Behavior
When running as a systemd service, cputild:
- Starts automatically on boot (if enabled)
- Restarts on failure (
Restart=on-failure) - Responds to
SIGINTfor graceful shutdown
Management Commands
# Enable service (start on boot)
sudo systemctl enable cputild.service
# Start service
sudo systemctl start cputild.service
# Check status
sudo systemctl status cputild.service
# Stop service
sudo systemctl stop cputild.service
# Restart service
sudo systemctl restart cputild.service
# View logs
sudo journalctl -u cputild.service
How It Works
Algorithm
- Read CPU statistics from
/proc/stat(in jiffies) - Parse the first line:
cpu user nice system idle iowait irq softirq steal guest guest_nice - Calculate active time = user + nice + system + irq + softirq + steal + guest + guest_nice
- Calculate idle time = iowait + idle
- Compute delta (difference) since last measurement
- Derive utilization = active_delta / (active_delta + idle_delta) × 100
- Write result to
/tmp/cputild(percentage, 2 decimal places)
Output Format
/tmp/cputild: 45.23
The file contains only the number (no newline) for easy parsing by other tools.
Signal Handling
The program uses a simple volatile flag pattern for signal handling:
| Signal | Effect |
|---|---|
SIGINT (Ctrl+C) |
Gracefully sets running=0 and terminates |
Troubleshooting
Permission Issues
# If you cannot write to /tmp/cputild
sudo chmod 666 /tmp
Systemd Service Not Starting
# Check for errors
sudo systemctl status cputild.service -l
# Check journal logs
sudo journalctl -xeu cputild.service
Manual Test
# Test in foreground
/usr/local/bin/cputild
# Verify output
cat /tmp/cputild
File Structure
cputild/
├── CMakeLists.txt # Build configuration
├── install.sh # Installation script
├── cputild.service # systemd unit file
└── main.c # Source code
Author
Linus Vogel linus@linvogel.ch
License
Free to use and modify.
Disclaimer
I have used an LLM to help with formulating most of the comments as well as this README file. The actual code I have written myself.