Temat: Automatyczne wyłączanie rdzeni ( parkowanie )
Cześć! W wolnej chwili, korzystając zarówno ze swojej wiedzy, jak i wsparcia AI, przygotowałem skrypt do wyłączania rdzeni procesora. Testuję go na terminalu x86 Futro S920 z 4-rdzeniowym GX424CC, używanym jako router z SQM pod światłowód 1Gb/s.
Skrypt sprawdza średnie obciążenie systemu i jeśli obciążenie jest za duże ( LOAD_UPPER ) to włącza kolejny rdzeń, jeśli się nudzi ( LOAD_LOWER ) zdejmuje. Oczywiście progi można ustawić w skrypcie.
Udało się zmniejszyć pobór energii o około 10W w trybie bezczynności – średnio urządzenie zużywa 16W przy włączonych wszystkich rdzeniach, a przy selektywnym wyłączaniu rdzeni spada do 5–6W. Oczywiście mówimy tu tylko o CPU.
Oczywiście spadły też temperatury
Może komuś się przyda
sensors
radeon-pci-0008
Adapter: PCI adapter
temp1: +56.0°C (crit = +120.0°C, hyst = +90.0°C)
fam15h_power-pci-00c4
Adapter: PCI adapter
power1: 16.88 W (interval = 0.01 s, crit = 25.03 W)
k10temp-pci-00c3
Adapter: PCI adapter
temp1: +56.2°C (high = +70.0°C)
(crit = +100.0°C, hyst = +99.0°C)bez parkowania rdzeni
sensors
radeon-pci-0008
Adapter: PCI adapter
temp1: +56.0°C (crit = +120.0°C, hyst = +90.0°C)
fam15h_power-pci-00c4
Adapter: PCI adapter
power1: 5.53 W (interval = 0.01 s, crit = 25.03 W)
k10temp-pci-00c3
Adapter: PCI adapter
temp1: +55.9°C (high = +70.0°C)
(crit = +100.0°C, hyst = +99.0°C)z parkowaniem
#!/bin/sh
# -------------------------------
# CONFIGURATION CONSTANTS
# -------------------------------
MIN_CORES=1 # Minimal number of cores to keep active
SLEEP_INTERVAL=0 # Seconds to wait between loop iterations
LOAD_UPPER=60 # CPU load % to activate next core
LOAD_LOWER=40 # CPU load % to deactivate highest core
# -------------------------------
# Function to log messages both to terminal and syslog
log_msg() {
msg="$(date '+%H:%M:%S') - $1"
echo "$msg"
logger -t dynamic_cpu "$msg"
}
# Function to validate integer numbers in a range
validate_int_range() {
value="$1"
min="$2"
max="$3"
name="$4"
echo "$value" | grep -qE '^[0-9]+$' || { log_msg "ERROR: $name is not a number"; exit 1; }
if [ "$value" -lt "$min" ] || [ "$value" -gt "$max" ]; then
log_msg "ERROR: $name ($value) is out of range [$min-$max]"
exit 1
fi
}
# Count total CPU cores
TOTAL_CORES=0
for core_path in /sys/devices/system/cpu/cpu[0-9]*; do
TOTAL_CORES=$((TOTAL_CORES + 1))
done
# Validate parameters
validate_int_range "$MIN_CORES" 1 "$TOTAL_CORES" "MIN_CORES"
validate_int_range "$SLEEP_INTERVAL" 0 3600 "SLEEP_INTERVAL"
validate_int_range "$LOAD_LOWER" 1 99 "LOAD_LOWER"
validate_int_range "$LOAD_UPPER" 1 99 "LOAD_UPPER"
# Ensure upper is greater than lower
if [ "$LOAD_UPPER" -le "$LOAD_LOWER" ]; then
log_msg "ERROR: LOAD_UPPER ($LOAD_UPPER) must be greater than LOAD_LOWER ($LOAD_LOWER)"
exit 1
fi
# Function returning average CPU load as integer
average_cpu_load() {
read cpu user nice system idle iowait irq softirq steal guest guest_nice < /proc/stat
total1=$((user + nice + system + idle + iowait + irq + softirq + steal))
idle1=$((idle + iowait))
sleep 1
read cpu user nice system idle iowait irq softirq steal guest guest_nice < /proc/stat
total2=$((user + nice + system + idle + iowait + irq + softirq + steal))
idle2=$((idle + iowait))
total_diff=$((total2 - total1))
idle_diff=$((idle2 - idle1))
usage=$(( (100 * (total_diff - idle_diff)) / total_diff ))
echo "$usage"
}
# Enable core
enable_core() {
core="$1"
online_file="/sys/devices/system/cpu/$core/online"
if [ -f "$online_file" ]; then
echo 1 > "$online_file"
log_msg "Activating core $core"
fi
}
# Disable core
disable_core() {
core="$1"
online_file="/sys/devices/system/cpu/$core/online"
if [ -f "$online_file" ]; then
echo 0 > "$online_file"
log_msg "Deactivating core $core"
fi
}
# Main loop
while true; do
usage=$(average_cpu_load)
max_core=0
active_count=0
# Check all cores and count active ones
for core_path in /sys/devices/system/cpu/cpu[0-9]*; do
core=$(basename "$core_path")
core_num=${core#cpu}
online=$(cat "$core_path/online" 2>/dev/null || echo 1)
if [ "$online" -eq 1 ]; then
active_count=$((active_count + 1))
if [ "$core_num" -gt "$max_core" ]; then
max_core=$core_num
fi
fi
done
# Activate next core if usage > LOAD_UPPER
if [ "$usage" -gt "$LOAD_UPPER" ]; then
for core_path in /sys/devices/system/cpu/cpu[0-9]*; do
core=$(basename "$core_path")
core_num=${core#cpu}
online=$(cat "$core_path/online" 2>/dev/null || echo 1)
if [ "$core_num" -ne 0 ] && [ "$online" -eq 0 ]; then
enable_core "$core"
active_count=$((active_count + 1))
break
fi
done
fi
# Deactivate highest core if usage < LOAD_LOWER and more than MIN_CORES active
if [ "$usage" -lt "$LOAD_LOWER" ] && [ "$active_count" -gt "$MIN_CORES" ] && [ "$max_core" -gt 0 ]; then
disable_core "cpu$max_core"
fi
sleep "$SLEEP_INTERVAL"
done