tags:

views:

778

answers:

13

If I have an empty while loop in my code such as:

while(true);

It will drive the processor usage up to about 25%. However if I do the following:

while(true)
    Sleep(1);

It will only use about 1%.

So why is that?

Update: Thanks for all the great replies, but I guess I really should have asked this question, http://stackoverflow.com/questions/175882/whats-the-algorithm-behind-sleep which is more of want I wanted to know.

A: 

Because you're keeping the processor busy evaluating the loop over annd over.

Using Sleep actually lets other threads execute on the CPU and along with a very short context switch looks as if the CPU is free for a short while.

Dror Helper
+7  A: 

The first continuously uses CPU operations. The latter switches the context of the currently running thread, putting is in sleep mode, thus allowing for other processes to be scheduled.

Scooterville
A: 

Because the Sleep is basically telling the processor to switch contexts and let some other programs get more CPU time.

Ed Swangren
A: 

A cpu can do some billion operations per second. This means the empty loop runs mybe one million times per second. The loop with the sleep statement runs only 1000 times per second. In this case the cpu has some operations per second left to do other things.

Say we have a 3GHz cpu. 3Ghz = 3 000 000 000Hz - The cpu can run the loop three bilion times a second (simplyfied).

With the sleep statement the loop is executed 1000 times a second. This means the cpu load is

1000 / 3 000 000 000 * 100 = 0.0001%

Gabb0
Most CPU's out there are in the Ghz range, not Mhz.
Ed Swangren
yes, i missed some 0's. fixed that
Gabb0
+30  A: 

With the former, the condition true must be checked by the processor as often as the application can possibly get focus. As soon as the application gets processor attention, it checks true, just like any other loop condition, to see if the next instruction in the loop can be executed. Of course, the next instruction in the loop is also true. Basically, you are forcing the processor to constantly determine whether or not true is true, which, although trivial, when performed constantly bogs the processor down.

In the latter, the processor checks true once, and then executes the next statement. In this case, that is a 1ms wait. Since 1 ms is far greater than the amount of time required to check true, and the processor knows it can do other things during this wait, you free up a lot of power.

JoshJordan
+1.1 good explanation.. -0.1 no mention on why it's 25%... ;)
Sani Huttunen
Compilers will often optimise `while(true){}` into an unconditional jump to the same instruction, like `jmp $`. In this case there's no need to check `true`, it's just a jump instruction that keeps getting executed.
Artelius
@Artelius - It's still unconditionally jumping possibly billions of times a second. When you add in a `sleep` statement, the processor jumps in a tiny fraction of a second, and then sleeps for a long time. As to why it's 25%, @CKret, that's purely dependent on the architecture. There's no way to say why without knowing what kind of processor the OP has (and how many).
Chris Lutz
@Chris: Did I say otherwise?
Artelius
A: 

The sleep in the second one is kinda like a 'yield' to the OS's process scheduler.

Dustin Getz
Not really. The program automatically gets yielded whenver its timeslice is over, which (while running) is thousands of times a second anyway. `Sleep` tells the OS to set the process's state to "sleeping" and wake it up after some duration has elapsed.
Artelius
Actually windows kernels don't interrupt that much, real-time systems or low latency linux kernels could interrupt thousands of times per second, but this is limited to the precision of the PIT.
Yannick M.
Hmm, I thought Linux used HZ = 1000 but it seems a bit more variable than that. And I'm not actually sure if 1 tick = 1 timeslice. Well, let's call it "tens or hundreds of times a second".
Artelius
@Artelius: While what you are saying is correct (the control is forcefully taken away from the thread once its timeslice is over), the thread might decide to yield [the remainder of] it's timeslice prematurely, on its own accord, if it has nothing else to do. In Windows it is normally done through `Sleep(0)`.
AndreyT
+19  A: 

I am going to guess that you have four cores on your multicore processor, which would explain the 25%, as you are completely tying up one processor doing your busy loop, as the only break in it is when the application is delayed so another application can run (but that may not happen depending on the load).

When you put a thread to sleep then it allows the OS to do other operations, and it knows when, as a minimum, to come back and wake up the thread, so it can continue it's work.

James Black
the hidden advantage of having more than one CPU core -- it protects you from badly written code! seriously!
Jeff Atwood
+1 quad core related to 25%...
Sani Huttunen
Four multicores? How many cores does each of these multicores have? :P
Artelius
Cute, ok, four cores on the multicore. :)
James Black
@Jeff That's a double-edged sword, people will write more bad code if they can get away with it (or don't even notice).
starblue
@Jeff: Any OS that can't protect you from badly written code is broken :). To quote my lecturer, "Windows is broken. Linux is broken. OS X is broken." He was making the point that Solaris is the only OS in this list with decent resource management.
Artelius
@Artelius - Under Solaris I have used up all the resources, mainly due to memory leaks and one time where it kept forking new processes until the server was hosed. :) I accidentally hit a key while using vi on the production server, as I was trying to do something with the vi key commands.
James Black
@Jeff, not from VERY badly written code. Just single threaded bad code.
Thorbjørn Ravn Andersen
@James Black, if that happens every time you hit a key in vi on a production machine you may want to switch to Emacs.
Thorbjørn Ravn Andersen
@Thorbjørn Ravn Andersen - on the production servers I didn't have emacs the only editors was vi or ed. Ed is not my friend. <g>
James Black
A: 

Take a look at Preemption

lsalamon
Why? The sleeping process doesn't gets pre-empted (because it will repeatedly yield well before its timeslice is over) while the busy-looping process gets pre-empted all the time, but the scheduler lets it continue running because there is enough spare CPU for it.
Artelius
You have to see it this way: it's like a slice of CPU to other processes is reduced.
lsalamon
+6  A: 

You have a quad-core machine, am I right? If so,

while(true);

is actually using 100% of one of your cores.

To the operating system, it seems your program has a lot of work to do. So the operating system lets the program go ahead with this work. It can't tell the difference between your program number crunching like crazy, and doing a useless infinite loop.

Sleep(1);

on the other hand explicitly tells the operating system that your have no work to do for the next millisecond. The OS will thus stop running your program and let other programs do work.

Artelius
+5  A: 

An empty loop isn't actually empty. A loop in itself is at least a comparison and a jump back to the comparison. Modern CPUs can do millions of these operations per second.

The sleep statement in the second loop relinquishes control to the operating system for at least 1 millisecond. In this state, the application is effectively halted and does not continue processing. The result of halting for x amount of time reduces the number of comparisons, and hence the % of cpu clock cycles the cpu can execute per second.

Concerning the 25%, Intel processors that support Hyperthreading or multi core processors might taint the performance statistics. The empty loop is effectively topping off at least one processor core.

Back in the day when multicore CPUs didn't exist, the users did have the need for multi processing/tasking. There are a couple of ways the illusion of running multiple processes at the same time was achieved.

One way was to design application in such a way that they needed to relinquish control to the system ever so often, as to let other processes run for a while. This was the case in the old Windows versions. If a given application was badly designed so that it didn't relinquish control, or got stuck in an endless loop, your entire PC effectively froze up.

Needless to say this wasn't the best way, and it was replaced by preemptive multitasking. Here a Programmable Interrupt Timer is instructed to interrupt the running process at a given interval to execute some scheduler code that lets the other processes have a go.

Yannick M.
Sorry for nitpicking, but an empty loop *is* empty as this expression refers to the body, not the loop code itself.
Georg Fritzsche
I was merely trying to note that an empty loop does require processing even if it has no body. This might be counter-intuitive for people that are new to programming.
Yannick M.
+2  A: 

Basically, you've got several "process scheduler" states. I'll name three of them. One: Ready Two: Running Three: Blocked

These states / queues only exist because of the limited number of cores on your processor. In Ready, processes are scheduled that are totally ready for execution. They don't have to wait for input, time, or whatever. On Running, processes actually "have" the processor and thus ARE running. State Blocked means your process is waiting for an event to happen before queueing for the processor.

When you keep on testing for while(true) you keep your process in the "ready" queue. Your process scheduler gives it a certain amount of time, and after a while, removes it from the processor (placing it on the back of the "ready" queue). And thus your process will keep coming back "on" the processor, keeping it busy.

When you execute a "sleep" statement, your process will not be scheduled on process until the prerequisity is fulfilled - in this particular case, as long as the time passed after the "sleep" command <= 1000 ms.

vstrien
A: 

Because that would run instructions all the time.

Normal programs don't madly run instructions all the time.

For instance, GUI programs just sit idle waiting for events, (such as keyboard input),

Note: sitting idle != while(true);

They only run instructions when events arrive, and the event-handling code is usually small and runs very quickly, (otherwise, the program will appear to be not-responding). Imagine your app gets 5 keystrokes per second, how much CPU time would it take?

That's why normal processes don't take that much CPU.

Now, earlier I said that sitting idle is not the same as an infinite empty loop. Why is that? Sitting idle means telling the OS that you don't have anything to run.

An infinite loops actually is something to run (a repeating jump instruction).

On the other hand, having nothing to run means basically that the OS won't even bother giving you any processor time at all, even if it's your turn.

Another example where programs sit idle is loading files: when you need to load a file, you basically send a signal to the disk and wait for it to find the data and load it into memory. While the data is being loaded (several milliseconds), the process just sits idle, doing nothing.

Yet another instance of a process sitting idle, is Sleep(1), here it's explicitly telling the OS not to give it any cpu-time before the specified time has passed.

hasen j
+1  A: 

Sleep() is not really doing anything during the period that the thread is sleeping. It hands its time over to other processes to use. A loop on the other hand is continuously checking to see if the condition is true or false.

Joe Philllips