kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

高精度定时器 high-cpu-load

http://stackoverflow.com/questions/1125297/nanosleep-high-cpu-usage

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
#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); // usleep(1); 同样异常
	}
	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?


Answers

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.


1
2
3
4
5
6
7
int nanosleep(const struct timespec *req, struct timespec *rem);

struct timespec
{
	time_t  tv_sec;         /* seconds */
	long    tv_nsec;        /* nanoseconds */
};

这个函数功能是暂停某个进程直到你规定的时间后恢复,参数req就是你要暂停的时间,其中req->tv_sec是以秒为单位,而tv_nsec以毫 微秒为单位(10的-9次方秒)。由于调用nanosleep是是进程进入TASK_INTERRUPTIBLE,这种状态是会相应信号而进入 TASK_RUNNING状态的,这就意味着有可能会没有等到你规定的时间就因为其它信号而唤醒,此时函数返回-1,切还剩余的时间会被记录在rem中。