create account

Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager) by thecrazygm

View this thread on: hive.blogpeakd.comecency.com
· @thecrazygm ·
$9.68
Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager)
Hey everyone,

Today's post is for those who like to tinker a bit deeper with their system's performance, especially on Linux. I've put together a Python script called `smt_manager.py` that allows you to view and toggle the state of your CPU's logical processors (often known by Intel's term, Hyper-Threading, or AMD's Simultaneous Multi-Threading - SMT).

## What's SMT/Hyper-Threading and Why Mess With It?

![All 80 Threads Available](https://files.peakd.com/file/peakd-hive/thecrazygm/Enyoz36A9t6dQdFakaK6KZ69a9rrSS39KtAQwJ1EugT3HQDZHr7hjm18WL9D71V1YtE.png)

Most modern CPUs present more "cores" to the operating system than they physically have. For instance, an 8-core CPU might show up as 16 "processors." This is typically achieved by each physical core being able to handle two threads simultaneously – one primary thread and one logical (or SMT/hyper-thread).

For many everyday tasks and general multitasking, this is great! It can improve overall system responsiveness and throughput. However, there are specific situations where having these logical cores enabled can actually be detrimental to performance, or at least not beneficial:

- **Certain High-Performance Computing (HPC) Workloads:** Some computationally intensive tasks, especially those that are heavily reliant on floating-point performance or specific cache behaviors, might see no improvement or even a slight degradation with SMT enabled. The two threads on a single physical core share resources, and this contention can sometimes outweigh the benefits.
- **Specific Benchmarks:** You might find that some benchmarks give you "better" (or at least more consistent) scores with logical cores turned off, as it ensures each running process has dedicated access to a full physical core's resources without sharing.
- **Some Gaming Scenarios:** While less common now, some older games or even specific modern titles might exhibit slightly more stable framerates or reduced micro-stuttering with SMT disabled, particularly if the game isn't optimized to effectively use a high number of logical cores and prefers fewer, more powerful physical cores.
- **Virtualization:** Depending on the virtualization software and the workloads running in your VMs, you might find that assigning only physical cores to demanding VMs can lead to more predictable performance.

The ability to easily toggle these logical cores on or off without rebooting and going into the BIOS/UEFI can be handy for testing these scenarios or optimizing for specific tasks.

## Introducing `smt_manager.py`

![After Disabling 40 Logical Cores](https://files.peakd.com/file/peakd-hive/thecrazygm/23swigsaP1ZcyScQP3qKmPVRVprGVgBuFoKdmCHvGgpzTEbiZothtSyqA6A48rUzUUuhB.png)

This Python script is designed to do just that on Linux systems. It directly interacts with the `/sys/devices/system/cpu/` interface to:

1.  Identify all available CPU processors.
2.  Determine which are "primary" (physical) cores and which are "logical" (SMT/hyper-threaded) cores.
3.  Display the current online/offline status of each processor.
4.  Allow you to set all logical cores to either "online" (enabled) or "offline" (disabled).

**Important Note:** Changing CPU states requires root privileges. So, you'll need to run the script with `sudo`.

## The Code:

Here's the [GitHub Gist](https://gist.github.com/TheCrazyGM/9636e8eacc0e46b39e747efbe4b68d6a) and the script itself:

```python
#!/usr/bin/env python3

# smt-manager.py - a script for managing logical cores
# Python implementation of the original Perl script by Steven Barrett
# https://github.com/damentz/smt-manager

import argparse
import os
import subprocess
import sys

# This is the top folder where CPUs can be enumerated and more detail retrieved
SYS_CPU = "/sys/devices/system/cpu"
DEBUG = False


def get_cpu_indexes() -> list[int]:
    """
    Get a list of CPU indexes by reading the system CPU directory

    Returns:
        list[int]: A sorted list of CPU indexes
    """
    try:
        cpu_dirs = [
            d for d in os.listdir(SYS_CPU) if d.startswith("cpu") and d[3:].isdigit()
        ]
        cpu_indexes = [int(d[3:]) for d in cpu_dirs]
        return sorted(cpu_indexes)
    except OSError as e:
        sys.exit(f"Cannot open folder: {SYS_CPU}. Error: {e}")


def get_cpu_settings() -> dict[int, dict[str, str]]:
    """
    Get settings for all CPUs including core type and power state

    Returns:
        dict[int, dict[str, str]]: A dictionary mapping CPU indexes to their settings,
            where each setting is a dictionary with 'core_type' and 'power' keys
    """
    cpu_indexes = get_cpu_indexes()
    cpus = {}

    for cpu in cpu_indexes:
        siblings_file = f"{SYS_CPU}/cpu{cpu}/topology/thread_siblings_list"
        power_file = f"{SYS_CPU}/cpu{cpu}/online"

        cpu_settings = {"core_type": "unknown", "power": "offline"}

        # Populate core topology, primary / logical
        try:
            with open(siblings_file, "r") as f:
                siblings_line = f.readline().strip()
                # Handle both comma-separated and hyphen-separated formats
                if "," in siblings_line:
                    siblings = [int(s) for s in siblings_line.split(",")]
                elif "-" in siblings_line:
                    start, end = map(int, siblings_line.split("-"))
                    siblings = list(range(start, end + 1))
                else:
                    siblings = [int(siblings_line)]

                if cpu == siblings[0]:
                    cpu_settings["core_type"] = "primary"
                else:
                    cpu_settings["core_type"] = "logical"
        except (OSError, IOError):
            if DEBUG:
                print(f"[ERROR] Could not open: {siblings_file}")

        # Populate core status, online / offline
        try:
            # CPU0 is always online and doesn't have an 'online' file
            if cpu == 0:
                cpu_settings["power"] = "online"
            else:
                with open(power_file, "r") as f:
                    cpu_power = f.readline().strip()
                    if cpu_power == "1":
                        cpu_settings["power"] = "online"
        except (OSError, IOError):
            if DEBUG:
                print(f"[ERROR] Could not open: {power_file}, assuming online")
            cpu_settings["power"] = "online"

        cpus[cpu] = cpu_settings

    return cpus


def set_logical_cpus(power_state: str) -> bool:
    """
    Set all logical CPUs to the specified power state (online/offline)

    Args:
        power_state (str): The desired power state ('online' or 'offline')

    Returns:
        bool: True if any CPU state was changed, False otherwise
    """
    cpus = get_cpu_settings()
    state_changed = False
    changed_cpus = []

    for cpu in sorted(cpus.keys()):
        # Skip CPU0 as it can't be disabled
        if cpu == 0:
            continue

        if (
            cpus[cpu]["core_type"] == "logical" or cpus[cpu]["core_type"] == "unknown"
        ) and cpus[cpu]["power"] != power_state:
            power_file = f"{SYS_CPU}/cpu{cpu}/online"

            try:
                with open(power_file, "w") as f:
                    state_changed = True
                    print(f"Setting CPU {cpu} to {power_state} ... ", end="")

                    if power_state == "online":
                        f.write("1")
                    elif power_state == "offline":
                        f.write("0")

                    changed_cpus.append(cpu)
                    print("done!")
            except (OSError, IOError):
                print(
                    f"[ERROR] failed to open file for writing: {power_file}. Are you root?"
                )

    if state_changed:
        # Rebalance the interrupts after power state changes
        try:
            subprocess.run(["irqbalance", "--oneshot"], check=True)
        except (subprocess.SubprocessError, FileNotFoundError):
            print(
                "[ERROR] Failed to balance interrupts with 'irqbalance --oneshot', "
                "you may experience strange behavior.",
                file=sys.stderr,
            )

        print()

    return state_changed


def pretty_print_topology() -> None:
    """
    Print the current CPU topology in a readable format using only standard library
    """
    cpus = get_cpu_settings()

    # Get the maximum width needed for each column
    cpu_width = max(len(str(cpu)) for cpu in cpus.keys())
    type_width = max(len(cpus[cpu]["core_type"]) for cpu in cpus.keys())
    power_width = max(len(cpus[cpu]["power"]) for cpu in cpus.keys())

    # Add header width to the calculation
    cpu_width = max(cpu_width, len("CPU"))
    type_width = max(type_width, len("Core Type"))
    power_width = max(power_width, len("Power State"))

    # Calculate total table width for the title
    total_width = cpu_width + type_width + power_width + 8  # 8 for borders and padding

    # Print table title
    print("CPU Topology".center(total_width))
    print("-" * total_width)

    # Print header
    print(
        f" {'CPU':<{cpu_width}} | {'Core Type':<{type_width}} | {'Power State':<{power_width}} "
    )
    print(f" {'-' * cpu_width} | {'-' * type_width} | {'-' * power_width} ")

    # Print rows
    for cpu in sorted(cpus.keys()):
        print(
            f" {cpu:<{cpu_width}} | {cpus[cpu]['core_type']:<{type_width}} | {cpus[cpu]['power']:<{power_width}} "
        )

    print()


def main() -> None:
    parser = argparse.ArgumentParser(
        description="View current status of CPU topology or set logical cores to offline or online.",
        epilog="This script provides details about whether each CPU is physical or logical. "
        "When provided an optional parameter, the logical CPUs can be enabled or disabled.",
    )

    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        "--online", action="store_true", help="Enables all logical CPU cores"
    )
    group.add_argument(
        "--offline", action="store_true", help="Disables all logical CPU cores"
    )
    parser.add_argument("--debug", action="store_true", help="Enable debug output")

    args = parser.parse_args()

    global DEBUG
    DEBUG = args.debug

    power_state = None
    if args.online:
        power_state = "online"
    elif args.offline:
        power_state = "offline"

    pretty_print_topology()

    if power_state and set_logical_cpus(power_state):
        # If there was a change, print the new state
        pretty_print_topology()


if __name__ == "__main__":
    # Check if running as root, which is required for changing CPU states
    if os.geteuid() != 0 and (
        len(sys.argv) > 1 and ("--online" in sys.argv or "--offline" in sys.argv)
    ):
        print("You need to have root privileges to change CPU states.")
        print("Please run the script with sudo or as root.")
        sys.exit(1)

    main()
```

## How to Use It:

1.  Save the code above as a Python file (e.g., `smt_manager.py`).
2.  Make it executable: `chmod +x smt_manager.py`
3.  Run it:
    - To view current topology: `sudo ./smt_manager.py`
    - To disable logical cores: `sudo ./smt_manager.py --offline`
    - To enable logical cores: `sudo ./smt_manager.py --online`
    - For debug output: `sudo ./smt_manager.py --debug` (or add it to the online/offline commands)

The script will print the CPU topology before, and if changes are made, it will print the new topology afterward. It also attempts to run `irqbalance --oneshot` after changing CPU states to help rebalance system interrupts, which is generally a good idea.

This is definitely a more advanced tool, but for those who need this kind of control for specific performance tuning or testing on Linux, it can be quite handy.

Let me know if you've found other interesting use cases for toggling SMT!

As always,
Michael Garcia a.k.a. TheCrazyGM
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , and 105 others
👎  
properties (23)
authorthecrazygm
permlinkgeek-out-a-python-tool-to-toggle-your-cpus-logical-cores-smt-manager
categoryhive-186392
json_metadata{"app":"peakd/2025.5.9","format":"markdown","tags":["dev","tribes","archon","proofofbrain","pimp"],"users":[],"image":["https://files.peakd.com/file/peakd-hive/thecrazygm/Enyoz36A9t6dQdFakaK6KZ69a9rrSS39KtAQwJ1EugT3HQDZHr7hjm18WL9D71V1YtE.png","https://files.peakd.com/file/peakd-hive/thecrazygm/23swigsaP1ZcyScQP3qKmPVRVprGVgBuFoKdmCHvGgpzTEbiZothtSyqA6A48rUzUUuhB.png"]}
created2025-05-31 15:51:18
last_update2025-05-31 15:51:18
depth0
children7
last_payout2025-06-07 15:51:18
cashout_time1969-12-31 23:59:59
total_payout_value4.458 HBD
curator_payout_value5.225 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length11,943
author_reputation88,579,278,070,605
root_title"Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager)"
beneficiaries
0.
accountthecrazygm.bank
weight1,500
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id143,082,260
net_rshares32,345,371,666,376
author_curate_reward""
vote details (170)
@ecoinstant ·
$0.02
Amazing custom core manager script!  That box of tricks of yours is amazing!!

!PAKX
!PIMP
!PIZZA
👍  ,
properties (23)
authorecoinstant
permlinkre-thecrazygm-sx4vje
categoryhive-186392
json_metadata{"tags":["hive-186392"],"app":"peakd/2025.5.9","image":[],"users":[]}
created2025-05-31 16:09:15
last_update2025-05-31 16:09:15
depth1
children1
last_payout2025-06-07 16:09:15
cashout_time1969-12-31 23:59:59
total_payout_value0.012 HBD
curator_payout_value0.012 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length97
author_reputation847,683,774,997,027
root_title"Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager)"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id143,082,586
net_rshares79,782,342,739
author_curate_reward""
vote details (2)
@pakx ·
<center><table><tr></tr><tr><td><center><img src='https://files.peakd.com/file/peakd-hive/pakx/PakX-logo-transparent.png'><p><sup><a href='https://hive-engine.com/?p=market&t=PAKX'>View or trade </a> <code>PAKX</code> tokens.</sup></p></center></td><td><center>@ecoinstant, PAKX has voted the post by @thecrazygm. (1/2 calls)</p><br><br><p>Use !PAKX command if you hold enough balance to call for a @pakx vote on worthy posts! More details available on <a href='/@pakx'>PAKX Blog</a>.</p></center></td></tr></table></center>
properties (22)
authorpakx
permlinkre-ecoinstant-1748707793
categoryhive-186392
json_metadata"{"tags": ["pakx", "hivepakistan"], "app": "HiveDiscoMod"}"
created2025-05-31 16:09:51
last_update2025-05-31 16:09:51
depth2
children0
last_payout2025-06-07 16:09:51
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length524
author_reputation54,807,837,621
root_title"Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager)"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id143,082,594
net_rshares0
@hivebuzz ·
Congratulations @thecrazygm! You received a personal badge!

<table><tr><td>https://images.hive.blog/70x70/https://hivebuzz.me/badges/pud.png?202506011208</td><td>You powered-up at least 10 HIVE on Hive Power Up Day!<br>Wait until the end of Power Up Day to find out the size of your Power-Bee.<br>May the Hive Power be with you!
</td></tr></table>

<sub>_You can view your badges on [your board](https://hivebuzz.me/@thecrazygm) and compare yourself to others in the [Ranking](https://hivebuzz.me/ranking)_</sub>


**Check out our last posts:**
<table><tr><td><a href="/hive-122221/@hivebuzz/pum-202505-result"><img src="https://images.hive.blog/64x128/https://i.imgur.com/mzwqdSL.png"></a></td><td><a href="/hive-122221/@hivebuzz/pum-202505-result">Hive Power Up Month Challenge - May 2025 Winners List</a></td></tr><tr><td><a href="/hive-122221/@hivebuzz/pum-202506"><img src="https://images.hive.blog/64x128/https://i.imgur.com/M9RD8KS.png"></a></td><td><a href="/hive-122221/@hivebuzz/pum-202506">Be ready for the June edition of the Hive Power Up Month!</a></td></tr><tr><td><a href="/hive-122221/@hivebuzz/pud-202506"><img src="https://images.hive.blog/64x128/https://i.imgur.com/805FIIt.jpg"></a></td><td><a href="/hive-122221/@hivebuzz/pud-202506">Hive Power Up Day - June 1st 2025</a></td></tr></table>
properties (22)
authorhivebuzz
permlinknotify-1748779980
categoryhive-186392
json_metadata{"image":["https://hivebuzz.me/notify.t6.png"]}
created2025-06-01 12:13:00
last_update2025-06-01 12:13:00
depth1
children0
last_payout2025-06-08 12:13:00
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length1,313
author_reputation369,401,014,246,496
root_title"Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager)"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id143,098,416
net_rshares0
@pizzabot ·
<center>PIZZA!


$PIZZA slices delivered:
@ecoinstant<sub>(1/20)</sub> tipped @thecrazygm 


<sub>Come get [MOON](https://moon.hive.pizza)ed!</sub></center>
properties (22)
authorpizzabot
permlinkre-geek-out-a-python-tool-to-toggle-your-cpus-logical-cores-smt-manager-20250531t160938z
categoryhive-186392
json_metadata"{"app": "pizzabot"}"
created2025-05-31 16:09:39
last_update2025-05-31 16:09:39
depth1
children0
last_payout2025-06-07 16:09:39
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length156
author_reputation7,553,614,105,110
root_title"Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager)"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id143,082,591
net_rshares0
@tydynrain · (edited)
$0.02
Super cool! I've been tweaking my Arch Linux systems for years, so I love tools like this. I'm going to give it a try. I could also make BASH alias for the toggle commands, like smton and smtoff, to make to even simpler and quicker. Thank you for your awesome tools! 😁 🙏 💚 ✨ 🤙 
👍  
properties (23)
authortydynrain
permlinkre-thecrazygm-2025531t21333295z
categoryhive-186392
json_metadata{"tags":["dev","tribes","archon","proofofbrain","pimp"],"app":"ecency/3.2.0-vision","format":"markdown+html"}
created2025-06-01 07:33:33
last_update2025-06-02 05:29:03
depth1
children2
last_payout2025-06-08 07:33:33
cashout_time1969-12-31 23:59:59
total_payout_value0.009 HBD
curator_payout_value0.010 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length277
author_reputation202,290,202,792,574
root_title"Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager)"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id143,095,390
net_rshares63,597,090,007
author_curate_reward""
vote details (1)
@thecrazygm ·
bash alias is a smart move if you plan on using it often.

Give it a try, I don't know what kind of CPU you are using, but I have found that even as counter intuitive as it sounds, some things build from source faster with the logical cores turned off.
👍  
properties (23)
authorthecrazygm
permlinkre-tydynrain-sx6pze
categoryhive-186392
json_metadata{"tags":["hive-186392"],"app":"peakd/2025.5.9"}
created2025-06-01 16:04:30
last_update2025-06-01 16:04:30
depth2
children1
last_payout2025-06-08 16:04:30
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length252
author_reputation88,579,278,070,605
root_title"Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager)"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id143,102,646
net_rshares8,267,877,812
author_curate_reward""
vote details (1)
@tydynrain ·
I tried it this morning, and it works perfectly well on my 10th generation i7 (*skylake*), and I did end up creating aliases for the commands. Now I just have to test assorted  things to see if I notice a difference. I used to build from source all the time, and I'd like to get back to it, though I need a bit more time...lol! I dig it mucho! 😁 🙏 💚 ✨ 🤙 
👍  
properties (23)
authortydynrain
permlinkre-thecrazygm-202561t19348291z
categoryhive-186392
json_metadata{"tags":["hive-186392"],"app":"ecency/3.2.0-vision","format":"markdown+html"}
created2025-06-02 05:34:12
last_update2025-06-02 05:34:12
depth3
children0
last_payout2025-06-09 05:34:12
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length354
author_reputation202,290,202,792,574
root_title"Geek Out: A Python Tool to Toggle Your CPU's Logical Cores (SMT Manager)"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id143,114,313
net_rshares51,995,721,338
author_curate_reward""
vote details (1)