-
-
Save rorar/cebde935cf4dfa6389df96c4df79ce38 to your computer and use it in GitHub Desktop.
Disable / Enable HyperThreading cores on runtime | CPU config backup and restore | simple CPU Mitigation Check that prevents HT | For Linux π§
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# ------------------------------------------------------------------------ | |
# Usage Instructions: | |
# To download and use this script, follow these steps: | |
# wget http://example.com/HToggler.su -O HToggler.su | |
# chmod +x HToggler.su | |
# sudo ./HToggler.su | |
# ------------------------------------------------------------------------ | |
# ASCII Art Header (Corrected) | |
printf "\n\n" | |
printf " ) \n" | |
printf " ( /( * ) ( \n" | |
printf " )\\())\` ) /( ( ( ( ( )\\ ( ( \n" | |
printf "((_)\ ( )(_))( )\\))( )\\))( ((_) ))\\ )( \n" | |
printf " _((_)(_(_()) )\\ ((_))\\((_))\\ _ /((_)(()\\ \n" | |
printf "| || ||_ _|((_) (()(_)(()(_)| |(_)) ((_) \n" | |
printf "| __ | | | / _ \\/ _\` |/ _\` | | |/ -_) | '_| \n" | |
printf "|_||_| |_| \\___/\\__, |\\__, | |_|\___| |_| \n" | |
printf " |___/ |___/ \n" | |
printf "\n" | |
# Explanation of the script functionality | |
printf "HToggler is a script to manage Hyperthreading settings on Linux systems.\n" | |
printf "It allows you to enable or disable Hyperthreading, create backups of CPU configurations, and restore them when needed.\n" | |
printf "\n" | |
HYPERTHREADING=1 | |
LOGFILE="/var/log/hyperthreading_script.log" | |
BACKUP_DIR="/tmp" | |
# Trap to handle SIGINT (Ctrl + C) to exit cleanly | |
function handleSigint() { | |
printf "\nScript interrupted by the user. Exiting...\n" >&2 | |
exit 1 | |
} | |
trap handleSigint SIGINT | |
# Check if the script is run as root | |
function ensureRoot() { | |
if [[ $EUID -ne 0 ]]; then | |
printf "This script must be run as root. Restarting with sudo...\n" | |
if command -v sudo &> /dev/null; then | |
exec sudo "$0" "$@" | |
else | |
printf "Error: sudo is not available. Script cannot continue without root privileges.\n" >&2 | |
exit 1 | |
fi | |
fi | |
} | |
# Backup CPU configuration before making changes | |
function backupCpuConfig() { | |
local TIMESTAMP | |
TIMESTAMP=$(date '+%Y%m%d_%H%M%S') | |
local BACKUP_FILE="$BACKUP_DIR/cpu_config_backup_$TIMESTAMP" | |
printf "Backing up current CPU configuration...\n" | |
cat /sys/devices/system/cpu/online > "$BACKUP_FILE" | |
if [[ $? -ne 0 ]]; then | |
logError "Error: Failed to create backup of CPU configuration." | |
return 1 | |
fi | |
printf "Backup saved to %s\n" "$BACKUP_FILE" | |
} | |
# Restore CPU configuration from a list of backups | |
function restoreCpuConfig() { | |
local backups=($BACKUP_DIR/cpu_config_backup_*) | |
local num_backups=${#backups[@]} | |
if [[ $num_backups -eq 0 ]]; then | |
printf "No backups found in %s\n" "$BACKUP_DIR" >&2 | |
return 1 | |
fi | |
printf "Available backups:\n" | |
for i in "${!backups[@]}"; do | |
printf "%d) %s\n" "$((i+1))" "${backups[$i]}" | |
done | |
while true; do | |
read -p "Enter the number of the backup you want to restore: " selection | |
if [[ "$selection" =~ ^[0-9]+$ && $selection -ge 1 && $selection -le $num_backups ]]; then | |
local selected_backup="${backups[$((selection-1))]}" | |
printf "Restoring CPU configuration from %s...\n" "$selected_backup" | |
while read -r cpu; do | |
echo "1" > "/sys/devices/system/cpu/cpu${cpu}/online" | |
done < "$selected_backup" | |
printf "CPU configuration restored.\n" | |
break | |
else | |
printf "Invalid selection. Please try again.\n" | |
fi | |
done | |
} | |
# Log errors and changes | |
function logError() { | |
local message="$1" | |
printf "%s\n" "$message" >&2 | |
printf "%s - %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$message" >> "$LOGFILE" | |
} | |
# Log Hyperthreading changes | |
function logHyperThreadingChange() { | |
local action="$1" | |
printf "%s: Hyperthreading was %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$action" >> "$LOGFILE" | |
} | |
# Check CPU load and warn the user if it's too high | |
function checkCpuLoad() { | |
local load | |
load=$(awk '{print $1}' /proc/loadavg) | |
local cores | |
cores=$(nproc) | |
if (( $(echo "$load > $cores * 0.75" | bc -l) )); then | |
printf "Warning: CPU load is high (%.2f). Disabling Hyperthreading under high load may increase workload and cause system instability.\n" "$load" | |
while true; do | |
read -p "Do you want to resolve the high CPU load before continuing? [y/n/continue anyway] " response | |
case $response in | |
[Yy]* ) | |
printf "Please resolve the high CPU load before proceeding.\n" | |
return 1 | |
;; | |
[Nn]* ) | |
printf "You chose to continue without addressing the CPU load issue.\n" | |
break | |
;; | |
[Cc]* ) | |
printf "Continuing anyway despite high CPU load.\n" | |
break | |
;; | |
* ) | |
printf "Invalid input. Please answer 'y', 'n', or 'continue anyway'.\n" | |
;; | |
esac | |
done | |
else | |
printf "CPU load is normal: %.2f\n" "$load" | |
fi | |
} | |
# Verify if hyperthreading has been changed correctly | |
function verifyHyperThreading() { | |
local expected_status="$1" # 1 for enabled, 0 for disabled | |
local current_status | |
current_status=$(lscpu | grep -oP 'Thread\(s\) per core:\s*\K[0-9]+') | |
if [[ "$expected_status" -eq 1 && "$current_status" -gt 1 ]]; then | |
printf "Verification successful: Hyperthreading is ENABLED.\n" | |
elif [[ "$expected_status" -eq 0 && "$current_status" -eq 1 ]]; then | |
printf "Verification successful: Hyperthreading is DISABLED.\n" | |
else | |
logError "Error: Verification failed. Expected Hyperthreading to be %s, but it is not." \ | |
"$([[ "$expected_status" -eq 1 ]] && echo "ENABLED" || echo "DISABLED")" | |
return 1 | |
fi | |
} | |
# Function to toggle hyperthreading on or off | |
function toggleHyperThreading() { | |
backupCpuConfig # Backup the CPU configuration before making changes | |
for CPU in /sys/devices/system/cpu/cpu[0-9]*; do | |
CPUID=$(basename "$CPU" | cut -b4-) | |
THREAD1=$(cut -f1 -d, < "$CPU/topology/thread_siblings_list") | |
if [[ "$CPUID" == "$THREAD1" ]]; then | |
printf "CPU: %s -> enable\n" "$CPUID" | |
if ! echo "1" > "$CPU/online"; then | |
logError "Error: Failed to enable hyperthreading on CPU $CPUID." | |
continue | |
fi | |
else | |
printf "CPU: %s -> %s\n" "$CPUID" "$([[ "$HYPERTHREADING" -eq 0 ]] && echo "disabled" || echo "enabled")" | |
if ! echo "$HYPERTHREADING" > "$CPU/online"; then | |
logError "Error: Failed to change hyperthreading on CPU $CPUID." | |
continue | |
fi | |
fi | |
done | |
} | |
# Disable hyperthreading | |
function disabled() { | |
printf "Disabling HyperThreading\n" | |
HYPERTHREADING=0 | |
checkCpuLoad || continueAnywayCheck | |
toggleHyperThreading | |
verifyHyperThreading 0 # Verify if Hyperthreading is disabled | |
logHyperThreadingChange "disabled" | |
} | |
# Enable hyperthreading | |
function enabled() { | |
printf "Enabling HyperThreading\n" | |
HYPERTHREADING=1 | |
toggleHyperThreading | |
verifyHyperThreading 1 # Verify if Hyperthreading is enabled | |
logHyperThreadingChange "enabled" | |
} | |
# Additional check if user still wants to continue after the issue persists | |
function continueAnywayCheck() { | |
while true; do | |
read -p "The issue still persists. Do you want to continue anyway? [y/n] " choice | |
case $choice in | |
[Yy]* ) | |
printf "Continuing despite the issue.\n" | |
break | |
;; | |
[Nn]* ) | |
printf "Aborting operation. Please resolve the issue first.\n" | |
exit 1 | |
;; | |
* ) | |
printf "Invalid input. Please answer 'y' for yes or 'n' for no.\n" | |
;; | |
esac | |
done | |
} | |
# Display detailed hyperthreading status for all CPUs | |
function detailedHyperThreadingStatus() { | |
for CPU in /sys/devices/system/cpu/cpu[0-9]*; do | |
CPUID=$(basename "$CPU" | cut -b4-) | |
THREADS=$(cat "$CPU/topology/thread_siblings_list") | |
# Check if the 'online' file exists before trying to read it | |
if [[ ! -f "$CPU/online" ]]; then | |
printf "Skipping CPU: %s (no 'online' file)\n" "$CPUID" | |
continue | |
fi | |
ONLINE=$(cat "$CPU/online") | |
printf "CPU: %s\t Siblings: %s\t Online: %s\n" "$CPUID" "$THREADS" "$ONLINE" | |
done | |
} | |
# Check for security mitigations that disable hyperthreading | |
function checkSecurityMitigations() { | |
local mitigations | |
mitigations=$(grep -o 'mitigations=off' /proc/cmdline) | |
if [[ "$mitigations" == "mitigations=off" ]]; then | |
printf "Warning: All security mitigations are turned off. Hyperthreading might be enabled but unprotected.\n" | |
else | |
printf "Security mitigations are active. Checking hyperthreading status...\n" | |
fi | |
local noht_param | |
noht_param=$(grep -o 'noht' /proc/cmdline) | |
if [[ "$noht_param" == "noht" ]]; then | |
printf "Security mitigation detected: Hyperthreading is disabled via kernel boot parameter 'noht'.\n" | |
return 1 | |
else | |
printf "No kernel boot parameters disabling hyperthreading found.\n" | |
fi | |
} | |
# Check if a backup exists and prompt the user to restore it | |
function promptRestoreBackup() { | |
local backups=($BACKUP_DIR/cpu_config_backup_*) | |
local num_backups=${#backups[@]} | |
if [[ $num_backups -gt 0 ]]; then | |
printf "A previous CPU configuration backup was found.\n" | |
printf "Do you want to restore the previous CPU configuration? [y/n]\n" | |
local SECONDS_LEFT=5 | |
while [[ $SECONDS_LEFT -gt 0 ]]; do | |
printf "\rProceeding without restoring the backup in %d seconds... " "$SECONDS_LEFT" | |
read -t 1 -n 1 response # Read user input with a 1 second timeout | |
if [[ "$response" =~ [Yy] ]]; then | |
restoreCpuConfig | |
return | |
elif [[ "$response" =~ [Nn] ]]; then | |
printf "\nProceeding without restoring the backup.\n" | |
return | |
fi | |
SECONDS_LEFT=$((SECONDS_LEFT - 1)) | |
done | |
printf "\nNo input detected. Proceeding without restoring the backup.\n" | |
else | |
printf "No previous backup found. Proceeding with current configuration.\n" | |
fi | |
} | |
# Main function | |
function main() { | |
ensureRoot # Check if script is run as root | |
promptRestoreBackup # Check and prompt the user to restore the previous backup | |
detailedHyperThreadingStatus # Display hyperthreading details for all CPUs | |
checkSecurityMitigations # Check if security mitigations are disabling hyperthreading | |
while true; do | |
read -p "Type 'e' to enable, 'd' to disable hyperthreading, or 'q' to quit [e/d/q]: " ed | |
case $ed in | |
[Ee]* ) enabled; break ;; | |
[Dd]* ) disabled; break ;; | |
[Qq]* ) exit ;; | |
* ) printf "Please answer 'e' to enable, 'd' to disable hyperthreading, or 'q' to quit.\n" ;; | |
esac | |
done | |
} | |
# Run the main function | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment