-
-
Save samueljon/e7818edeb218f5e2f1e3e258949d04c8 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| HYPERTHREADING=1 | |
| TABLE_VIEW=0 # Default to list view | |
| AUTO_MODE=0 # Automatic enable/disable without prompt | |
| # Color codes | |
| BOLD='\033[1m' | |
| GREEN='\033[0;32m' | |
| RED='\033[0;31m' | |
| ORANGE='\033[0;33m' | |
| RESET='\033[0m' | |
| # Global arrays to cache topology information | |
| declare -A CACHED_SIBLINGS # Maps thread ID to its sibling list | |
| declare -A CACHED_SIBLING_MAP # Maps each thread to its sibling | |
| declare -A CACHED_PRIMARY # Maps each thread to 1 if primary, 0 if HT sibling | |
| # Parse command line arguments | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| -t|--table) | |
| TABLE_VIEW=1 | |
| shift | |
| ;; | |
| -e|--enable) | |
| AUTO_MODE=1 | |
| HYPERTHREADING=1 | |
| shift | |
| ;; | |
| -d|--disable) | |
| AUTO_MODE=1 | |
| HYPERTHREADING=0 | |
| shift | |
| ;; | |
| -h|--help) | |
| echo "Usage: $0 [OPTIONS]" | |
| echo "" | |
| echo "Options:" | |
| echo " -e, --enable Enable hyperthreading and exit" | |
| echo " -d, --disable Disable hyperthreading and exit" | |
| echo " -t, --table Display threads in table format grouped by physical cores" | |
| echo " -h, --help Show this help message" | |
| echo "" | |
| echo "Examples:" | |
| echo " $0 # Interactive mode with list view" | |
| echo " $0 -t # Interactive mode with table view" | |
| echo " $0 -d # Disable HT immediately" | |
| echo " $0 -e -t # Enable HT and show table view" | |
| exit 0 | |
| ;; | |
| *) | |
| echo "Unknown option: $1" | |
| echo "Use -h or --help for usage information" | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| function cacheTopology() { | |
| # Cache topology information - temporarily enable offline threads to read topology | |
| # Save original state | |
| declare -A original_state | |
| for CPU in $(printf '%s\n' /sys/devices/system/cpu/cpu[0-9]* | sort -V); do | |
| CPUID=`basename $CPU | cut -b4-` | |
| # Save original state | |
| if [ -e $CPU/online ]; then | |
| original_state[$CPUID]=$(cat $CPU/online 2>/dev/null || echo "1") | |
| # Temporarily bring thread online to read topology | |
| [ -w $CPU/online ] && echo "1" > $CPU/online 2>/dev/null | |
| else | |
| original_state[$CPUID]=1 # Thread 0 is always online | |
| fi | |
| done | |
| # Small delay to ensure threads are fully online | |
| sleep 0.1 | |
| # Read topology from all threads | |
| for CPU in $(printf '%s\n' /sys/devices/system/cpu/cpu[0-9]* | sort -V); do | |
| CPUID=`basename $CPU | cut -b4-` | |
| # Cache sibling list if available | |
| if [ -e $CPU/topology/thread_siblings_list ]; then | |
| CACHED_SIBLINGS[$CPUID]=`cat $CPU/topology/thread_siblings_list` | |
| # Parse and build sibling map | |
| SIBLINGS="${CACHED_SIBLINGS[$CPUID]}" | |
| PRIMARY=$(echo "$SIBLINGS" | cut -d',' -f1 | cut -d'-' -f1) | |
| SECONDARY=$(echo "$SIBLINGS" | cut -d',' -f2 | cut -d'-' -f2) | |
| if [ "$PRIMARY" != "$SECONDARY" ] && [ -n "$SECONDARY" ]; then | |
| # Map both directions | |
| CACHED_SIBLING_MAP[$PRIMARY]=$SECONDARY | |
| CACHED_SIBLING_MAP[$SECONDARY]=$PRIMARY | |
| # Mark which is primary (first in siblings list) | |
| CACHED_PRIMARY[$PRIMARY]=1 | |
| CACHED_PRIMARY[$SECONDARY]=0 | |
| fi | |
| fi | |
| done | |
| # Restore original state | |
| for CPU in $(printf '%s\n' /sys/devices/system/cpu/cpu[0-9]* | sort -V); do | |
| CPUID=`basename $CPU | cut -b4-` | |
| ORIG_STATE="${original_state[$CPUID]}" | |
| if [ -n "$ORIG_STATE" ] && [ -w $CPU/online ]; then | |
| echo "$ORIG_STATE" > $CPU/online 2>/dev/null | |
| fi | |
| done | |
| } | |
| function toggleHyperThreading() { | |
| # Only show line-by-line output if not in table view | |
| local SHOW_OUTPUT=1 | |
| if [ "$TABLE_VIEW" -eq "1" ]; then | |
| SHOW_OUTPUT=0 | |
| fi | |
| for CPU in $(printf '%s\n' /sys/devices/system/cpu/cpu[0-9]* | sort -V); do | |
| CPUID=`basename $CPU | cut -b4-` | |
| [ "$SHOW_OUTPUT" -eq "1" ] && echo -en "${BOLD}Thread:${RESET} $CPUID\t" | |
| [ -w $CPU/online ] && echo "1" > $CPU/online | |
| THREAD1=`cat $CPU/topology/thread_siblings_list | cut -f1 -d,` | |
| if [ $CPUID = $THREAD1 ]; then | |
| [ "$SHOW_OUTPUT" -eq "1" ] && echo -e "${GREEN}-> online (primary)${RESET}" | |
| [ -w $CPU/online ] && echo "1" > $CPU/online | |
| else | |
| if [ "$HYPERTHREADING" -eq "0" ]; then | |
| [ "$SHOW_OUTPUT" -eq "1" ] && echo -e "${RED}-> offline (HT sibling)${RESET}" | |
| else | |
| [ "$SHOW_OUTPUT" -eq "1" ] && echo -e "${ORANGE}-> online (HT sibling)${RESET}" | |
| fi | |
| [ -w $CPU/online ] && echo "$HYPERTHREADING" > $CPU/online | |
| fi | |
| done | |
| } | |
| function enabled() { | |
| echo -e "${GREEN}${BOLD}Enabling Hyperthreading (bringing HT sibling threads online)${RESET}\n" | |
| HYPERTHREADING=1 | |
| toggleHyperThreading | |
| # Show result in appropriate format | |
| if [ "$TABLE_VIEW" -eq "1" ]; then | |
| echo "" | |
| showCurrentStateTable | |
| fi | |
| } | |
| function disabled() { | |
| echo -e "${RED}${BOLD}Disabling Hyperthreading (taking HT sibling threads offline)${RESET}\n" | |
| HYPERTHREADING=0 | |
| toggleHyperThreading | |
| # Show result in appropriate format | |
| if [ "$TABLE_VIEW" -eq "1" ]; then | |
| echo "" | |
| showCurrentStateTable | |
| fi | |
| } | |
| function showCurrentState() { | |
| echo -e "${BOLD}Current Thread Status:${RESET}\n" | |
| for CPU in $(printf '%s\n' /sys/devices/system/cpu/cpu[0-9]* | sort -V); do | |
| CPUID=`basename $CPU | cut -b4-` | |
| echo -en "${BOLD}Thread:${RESET} $CPUID\t" | |
| # Check if thread is online | |
| if [ -e $CPU/online ]; then | |
| ONLINE_STATUS=$(cat $CPU/online) | |
| else | |
| # Thread 0 doesn't have online file, it's always online | |
| ONLINE_STATUS=1 | |
| fi | |
| # Check if thread is offline - if so, topology files won't exist | |
| if [ "$ONLINE_STATUS" -eq "0" ]; then | |
| echo -e "${RED}-> offline (HT sibling)${RESET}" | |
| continue | |
| fi | |
| # For online threads, determine if it's a primary or secondary thread | |
| if [ -e $CPU/topology/thread_siblings_list ]; then | |
| THREAD1=`cat $CPU/topology/thread_siblings_list | cut -f1 -d,` | |
| if [ $CPUID = $THREAD1 ]; then | |
| # Primary thread | |
| echo -e "${GREEN}-> online (primary)${RESET}" | |
| else | |
| # Secondary thread (HT sibling) | |
| echo -e "${ORANGE}-> online (HT sibling)${RESET}" | |
| fi | |
| else | |
| # Topology file doesn't exist, just show online status | |
| echo -e "${GREEN}-> online${RESET}" | |
| fi | |
| done | |
| echo "" | |
| } | |
| function showCurrentStateTable() { | |
| # Get current status for all threads (topology is cached globally) | |
| declare -A cpu_status | |
| declare -A processed | |
| # Get current online/offline status for all threads | |
| for CPU in $(printf '%s\n' /sys/devices/system/cpu/cpu[0-9]* | sort -V); do | |
| CPUID=`basename $CPU | cut -b4-` | |
| # Get online status | |
| if [ -e $CPU/online ]; then | |
| cpu_status[$CPUID]=$(cat $CPU/online) | |
| else | |
| cpu_status[$CPUID]=1 # Thread 0 is always online | |
| fi | |
| done | |
| # Print table header | |
| echo -e "${BOLD}┌───────────────────────┬───────────────────────┐${RESET}" | |
| echo -e "${BOLD}│ Primary Thread │ HT Sibling │${RESET}" | |
| echo -e "${BOLD}├───────────────────────┼───────────────────────┤${RESET}" | |
| # Display all threads in pairs using cached topology | |
| for CPU in $(printf '%s\n' /sys/devices/system/cpu/cpu[0-9]* | sort -V); do | |
| CPUID=`basename $CPU | cut -b4-` | |
| # Skip if already processed | |
| [ "${processed[$CPUID]}" = "1" ] && continue | |
| # Check if this thread has a sibling (use cached data) | |
| SIBLING="${CACHED_SIBLING_MAP[$CPUID]}" | |
| if [ -n "$SIBLING" ]; then | |
| # Mark both as processed | |
| processed[$CPUID]=1 | |
| processed[$SIBLING]=1 | |
| # Get status for both threads | |
| STATUS1="${cpu_status[$CPUID]}" | |
| STATUS2="${cpu_status[$SIBLING]}" | |
| # Determine display order: online thread goes in Primary column | |
| # If both online or both offline, use cached primary designation | |
| if [ "$STATUS1" -eq "1" ] && [ "$STATUS2" -eq "0" ]; then | |
| # CPUID is online, SIBLING is offline - CPUID is primary | |
| PRIMARY=$CPUID | |
| SECONDARY=$SIBLING | |
| elif [ "$STATUS1" -eq "0" ] && [ "$STATUS2" -eq "1" ]; then | |
| # SIBLING is online, CPUID is offline - SIBLING is primary | |
| PRIMARY=$SIBLING | |
| SECONDARY=$CPUID | |
| else | |
| # Both same status - use cached topology | |
| if [ "${CACHED_PRIMARY[$CPUID]}" = "1" ]; then | |
| PRIMARY=$CPUID | |
| SECONDARY=$SIBLING | |
| else | |
| PRIMARY=$SIBLING | |
| SECONDARY=$CPUID | |
| fi | |
| fi | |
| # Get status for primary (should be online or both same status) | |
| PRIMARY_STATUS="${cpu_status[$PRIMARY]}" | |
| if [ "$PRIMARY_STATUS" -eq "1" ]; then | |
| PRIMARY_COLOR="${GREEN}" | |
| PRIMARY_SYMBOL="✓" | |
| else | |
| PRIMARY_COLOR="${RED}" | |
| PRIMARY_SYMBOL="✗" | |
| fi | |
| # Build display strings | |
| PRIMARY_TEXT=$(printf "Thread %-2s %s" "$PRIMARY" "$PRIMARY_SYMBOL") | |
| # Get status for secondary (HT sibling) | |
| SECONDARY_STATUS="${cpu_status[$SECONDARY]}" | |
| if [ "$SECONDARY_STATUS" -eq "1" ]; then | |
| HT_COLOR="${ORANGE}" | |
| HT_SYMBOL="✓" | |
| else | |
| HT_COLOR="${RED}" | |
| HT_SYMBOL="✗" | |
| fi | |
| HT_TEXT=$(printf "Thread %-2s %s" "$SECONDARY" "$HT_SYMBOL") | |
| # Print row with proper alignment | |
| printf "│ ${PRIMARY_COLOR}%-16s${RESET} \t│ ${HT_COLOR}%-16s${RESET} \t│\n" \ | |
| "$PRIMARY_TEXT" "$HT_TEXT" | |
| else | |
| # Single-threaded core (no HT sibling) | |
| processed[$CPUID]=1 | |
| STATUS="${cpu_status[$CPUID]}" | |
| if [ "$STATUS" -eq "1" ]; then | |
| COLOR="${GREEN}" | |
| SYMBOL="✓" | |
| else | |
| COLOR="${RED}" | |
| SYMBOL="✗" | |
| fi | |
| THREAD_TEXT=$(printf "Thread %-2s %s" "$CPUID" "$SYMBOL") | |
| printf "│ ${COLOR}%-16s${RESET} \t│ %-16s \t│\n" \ | |
| "$THREAD_TEXT" "N/A" | |
| fi | |
| done | |
| echo -e "${BOLD}└───────────────────────┴───────────────────────┘${RESET}" | |
| echo "" | |
| echo -e "Legend: ${GREEN}✓${RESET} = Online (Primary) ${ORANGE}✓${RESET} = Online (HT) ${RED}✗${RESET} = Offline" | |
| echo "" | |
| } | |
| # | |
| ONLINE=$(cat /sys/devices/system/cpu/online) | |
| OFFLINE=$(cat /sys/devices/system/cpu/offline) | |
| if [[ $EUID -ne 0 ]]; then | |
| echo "This script must be run as root" | |
| exit 1 | |
| fi | |
| # Cache topology information while all threads are online | |
| cacheTopology | |
| # If auto mode is enabled, toggle and exit | |
| if [ "$AUTO_MODE" -eq "1" ]; then | |
| if [ "$HYPERTHREADING" -eq "1" ]; then | |
| enabled | |
| else | |
| disabled | |
| fi | |
| # For list view, show final summary | |
| if [ "$TABLE_VIEW" -eq "0" ]; then | |
| echo "" | |
| echo "---------------------------------------------------" | |
| ONLINE=$(cat /sys/devices/system/cpu/online) | |
| OFFLINE=$(cat /sys/devices/system/cpu/offline) | |
| echo -en "Threads online: $ONLINE\t Threads offline: $OFFLINE\n" | |
| echo "---------------------------------------------------" | |
| fi | |
| exit 0 | |
| fi | |
| # Interactive mode - show current state first | |
| if [ "$TABLE_VIEW" -eq "1" ]; then | |
| showCurrentStateTable | |
| else | |
| echo "---------------------------------------------------" | |
| echo -en "Threads online: $ONLINE\t Threads offline: $OFFLINE\n" | |
| echo "---------------------------------------------------" | |
| showCurrentState | |
| echo "---------------------------------------------------" | |
| fi | |
| # Interactive prompt | |
| while true; do | |
| read -p "Type in e to enable or d to disable hyperthreading or q to quit [e/d/q] ?" ed | |
| case $ed in | |
| [Ee]* ) enabled; break;; | |
| [Dd]* ) disabled;exit;; | |
| [Qq]* ) exit;; | |
| * ) echo "Please answer e for enable or d for disable hyperthreading.";; | |
| esac | |
| done |
Nice to know that you found it useful @gabrielctn
Thanks, indeed very useful!
hi sir, I'm beginner in Linux, how can I use this bash file?
@ha3ant I would click the "raw" button at the top of the script and copy the contents of the script. Then on the machine where you will be running the script open a file editor where you will paste the content and save as f.ex togglHt.sh. Then you would make the script executable by issuing following command in a terminal chmod +x toggleHT.sh. After that you should be able to run it from the directory where you saved it f.ex. ./toggleHT.sh
Great!
this is givinig me prermission denied:
bash: /sys/devices/system/cpu/cpu6/online: Permission denied
for all cpus
@nevil02 you must run this script as root. I have updated the script to check if the user running the script is root, otherwise printing "The script must be run as root". You could do sudo ./toogleHT.sh or become root to execute.
it is giving me following message
sudo: ./hyperthreading-on-off.sh: command not foun
@nevil02 did you create the script as hyperthreading-on-off.sh and have you made it executable by doing chmod +x hyperthreading-on-off.sh before running it ?
done, Thank you
@nevil02 my pleasure 👍
Hi, thank you for sharing this code.
I was wondering that if my CPU has 16 cores, should I change the code cpu[0-9] in the 6th line into cpu[0-15]?
@ha3ant I would click the "raw" button at the top of the script and copy the contents of the script. Then on the machine where you will be running the script open a file editor where you will paste the content and save as f.ex togglHt.sh. Then you would make the script executable by issuing following command in a terminal
chmod +x toggleHT.sh. After that you should be able to run it from the directory where you saved it f.ex../toggleHT.sh
Hi, I am not sure what's the meaning of "save as f.ex toggIHt.sh".
The coed is a bash code, and it would be as toggIHt.sh. What is the f.ex mean?
@LePingKYXK i do not think you need to change code in line 6. I did test this with more than ten cpu's. F.ex means for example.
@LePingKYXK i do not think you need to change code in line 6. I did test this with more than ten cpu's. F.ex means for example.
Thanks a lot. It works well.
prefect,thanks
Perfect, thanks a lot.
hey this actually works, nice!
Works like a charm on my old Slackare 14.2 with a i7-4810mq - Thanks!
@samueljon Would it be possibel for you to add a few checks?
- Check if CPU is HT capable
- Check if HT is enabled or disabled
- Check for availabe cores and threads per cores
Edit: Did some work here...
https://gist.github.com/rorar/cebde935cf4dfa6389df96c4df79ce38
Not perfect, still need polishing (colored text output, disable selected cores,...) . Do you want to give it a try?
@samueljon Would it be possibel for you to add a few checks?
- Check if CPU is HT capable
- Check if HT is enabled or disabled
- Check for availabe cores and threads per cores
Edit: Did some work here... https://gist.github.com/rorar/cebde935cf4dfa6389df96c4df79ce38 Not perfect, still need polishing (colored text output, disable selected cores,...) . Do you want to give it a try?
Nice I will have a look when I can @rorar . Thanks for the inspiration in your implementation.
Hello, I noticed that the script does not output the CPUs in correct order.
Actual output:
---------------------------------------------------
CPU's online: 0-11 CPU's offline:
---------------------------------------------------
Type in e to enable or d disable hyperThreading or q to quit [e/d/q] ?d
Disabling HyperThreading
CPU: 0 -> enable
CPU: 1 -> enable
CPU: 10 -> disabled
CPU: 11 -> disabled
CPU: 2 -> enable
CPU: 3 -> enable
CPU: 4 -> enable
CPU: 5 -> enable
CPU: 6 -> disabled
CPU: 7 -> disabled
CPU: 8 -> disabled
CPU: 9 -> disabled
Expected output:
---------------------------------------------------
CPU's online: 0-11 CPU's offline:
---------------------------------------------------
Type in e to enable or d disable hyperThreading or q to quit [e/d/q] ?d
Disabling HyperThreading
CPU: 0 -> enable
CPU: 1 -> enable
CPU: 2 -> enable
CPU: 3 -> enable
CPU: 4 -> enable
CPU: 5 -> enable
CPU: 6 -> disabled
CPU: 7 -> disabled
CPU: 8 -> disabled
CPU: 9 -> disabled
CPU: 10 -> disabled
CPU: 11 -> disabled
Thanks for reporting this @antermin and I have mades some improvements and also taken the considerations from @rorar into account. Here is the changelog:
Display Enhancements
- Add table view mode (-t/--table flag) showing thread pairs grouped by physical core
- Use Unicode box-drawing characters for clean table borders
- Add color-coded output:
- Green: online primary threads
- Orange: online HT sibling threads
- Red: offline threads
- Bold formatting for labels and headers
Bug Fixes
- Fix CPU ordering to use numeric sort instead of lexicographic (0,1,2...10,11 not 0,1,10,11)
- Handle CPU 0 permission errors (boot CPU cannot be taken offline)
- Check file writability before attempting to modify /sys/devices/system/cpu/*/online
Functionality Improvements
- Add non-interactive mode with -e/--enable and -d/--disable flags
- Cache topology information at startup to handle offline threads correctly
- Smart display logic: online threads are always shown in the Primary column when HT is disabled
- Preserve thread pairing information even when siblings are offline
- Temporarily enable offline threads during cache to read topology files
Terminology Updates
- Use "Thread" instead of "CPU" for logical processors
- Use "Physical Core" for hardware cores
- Clarify "Primary Thread" vs "HT Sibling" throughout
- Update all messages and labels for consistency
Architecture
- Global topology cache (CACHED_SIBLINGS, CACHED_SIBLING_MAP, CACHED_PRIMARY)
- Separate functions for list and table views
- cacheTopology() function to preserve sibling relationships
- Conditional output in toggleHyperThreading() based on view mode
Usage
- Interactive mode: ./toggleHT.sh [-t]
- Direct disable: ./toggleHT.sh -d [-t]
- Direct enable: ./toggleHT.sh -e [-t]
- Help: ./toggleHT.sh -h
Nice, thank you for this usefull snippet ! 👍