1. Multitasking in Mac OS Gets 100% CPU

The following naive implementation of get_key with multitasking support causes 100% CPU in Mac OS (Mountain Lion, Eu 4.0.4). Is there a better practice? This does not cause high CPU usage in Windows 7.

Is there something I can do in Mac OS to reduce the CPU consumption?

    function editor_wait_key() 
        atom c = -1 
        while c = -1 do 
            c = get_key() 
            task_yield() 
        end while 
        return c 
    end function 

Changing task_yield to task_delay or even sleep still has the same problem:

    function editor_wait_key() 
        atom c = -1 
        while c = -1 do 
            c = get_key() 
            task_delay(0.05) 
            -- sleep(0.01) 
        end while 
        return c 
    end function 

Thanks

new topic     » topic index » view message » categorize

2. Re: Multitasking in Mac OS Gets 100% CPU

bryanso said...

The following naive implementation of get_key with multitasking support causes 100% CPU in Mac OS (Mountain Lion, Eu 4.0.4). Is there a better practice? This does not cause high CPU usage in Windows 7.

Is there something I can do in Mac OS to reduce the CPU consumption?

It's hard to say without seeing more of your code. Where does execution go when you call task_yield()? get_key() returns immediately. There's nothing there really that would lead me to believe that you'd get anything but 100% utilization until a key is pressed.

Matt

new topic     » goto parent     » topic index » view message » categorize

3. Re: Multitasking in Mac OS Gets 100% CPU

What happens when you use a longer delay? Such as:

task_delay(5) 

Does it still use 100% CPU?

new topic     » goto parent     » topic index » view message » categorize

4. Re: Multitasking in Mac OS Gets 100% CPU

I'll trim my test case down to a more manageable size and post the code. (I believe nothing has been scheduled, though, so task_yield really has nothing to do).

Hi Ryan, I think I can't use task_delay(5) in a loop that's getting user input. The user will feel the keyboard is sluggish.

Thanks all.

ryanj said...

What happens when you use a longer delay? Such as:

task_delay(5) 

Does it still use 100% CPU?

new topic     » goto parent     » topic index » view message » categorize

5. Re: Multitasking in Mac OS Gets 100% CPU

My point was to try it temporarily for troubleshooting, just to see if task_delay() itself was using 100% CPU.

new topic     » goto parent     » topic index » view message » categorize

6. Re: Multitasking in Mac OS Gets 100% CPU

bryanso said...

Hi Ryan, I think I can't use task_delay(5) in a loop that's getting user input. The user will feel the keyboard is sluggish.

If you're not really doing anything else, and this is a console program, then you should probably be using wait_key().

Matt

new topic     » goto parent     » topic index » view message » categorize

7. Re: Multitasking in Mac OS Gets 100% CPU

Hi Matt, thanks for the suggestion. It's a command shell so it's waiting for user to run something in the background, e.g. in Unix shell, one can put an & at the end of a command to run it in the background.

Ideally the input routine doesn't need to be written in two ways: wait_key when nothing is running in background; switch to get_key when there is a background job, and somehow switch back to wait_key when the background jobs complete. That's very complicated.

Again, I'll post a streamlined test case later, which will make it clear.

mattlewis said...
bryanso said...

Hi Ryan, I think I can't use task_delay(5) in a loop that's getting user input. The user will feel the keyboard is sluggish.

If you're not really doing anything else, and this is a console program, then you should probably be using wait_key().

Matt

new topic     » goto parent     » topic index » view message » categorize

8. Re: Multitasking in Mac OS Gets 100% CPU

Hi Matt,

The simplest case is the multitasking example in mini guide http://openeuphoria.org/docs/tasking.html#_645_multitaskingineuphoria
When it is run in Mac OS Mountain Lion, EU 4.0.4, the cpu goes up to 100% during the entire execution.

I don't believe this is expected as it doesn't have the same problem in Windows 7.

In a command shell application as I explained above, even when there is no scheduled background task, the cpu goes up to 100% during user data entry.
This happens only in Mac OS.

Thanks

new topic     » goto parent     » topic index » view message » categorize

9. Re: Multitasking in Mac OS Gets 100% CPU

bryanso said...

Hi Matt,

The simplest case is the multitasking example in mini guide http://openeuphoria.org/docs/tasking.html#_645_multitaskingineuphoria
When it is run in Mac OS Mountain Lion, EU 4.0.4, the cpu goes up to 100% during the entire execution.

I don't believe this is expected as it doesn't have the same problem in Windows 7.

I get this behavior on Linux. I would expect Windows to show the same thing. Most of the time is spent in the while loop:

while t1_running or t2_running do 
	if get_key() = 'q' then 
		exit 
	end if 
	task_yield() 
end while 

The other tasks don't run very often, so control returns here. When you yield here, control typically comes right back, because the other tasks aren't ready to run yet.

I tried this in WinXP, and I think it's actually using all of the CPU there, but some of it is reported for csrss.exe. The multitasking on Windows is implemented with Fibers, and I think that Fiber related activity shows up under csrss.exe. The CPU is definitely pegged while the program is running.

Matt

new topic     » goto parent     » topic index » view message » categorize

10. Re: Multitasking in Mac OS Gets 100% CPU

I don't have XP for testing. In Windows 7 the CPU usage is really awesome. Same multitask sample code, except I changed the For loops to 100 for longer run time.

csrss.exe between 1% to 7%
eui between 2% to 5%

Nothing else is out of the ordinary.

I do understand having a while loop doing get_key() is probably CPU intensive. So I'm merely looking for ideas for a better coding practice to code a "get_line" routine that's suitable as Shell command input, sometimes with background processes, sometimes not (just like a Unix shell)... without taking up 100% CPU in Linux and Mac OS. The Mac gets hot and the fan starts fanning as soon as the multitask sample is run.

I'll try task_delay within the get_key loop again tonight using the multitask sample code in Mac and report.

new topic     » goto parent     » topic index » view message » categorize

11. Re: Multitasking in Mac OS Gets 100% CPU

mattlewis said...

I get this behavior on Linux. I would expect Windows to show the same thing. Most of the time is spent in the while loop:

while t1_running or t2_running do 
	if get_key() = 'q' then 
		exit 
	end if 
	task_yield() 
end while 

The other tasks don't run very often, so control returns here. When you yield here, control typically comes right back, because the other tasks aren't ready to run yet.

I tried this in WinXP, and I think it's actually using all of the CPU there, but some of it is reported for csrss.exe. The multitasking on Windows is implemented with Fibers, and I think that Fiber related activity shows up under csrss.exe. The CPU is definitely pegged while the program is running.

On Linux, throwing sleep(1) into the main loop seems to keep the CPU usage under control (practically 0%). Using sleep(0) or any fraction < 1 (e.g. sleep(0.01)) has no effect and the CPU still spikes to 100%.

while t1_running or t2_running do 
    if get_key() = 'q' then 
        exit 
    end if 
    task_yield() 
    sleep(1) -- toggle between 0 or 1 and observe the outcome 
end while 

Interestingly, checking gnome-system-monitor with sleep(1) the "Waiting Channel" column displays hrtimer_nanosleep, but with sleep(0) it simply shows "0". Is the sleep() function not calling "nanosleep" when we pass 0 as a parameter?

-Greg

new topic     » goto parent     » topic index » view message » categorize

12. Re: Multitasking in Mac OS Gets 100% CPU

ghaberek said...
mattlewis said...

I get this behavior on Linux. I would expect Windows to show the same thing. Most of the time is spent in the while loop:

while t1_running or t2_running do 
	if get_key() = 'q' then 
		exit 
	end if 
	task_yield() 
end while 

The other tasks don't run very often, so control returns here. When you yield here, control typically comes right back, because the other tasks aren't ready to run yet.

I tried this in WinXP, and I think it's actually using all of the CPU there, but some of it is reported for csrss.exe. The multitasking on Windows is implemented with Fibers, and I think that Fiber related activity shows up under csrss.exe. The CPU is definitely pegged while the program is running.

On Linux, throwing sleep(1) into the main loop seems to keep the CPU usage under control (practically 0%). Using sleep(0) or any fraction < 1 (e.g. sleep(0.01)) has no effect and the CPU still spikes to 100%.


That there are spikes to 100% is almost expected. It's the long time between the spikes when it's sleeping that cpu should go to 0%.

useless

new topic     » goto parent     » topic index » view message » categorize

13. Re: Multitasking in Mac OS Gets 100% CPU

ghaberek said...

Interestingly, checking gnome-system-monitor with sleep(1) the "Waiting Channel" column displays hrtimer_nanosleep, but with sleep(0) it simply shows "0". Is the sleep() function not calling "nanosleep" when we pass 0 as a parameter?

-Greg

Looks like we have a bug in Wait() in be_task.c (which is used to implement the sleep() routine).

We have code in there to busy-wait if we are attempting to sleep in fractional sections, and the fractions are too small - but we also have a check so if we're sleeping for less than 1 second we just busy-wait it out.

I think this was done back when we supported DOS so we could sleep for fractional seconds from DOS apps...

new topic     » goto parent     » topic index » view message » categorize

14. Re: Multitasking in Mac OS Gets 100% CPU

useless_ said...

That there are spikes to 100% is almost expected. It's the long time between the spikes when it's sleeping that cpu should go to 0%.

I meant spikes as in "goes from almost zero to almost 100% very quickly." I suppose plateaus might be more appropriate, since after it gets to 100% it also stays there until the program exits. This would be the opposite of say, climbs, which would be "gradually increases from zero to 100% over several seconds."

jimcbrown said...

I think this was done back when we supported DOS so we could sleep for fractional seconds from DOS apps...

So, if you're actually calling to nanosleep, you could pass that fraction directly to it, correct?

-Greg

new topic     » goto parent     » topic index » view message » categorize

15. Re: Multitasking in Mac OS Gets 100% CPU

ghaberek said...
jimcbrown said...

I think this was done back when we supported DOS so we could sleep for fractional seconds from DOS apps...

So, if you're actually calling to nanosleep, you could pass that fraction directly to it, correct?

-Greg

Yes, we could. (Technically, we'd have to convert it to a set of integer values, one of which representing the micro/nanosecond value, and then pass that in - but same difference.) And in theory we'd have to busy-wait if we wanted to be able to sleep any leftover fractional value - but at such a low range, I doubt busy-waiting would make much of a difference anyways.

new topic     » goto parent     » topic index » view message » categorize

16. Re: Multitasking in Mac OS Gets 100% CPU

jimcbrown said...
ghaberek said...

Interestingly, checking gnome-system-monitor with sleep(1) the "Waiting Channel" column displays hrtimer_nanosleep, but with sleep(0) it simply shows "0". Is the sleep() function not calling "nanosleep" when we pass 0 as a parameter?

-Greg

Looks like we have a bug in Wait() in be_task.c (which is used to implement the sleep() routine).

We have code in there to busy-wait if we are attempting to sleep in fractional sections, and the fractions are too small - but we also have a check so if we're sleeping for less than 1 second we just busy-wait it out.

I think this was done back when we supported DOS so we could sleep for fractional seconds from DOS apps...

I just profiled this (on Linux) and I don't see Wait() being called at all (though I agree that we should probably move all of the waiting time in Wait() into the nanosleep call). If you add a print statement after the call to get_key(), you'll see that a lot of time is spent going around in that loop.

Most of the time is spent in nodelaych() (and really, in a call to tcsetattr), which is how we get keyboard input in non-windows systems. Windows works differently. So perhaps Win7 has a more efficient way of handling console input than XP. Perhaps our implementation of nodelaych() could be improved. Do we really need to call tcsetattr() each time we call get_key()?

Matt

new topic     » goto parent     » topic index » view message » categorize

17. Re: Multitasking in Mac OS Gets 100% CPU

mattlewis said...

Most of the time is spent in nodelaych() (and really, in a call to tcsetattr), which is how we get keyboard input in non-windows systems. Windows works differently. So perhaps Win7 has a more efficient way of handling console input than XP. Perhaps our implementation of nodelaych() could be improved. Do we really need to call tcsetattr() each time we call get_key()?

I took out the tcsetattr() call in nodelaych(), which changed the profiling, but not the CPU usage. Most time is being spent in the task scheduler() routine, which isn't surprising, since task_yield() was called over 1.5 million times.

In short, I don't think there is really any problem here. A busy loop should produce 100% CPU usage.

Matt

new topic     » goto parent     » topic index » view message » categorize

18. Re: Multitasking in Mac OS Gets 100% CPU

mattlewis said...

In short, I don't think there is really any problem here. A busy loop should produce 100% CPU usage.

While I agree that a simple busy loop should produce 100% CPU usage, I think that a tasking loop with regular calls to sleep() should not, since the OS has the opportunity to schedule other programs.

-Greg

new topic     » goto parent     » topic index » view message » categorize

19. Re: Multitasking in Mac OS Gets 100% CPU

ghaberek said...
mattlewis said...

In short, I don't think there is really any problem here. A busy loop should produce 100% CPU usage.

While I agree that a simple busy loop should produce 100% CPU usage, I think that a tasking loop with regular calls to sleep() should not, since the OS has the opportunity to schedule other programs.

-Greg

This raises the question: How does one go about implementing a non-busy-looping version of wait_key() that allows other tasks to run while waiting for a key press?

new topic     » goto parent     » topic index » view message » categorize

20. Re: Multitasking in Mac OS Gets 100% CPU

ghaberek said...
mattlewis said...

In short, I don't think there is really any problem here. A busy loop should produce 100% CPU usage.

While I agree that a simple busy loop should produce 100% CPU usage, I think that a tasking loop with regular calls to sleep() should not, since the OS has the opportunity to schedule other programs.

Well, yes, there's that. Looking deeper, I suspect that Jim is right about the busy loop for sleeps of less than a second being a DOS hold over, since nanosleep() and Windows' sleep() work with fractional seconds.

Matt

new topic     » goto parent     » topic index » view message » categorize

21. Re: Multitasking in Mac OS Gets 100% CPU

jimcbrown said...

This raises the question: How does one go about implementing a non-busy-looping version of wait_key() that allows other tasks to run while waiting for a key press?

I updated Wait() to use nanosleep for all values, then I put the input loop into its own task and scheduled the main task. So, added to the example code (I also added code to output keystrokes other than 'q' to demonstrate responsiveness):

procedure input_task( object o ) 
	integer key 
	while key != 'q' with entry do 
		if key != -1 then 
			puts(1, key ) 
		end if 
		task_yield() 
	entry 
		key = get_key() 
	end while 
	t3_running = FALSE 
end procedure 
t3 = task_create(routine_id("input_task"), {""}) 
task_schedule(t3,  {0.001, 0.05}) 
task_schedule( task_self(), {0.1, 0.5}) 
t1_running = TRUE 
t2_running = TRUE 
t3_running = TRUE 
while t3_running and (t1_running or t2_running) do 
	task_yield() 
end while 

This reduces the CPU load such that it's not really noticeable (for this minimal example that doesn't do anything).

Matt

new topic     » goto parent     » topic index » view message » categorize

22. Re: Multitasking in Mac OS Gets 100% CPU

This demonstrates task_delay has a bug. CPU remains at 100% even though the main loop and the thread both generously allow lots of delay:

include std/task.e 
 
integer t1_running 
 
procedure task1(sequence message) 
	for i = 1 to 100 do 
		printf(1, "task1 (%d) %s\n", {i, message}) 
        task_delay(1) 
	end for 
	t1_running = 0 
end procedure 
 
atom t1 = task_create(routine_id("task1"), {"Hello"}) 
 
task_schedule(t1, 10) 
t1_running = 1 
 
while t1_running do 
	if get_key() = 'q' then 
		exit 
	end if 
	 
        task_delay(5) 
end while 
new topic     » goto parent     » topic index » view message » categorize

23. Re: Multitasking in Mac OS Gets 100% CPU

bryanso said...

This demonstrates task_delay has a bug. CPU remains at 100% even though the main loop and the thread both generously allow lots of delay:

This is fixed. See ticket:819.

Matt

new topic     » goto parent     » topic index » view message » categorize

24. Re: Multitasking in Mac OS Gets 100% CPU

mattlewis said...
bryanso said...

This demonstrates task_delay has a bug. CPU remains at 100% even though the main loop and the thread both generously allow lots of delay:

This is fixed. See ticket:819.

Matt

Thanks a lot. Awesome.

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu