Add CPU power management tools and dynamic frequency scaling

- Add cpu-power-control.sh: Script for managing CPU power limits and presets
- Add monitor-cpu-freq.sh: Real-time CPU frequency monitoring tool
- Add test-single-core-boost.sh: Tool for testing single-core boost frequencies
- Add BIOS-FIX.md: Documentation for BIOS configuration fix
- Update tlp.conf: Configure dynamic CPU frequency scaling (400MHz-4.2GHz on AC, 400MHz-2.2GHz on battery)
- Add Intel RAPL power limit controls for CPU power capping
- Enable dynamic frequency scaling with proper platform profiles
- Fix CPU frequency stuck at 1.6GHz issue (required BIOS SpeedStep disable)
- Configure balanced battery mode with 2.2GHz max for responsiveness
This commit is contained in:
rwiegand
2025-10-06 22:34:19 +02:00
parent ba8f37706f
commit b9e2c2a731
5 changed files with 648 additions and 12 deletions

356
scripts/cpu-power-control.sh Executable file
View File

@@ -0,0 +1,356 @@
#!/bin/bash
# CPU Power Control Script
# Provides slider-like functionality for setting CPU power limits
# Replaces the missing GUI power slider functionality
RAPL_PATH="/sys/class/powercap/intel-rapl:0"
CONSTRAINT_LONG="${RAPL_PATH}/constraint_0_power_limit_uw"
CONSTRAINT_SHORT="${RAPL_PATH}/constraint_1_power_limit_uw"
# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
print_usage() {
echo "CPU Power Control - Equivalent to GUI Power Slider"
echo ""
echo "Usage: $0 [COMMAND] [VALUE]"
echo ""
echo "Commands:"
echo " status Show current CPU power limits"
echo " set <watts> Set both long and short term limits"
echo " set-long <watts> Set long term limit only"
echo " set-short <watts> Set short term limit only"
echo " preset <name> Apply predefined power profile"
echo ""
echo "Presets:"
echo " dynamic 400MHz-4.2GHz dynamic (recommended)"
echo " max-performance 1.6GHz-4.2GHz (high performance)"
echo " balanced 400MHz-2.2GHz (battery friendly, responsive)"
echo " power-save 400MHz-2.0GHz (battery optimized)"
echo " ultra-save 400MHz-1.6GHz (extreme battery)"
echo ""
echo "Examples:"
echo " $0 status Show current settings"
echo " $0 set 10 Set both limits to 10W"
echo " $0 preset dynamic Dynamic scaling (800MHz-4.2GHz)"
echo ""
}
check_permissions() {
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}Error: This script requires root privileges${NC}"
echo "Please run with sudo: sudo $0 $*"
exit 1
fi
}
check_rapl_support() {
if [ ! -d "$RAPL_PATH" ]; then
echo -e "${RED}Error: Intel RAPL not supported on this system${NC}"
exit 1
fi
}
watts_to_microwatts() {
echo $(($1 * 1000000))
}
microwatts_to_watts() {
echo "scale=1; $1 / 1000000" | bc -l
}
get_current_limits() {
if [ -r "$CONSTRAINT_LONG" ] && [ -r "$CONSTRAINT_SHORT" ]; then
LONG_UW=$(cat "$CONSTRAINT_LONG")
SHORT_UW=$(cat "$CONSTRAINT_SHORT")
LONG_W=$(microwatts_to_watts $LONG_UW)
SHORT_W=$(microwatts_to_watts $SHORT_UW)
else
echo -e "${RED}Error: Cannot read power limit files${NC}"
exit 1
fi
}
get_max_limits() {
MAX_LONG_UW=$(cat "${RAPL_PATH}/constraint_0_max_power_uw")
MAX_SHORT_UW=$(cat "${RAPL_PATH}/constraint_1_max_power_uw")
MAX_LONG_W=$(microwatts_to_watts $MAX_LONG_UW)
MAX_SHORT_W=$(microwatts_to_watts $MAX_SHORT_UW)
}
show_status() {
echo -e "${BLUE}=== CPU Power Limits Status ===${NC}"
echo ""
get_current_limits
get_max_limits
echo -e "Current Limits:"
echo -e " Long term (PL1): ${GREEN}${LONG_W}W${NC}"
echo -e " Short term (PL2): ${GREEN}${SHORT_W}W${NC}"
echo ""
echo -e "Maximum Limits:"
echo -e " Long term max: ${YELLOW}${MAX_LONG_W}W${NC}"
echo -e " Short term max: ${YELLOW}${MAX_SHORT_W}W${NC}"
echo ""
# Show platform profile
if [ -r "/sys/firmware/acpi/platform_profile" ]; then
PLATFORM_PROFILE=$(cat /sys/firmware/acpi/platform_profile)
echo -e "Platform Profile: ${GREEN}${PLATFORM_PROFILE}${NC}"
fi
# Show CPU performance percentage
if [ -r "/sys/devices/system/cpu/intel_pstate/min_perf_pct" ]; then
MIN_PERF=$(cat /sys/devices/system/cpu/intel_pstate/min_perf_pct)
MAX_PERF=$(cat /sys/devices/system/cpu/intel_pstate/max_perf_pct)
echo -e "CPU Performance: ${GREEN}${MIN_PERF}% - ${MAX_PERF}%${NC}"
fi
# Show current CPU frequency
if [ -r "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]; then
CUR_FREQ=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq)
CUR_FREQ_MHZ=$((CUR_FREQ / 1000))
MAX_FREQ=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq)
MAX_FREQ_MHZ=$((MAX_FREQ / 1000))
echo -e "Current CPU frequency: ${GREEN}${CUR_FREQ_MHZ} MHz${NC} (max: ${MAX_FREQ_MHZ} MHz)"
fi
# Show governor
if [ -r "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" ]; then
GOVERNOR=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
echo -e "CPU Governor: ${GREEN}${GOVERNOR}${NC}"
fi
# Show power usage if available
if command -v powertop >/dev/null 2>&1; then
echo ""
echo -e "${BLUE}Tip: Run 'sudo powertop' to monitor real-time power consumption${NC}"
fi
}
set_power_limit() {
local watts=$1
local type=$2
if [ -z "$watts" ]; then
echo -e "${RED}Error: Power value required${NC}"
exit 1
fi
# Validate input is a number
if ! [[ "$watts" =~ ^[0-9]+\.?[0-9]*$ ]]; then
echo -e "${RED}Error: Invalid power value '$watts'. Must be a number.${NC}"
exit 1
fi
local microwatts=$(watts_to_microwatts $watts)
get_max_limits
# Check against maximum limits
case $type in
"long")
if [ $microwatts -gt $MAX_LONG_UW ]; then
echo -e "${YELLOW}Warning: ${watts}W exceeds maximum long term limit of ${MAX_LONG_W}W${NC}"
echo -e "Setting to maximum: ${MAX_LONG_W}W"
microwatts=$MAX_LONG_UW
fi
echo $microwatts > "$CONSTRAINT_LONG"
echo -e "${GREEN}Long term power limit set to $(microwatts_to_watts $microwatts)W${NC}"
;;
"short")
if [ $microwatts -gt $MAX_SHORT_UW ]; then
echo -e "${YELLOW}Warning: ${watts}W exceeds maximum short term limit of ${MAX_SHORT_W}W${NC}"
echo -e "Setting to maximum: ${MAX_SHORT_W}W"
microwatts=$MAX_SHORT_UW
fi
echo $microwatts > "$CONSTRAINT_SHORT"
echo -e "${GREEN}Short term power limit set to $(microwatts_to_watts $microwatts)W${NC}"
;;
"both")
# For setting both, use appropriate limits
echo $microwatts > "$CONSTRAINT_LONG"
# Short term should be higher, but not exceed max
local short_microwatts=$((microwatts * 3 / 2)) # 1.5x long term
if [ $short_microwatts -gt $MAX_SHORT_UW ]; then
short_microwatts=$MAX_SHORT_UW
fi
echo $short_microwatts > "$CONSTRAINT_SHORT"
echo -e "${GREEN}Power limits set:${NC}"
echo -e " Long term: $(microwatts_to_watts $microwatts)W"
echo -e " Short term: $(microwatts_to_watts $short_microwatts)W"
;;
esac
}
apply_preset() {
local preset=$1
case $preset in
"dynamic")
# Full dynamic range: 400MHz to 4.2GHz
set_power_limit 15 long
set_power_limit 25 short
# Set platform profile to balanced for dynamic scaling
if [ -w "/sys/firmware/acpi/platform_profile" ]; then
echo "balanced" > /sys/firmware/acpi/platform_profile 2>/dev/null
echo -e "${BLUE}Platform profile: balanced${NC}"
fi
# Allow full range 0-100%
if [ -w "/sys/devices/system/cpu/intel_pstate/min_perf_pct" ]; then
echo 0 > /sys/devices/system/cpu/intel_pstate/min_perf_pct
echo -e "${BLUE}CPU Performance: 0% - 100% (400MHz - 4.2GHz)${NC}"
fi
# Set governor to powersave for dynamic scaling
for gov in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo "powersave" > $gov 2>/dev/null
done
# Set energy preference to balance_performance
for epp in /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference; do
echo "balance_performance" > $epp 2>/dev/null
done
echo -e "${GREEN}Applied dynamic scaling preset (recommended)${NC}"
;;
"max-performance")
# Higher base but still allows boost: 1.6GHz to 4.2GHz
set_power_limit 15 long
set_power_limit 25 short
# Set platform profile to performance
if [ -w "/sys/firmware/acpi/platform_profile" ]; then
echo "performance" > /sys/firmware/acpi/platform_profile 2>/dev/null
echo -e "${BLUE}Platform profile: performance${NC}"
fi
# Set minimum to base frequency (38% = 1.6GHz)
if [ -w "/sys/devices/system/cpu/intel_pstate/min_perf_pct" ]; then
echo 38 > /sys/devices/system/cpu/intel_pstate/min_perf_pct
echo -e "${BLUE}CPU Performance: 38% - 100% (1.6GHz - 4.2GHz)${NC}"
fi
# Set governor to powersave (still allows turbo with intel_pstate)
for gov in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo "powersave" > $gov 2>/dev/null
done
# Set energy preference to performance
for epp in /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference; do
echo "performance" > $epp 2>/dev/null
done
echo -e "${GREEN}Applied maximum performance preset${NC}"
;;
"balanced")
set_power_limit 10 long
set_power_limit 15 short
# Set platform profile to balanced
if [ -w "/sys/firmware/acpi/platform_profile" ]; then
echo "balanced" > /sys/firmware/acpi/platform_profile 2>/dev/null
echo -e "${BLUE}Platform profile: balanced${NC}"
fi
# Allow dynamic scaling 0-52% (400MHz - 2.2GHz)
if [ -w "/sys/devices/system/cpu/intel_pstate/min_perf_pct" ]; then
echo 0 > /sys/devices/system/cpu/intel_pstate/min_perf_pct
echo -e "${BLUE}CPU Performance: 0% - 52% (400MHz - 2.2GHz)${NC}"
fi
if [ -w "/sys/devices/system/cpu/intel_pstate/max_perf_pct" ]; then
echo 52 > /sys/devices/system/cpu/intel_pstate/max_perf_pct
fi
# Set max frequency to 2.2 GHz
for freq in /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq; do
echo 2200000 > $freq 2>/dev/null
done
# Set governor to powersave
for gov in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo "powersave" > $gov 2>/dev/null
done
# Set energy preference to balance_power
for epp in /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference; do
echo "balance_power" > $epp 2>/dev/null
done
echo -e "${GREEN}Applied balanced preset (battery friendly)${NC}"
;;
"power-save")
set_power_limit 8 long
set_power_limit 12 short
# Set platform profile to low-power
if [ -w "/sys/firmware/acpi/platform_profile" ]; then
echo "low-power" > /sys/firmware/acpi/platform_profile 2>/dev/null
echo -e "${BLUE}Platform profile: low-power${NC}"
fi
# Limit to 50% max performance
if [ -w "/sys/devices/system/cpu/intel_pstate/min_perf_pct" ]; then
echo 0 > /sys/devices/system/cpu/intel_pstate/min_perf_pct
echo -e "${BLUE}CPU Performance: 0% - 50% (800MHz - 2.0GHz)${NC}"
fi
if [ -w "/sys/devices/system/cpu/intel_pstate/max_perf_pct" ]; then
echo 50 > /sys/devices/system/cpu/intel_pstate/max_perf_pct
fi
# Set energy preference to power
for epp in /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference; do
echo "power" > $epp 2>/dev/null
done
echo -e "${GREEN}Applied power-saving preset${NC}"
;;
"ultra-save")
set_power_limit 6 long
set_power_limit 8 short
# Set platform profile to low-power
if [ -w "/sys/firmware/acpi/platform_profile" ]; then
echo "low-power" > /sys/firmware/acpi/platform_profile 2>/dev/null
echo -e "${BLUE}Platform profile: low-power${NC}"
fi
# Limit to base frequency (38% = 1.6GHz max)
if [ -w "/sys/devices/system/cpu/intel_pstate/min_perf_pct" ]; then
echo 0 > /sys/devices/system/cpu/intel_pstate/min_perf_pct
echo -e "${BLUE}CPU Performance: 0% - 38% (800MHz - 1.6GHz)${NC}"
fi
if [ -w "/sys/devices/system/cpu/intel_pstate/max_perf_pct" ]; then
echo 38 > /sys/devices/system/cpu/intel_pstate/max_perf_pct
fi
# Set energy preference to power
for epp in /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference; do
echo "power" > $epp 2>/dev/null
done
echo -e "${GREEN}Applied ultra power-saving preset${NC}"
;;
*)
echo -e "${RED}Error: Unknown preset '$preset'${NC}"
echo "Available presets: dynamic, max-performance, balanced, power-save, ultra-save"
exit 1
;;
esac
}
# Main script logic
case "$1" in
"status")
check_rapl_support
show_status
;;
"set")
check_permissions
check_rapl_support
set_power_limit "$2" "both"
;;
"set-long")
check_permissions
check_rapl_support
set_power_limit "$2" "long"
;;
"set-short")
check_permissions
check_rapl_support
set_power_limit "$2" "short"
;;
"preset")
check_permissions
check_rapl_support
apply_preset "$2"
;;
*)
print_usage
;;
esac

61
scripts/monitor-cpu-freq.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
# Real-time CPU Frequency Monitor
# Shows actual CPU frequencies and helps identify boost behavior
echo "=== Real-time CPU Frequency Monitor ==="
echo "Press Ctrl+C to stop"
echo ""
echo "Note: Modern Intel CPUs dynamically adjust frequency based on:"
echo " - Workload type (single vs multi-core)"
echo " - Power limits (TDP)"
echo " - Temperature"
echo " - Energy efficiency preferences"
echo ""
# Check if turbostat is available
if command -v turbostat >/dev/null 2>&1; then
echo "Using turbostat for accurate frequency monitoring..."
echo ""
sudo turbostat --quiet --show Core,CPU,Busy%,Bzy_MHz,PkgWatt --interval 2
else
echo "turbostat not available, using basic monitoring..."
echo ""
echo "Timestamp | CPU0 CPU1 CPU2 CPU3 | Avg MHz | Governor | Temp"
echo "----------------+---------------------------------+---------+-----------+------"
while true; do
TIMESTAMP=$(date +"%H:%M:%S")
# Get frequencies
FREQ0=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq)
FREQ1=$(cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq)
FREQ2=$(cat /sys/devices/system/cpu/cpu2/cpufreq/scaling_cur_freq)
FREQ3=$(cat /sys/devices/system/cpu/cpu3/cpufreq/scaling_cur_freq)
# Convert to MHz
F0=$((FREQ0 / 1000))
F1=$((FREQ1 / 1000))
F2=$((FREQ2 / 1000))
F3=$((FREQ3 / 1000))
# Calculate average
AVG=$(( (F0 + F1 + F2 + F3) / 4 ))
# Get governor
GOV=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
# Get temperature if available
if [ -r "/sys/class/thermal/thermal_zone0/temp" ]; then
TEMP_RAW=$(cat /sys/class/thermal/thermal_zone0/temp)
TEMP=$((TEMP_RAW / 1000))
else
TEMP="N/A"
fi
printf "%s | %4d %4d %4d %4d | %4d MHz | %-9s | %s°C\n" \
"$TIMESTAMP" "$F0" "$F1" "$F2" "$F3" "$AVG" "$GOV" "$TEMP"
sleep 2
done
fi

View File

@@ -0,0 +1,29 @@
#!/bin/bash
# Single Core Boost Test Script
# Forces maximum single-core performance to reach peak boost frequencies
echo "Testing single-core boost capability..."
echo "Current base frequency: $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq | awk '{print $1/1000}') MHz"
# Disable cores 1-7 temporarily to force single-core boost
for cpu in {1..7}; do
echo 0 | sudo tee /sys/devices/system/cpu/cpu${cpu}/online > /dev/null 2>&1
done
echo "Cores 1-7 disabled, testing single-core boost..."
# Run intensive single-core workload
timeout 5s bash -c 'while true; do echo "scale=5000; 4*a(1)" | bc -l > /dev/null 2>&1; done' &
sleep 2
echo "Peak frequency during single-core load: $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq | awk '{print $1/1000}') MHz"
# Re-enable all cores
for cpu in {1..7}; do
echo 1 | sudo tee /sys/devices/system/cpu/cpu${cpu}/online > /dev/null 2>&1
done
wait
echo "All cores re-enabled"
echo "Final frequency: $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq | awk '{print $1/1000}') MHz"