Even with optimal hardware settings, a server’s idle power depends heavily on what software is running. Every service, timer, and polling loop prevents the CPU from entering deep sleep states. This chapter covers the software hygiene that keeps idle power low.
The CPU can only enter a deep package C-state (PC6, PC7, PC8) when all cores are idle simultaneously and no device has requested a low-latency wakeup. Any of the following blocks deep C-states:
hrtimer, jiffies timer)The wakeup rate visible in powertop is the direct indicator. The goal for a lightly loaded server is fewer than 50 wakeups per second.
Start by listing active services and their CPU usage:
systemctl list-units --type=service --state=running
systemd-cgtop --depth=5 # real-time CPU/memory by cgroup
Identify services you do not actually need and disable them:
sudo systemctl disable --now avahi-daemon # mDNS, rarely needed on servers
sudo systemctl disable --now cups # printing
sudo systemctl disable --now ModemManager # cellular modem management
sudo systemctl disable --now bluetooth # if no BT hardware/use
Check service CPU accounting:
import subprocess, json
def get_service_cpu():
result = subprocess.run(
["systemctl", "show", "--all", "--output=json"],
capture_output=True, text=True
)
# parse and filter by CPUUsageNSec > 0
for line in result.stdout.splitlines():
if "CPUUsageNSec" in line and '"0"' not in line:
print(line.strip())
get_service_cpu()
The full systemd accounting script using the D-Bus API is in code/systemd_power_audit.py.
Many services use their own timer loop. systemctl list-timers shows all active systemd timers:
systemctl list-timers --all
Look for timers that fire very frequently (every minute or more often). For background maintenance tasks that do not need sub-hourly precision, consolidate:
# /etc/systemd/system/my-task.timer
[Unit]
Description=Daily maintenance task
[Timer]
OnCalendar=daily
RandomizedDelaySec=3600 # spread across an hour to avoid thundering herd
Persistent=true # run if missed (e.g., server was off)
[Install]
WantedBy=timers.target
# /etc/systemd/system/my-task.service
[Unit]
Description=Maintenance task
[Service]
Type=oneshot
ExecStart=/usr/local/bin/my-task.sh
CPUSchedulingPolicy=idle # run at idle priority, won't preempt other work
IOSchedulingClass=idle
Using CPUSchedulingPolicy=idle and IOSchedulingClass=idle ensures the task only runs when the system is genuinely idle, minimizing its impact on latency and power.
HDDs draw 4–8 W while spinning and 0.8–1.5 W when parked. For servers that access the disk infrequently (e.g., media servers accessed only a few times per day), spindown can save significant power.
# Set Advanced Power Management (APM) level: 1 = aggressive spindown, 128 = balanced, 254 = off
sudo hdparm -B 128 /dev/sda
# Set spindown timeout: value × 5 seconds (e.g., 120 = 600 s = 10 minutes)
sudo hdparm -S 120 /dev/sda
# Check current APM level
sudo hdparm -B /dev/sda
To make persistent, add to /etc/hdparm.conf:
/dev/sda {
apm = 128
spindown_time = 120
}
Warning: Frequent spinup/spindown cycles wear out drive bearings. Only enable spindown if your workload genuinely has long idle periods (30+ minutes). For NVMe SSDs, spindown is not applicable — NVMe uses runtime power management instead.
Network activity prevents the NIC from entering power-saving states and generates interrupts that wake the CPU. For a low-power server:
Disable unnecessary network protocols:
sudo systemctl disable --now avahi-daemon # mDNS discovery
sudo systemctl disable --now cups-browsed # printer discovery
NIC power saving: Enable Wake-on-LAN only if needed; the NIC draws more power to monitor for magic packets.
# Disable WoL (saves ~0.2 W on some NICs)
sudo ethtool -s eth0 wol d
# Enable NIC power saving (may increase latency)
sudo ethtool -s eth0 autoneg on
Reduce log noise: syslog and journald I/O from verbose applications can keep the disk awake. Rate-limit noisy services:
# /etc/systemd/journald.conf
[Journal]
RateLimitIntervalSec=30s
RateLimitBurst=1000
For servers that are sometimes plugged into AC and sometimes running on UPS battery, systemd can run different service configurations:
[Service]
# Only start this high-power optional service when on AC power
ConditionACPower=true
Combined with a systemd target triggered by power source detection (via udev rules for /sys/class/power_supply/), you can build a server that automatically reduces its workload when on battery.
| ← Chapter 10: NUC and Small Server BIOS and Idle Tuning | Table of Contents | Chapter 12: Cross-Platform Power Monitoring and Automation → |