Disabling Hyperthreading

posted Mar 12, 2012, 4:28 PM by Tyler Akins   [ updated Apr 12, 2013, 11:46 AM ]
I never thought I would find what I feel is a really bad problem with the Linux scheduler, but it's hard to argue with my results.  I have an Acer Aspire One netbook and it has an 1.5 Ghz Intel Atom N550 inside.  It is a dual-core CPU with hyperthreading enabled.

At first I thought I was crazy or that something was fundamentally broken with my recent Ubuntu install on this fine machine.  I had been used to an HP Mini 110.  It's a dual core 1 Ghz AMD processor, and I expected better performance from this one.  Instead, I had found that my programs seemed to frequently hang, really crawl slowly, or sporadically operate well.  Very odd behavior.  I found, through use of my Mad Google Skillz, that it could be due to hyperthreading on the processor.  You see, hyperthreading isn't a real processing thread.  It's more like sharing parts of the same processing unit.  While one is doing an addition, another could use the unused multiplication routine.  If they both want to use bits of the CPU that overlap, then one process just has to wait.  In my case, that starved process waited and waited and waited.  It looked like Linux thought the hyperthreading was another core and treated it as though it could safely and quickly run threads on any of the available cores.  Thus, lots of jobs were running on the first core and few were running on the seconds.  The ones sharing a real core all got stalled.

Manually Disabling Hyperthreading

I found that the Ubuntu kernel, as well as RedHat and others, compile in an option to disable use of a CPU on the fly.  Fantastic!  Running two commands as root will kill the hyperthreading on my machine.

echo 0 > /sys/devices/system/node/node0/cpu1/online
echo 0 > /sys/devices/system/node/node0/cpu3/online

Your CPU numbers may not match mine, so I don't suggest you use the above.

Now you might be wondering how you can get this to happen automatically on machines when they start up.  You can edit /etc/rc.local and add those two lines above the 'exit' line, but if the machine changes and you now don't have hyperthreading, then maybe you disabled two processors in your quad core machine.  Yikes!  Since programs are supposed to detect things like this and do work for you, I scoured the internet and tried to find a way to detect if a CPU is a hyperthreading CPU or not.  I didn't come up with anything at all.

But that didn't stop me.

Automatically Disabling Hyperthreading

I wrote this code to detect and disable all hyperthreading that looks like processors.  You can use this on any machine, whether or not it has hyperthreading and no matter how many processors and cores it actually has.  Let me know if this works well for you or what could be changed to make everyone happier.

Update 2013-03-22:  Linux 2.6.x uses a comma as a separator, so changed cut -d '-' -f 1 to a sed command.

#!/bin/bash

# Be careful to not skip the space at the beginning nor the end
CPUS_TO_SKIP=" $(cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list | sed 's/[^0-9].*//' | sort | uniq | tr "\r\n" "  ") "


for CPU_PATH in /sys/devices/system/cpu/cpu[0-9]*; do
    CPU="$(echo $CPU_PATH | tr -cd "0-9")"
    echo "$CPUS_TO_SKIP" | grep " $CPU " > /dev/null
    if [ $? -ne 0 ]; then
        echo 0 > $CPU_PATH/online
    fi
done

With the above script saved safely on my hard drive and /etc/rc.local running this shell command, I automatically disable hyperthreading just after boot... until my machine gets cloned to another netbook that doesn't have hyperthreading, and then no CPUs are disabled.  The best of both worlds.
Comments