views:

837

answers:

2

I noticed that a little test program which calls nanosleep is showing a huge difference in CPU usage when run on Linux machines with a kernel newer than 2.6.22.

#include <time.h>
int main (void)
{
    struct timespec sleepTime;
    struct timespec returnTime;
    sleepTime.tv_sec = 0;
    sleepTime.tv_nsec = 1000;
    while (1)
    {
      nanosleep(&sleepTime, &returnTime);
    }
    return 0;
}

(Yes, I realise this program does nothing)

If I compile this and run it on an openSUSE 10.3 machine (2.6.22.19-0.2-default), the program does not even show up on the process list generated by "top", indicating to me that it is using very little CPU time. If I run it on an openSUSE 11.1 machine (2.6.27.23-0.1-default), top shows the program taking 40% of the CPU time. Running on Fedora 9 (2.6.25-14.fc9.i686) and Fedora 10 also showed the same high CPU usage in "top".

Has there been a change in the kernel that affects this?

+1  A: 

I don't have a definitive answer... but the first thing I would look at is the config options with which the kernel was compiled:

cat /boot/config-`uname -r`

Options that I think might be relevant are CONFIG_HZ, CONFIG_HPET_TIMER and CONFIG_HIGH_RES_TIMERS. Maybe those differ among your kernels... that might help you narrow it down.

It used to be on 2.4 kernels that nanosleep would busy-wait for waits of under 2 ms if running under real-time scheduler policies (SCHED_FIFO or SCHED_RR, see the nanosleep man page), but since all of the kernels are 2.6, that doesn't seem to be a factor.

Martin B
+4  A: 

This is due to the introduction of NO_HZ into the mainline scheduler.

Previously, your 1,000 ns sleep was usually sleeping for a whole tick - 1,000,000 ns. Now, when the machine is otherwise idle, it's actually only sleeping for what you asked for. So it's running the while() loop and syscall around 1,000 times more frequently - hence a lot more CPU usage. If you increase tv_nsec you should see a reduction in the CPU usage.

caf