1 (edytowany przez krypton_pl 2025-11-15 22:49:39)

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

2

Odp: Automatyczne wyłączanie rdzeni ( parkowanie )

Dzięki!
Czy ten skrypt zadziała bezpośrednio w Debian 13/Proxmox na HP T630 również z AMD czy jest specyficzny dla OpenWRT?

3

Odp: Automatyczne wyłączanie rdzeni ( parkowanie )

W każdym linuksie możesz tak rdzenie tymczasowo wyłączyć.

Masz niepotrzebny router, uszkodzony czy nie - chętnie przygarnę go.

4

Odp: Automatyczne wyłączanie rdzeni ( parkowanie )

Bez przeróbek zadziałał na debianie 13