Processor sleep in the UI

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Processor sleep in the UI

Bill Dargel
There's something I'm not understanding. If you do a "Processor sleep:
10000" in a workspace with a doIt, Dolphin (5.0.3) grabs 100% of the CPU
(on Win2k) for the duration of the 10 seconds. Shouldn't the main
process be doing a wait on the delay semaphore, allowing the idle
process to run which should call Windows with a
MsgWaitForMultipleObjectsEx and relinquish the CPU?

I guess that having the main UI process sleep is not the greatest idea,
but it certainly seemed the simplest for what I was doing. This came up
in putting together a short script to use Word via automation to print a
file. (BTW, I was pleasantly surprised to find out how easy it was to
invoke Word and do a few things with it). The script I came up with is
shown below.

I needed to have Dolphin wait for Word to finish printing before I could
tell Word to quit. So I'm polling Word periodically to see if it's done.
But the "Processor sleep:" was sucking all the CPU and not giving Word
any processing time to do its job. On the other hand, activating some
other application on the desktop would allow it to finish up.

When I put the entire thing into a forked process, then it worked just
fine. I was thinking that I'd have to add an additional semaphore to
have the forked process signal the main process when it was done, if I
wanted to make the whole operation be synchronous with the UI process.
But if you have the UI process wait on that semaphore, then we're right
back where we started.

OK, I dug a little deeper, and I think I understand what's going on. The
idleLoop calls on Windows to wait, but gets a return because messages
are pending. It checks that the the main UI process #isAlive and
therefore doesn't fork a new main process (even though the current main
process is waiting for the sleep to expire). So the idleLoop ends up
looping without pausing, using all the CPU.

For what I really need to do, I'll probably just keep the interaction
with Word asynchronous with the main UI by using the forked process, and
let the UI process check on the state of the other process as needed.

But in general, it would be good if Dolphin could act better when a
"Processor sleep:" gets handled by the main UI process. I'm thinking
something along the lines of having the idleLoop detect when it's
spinning hot, and then (or perhaps just always) inserting a short sleep
on the Windows thread. Or anything else that would keep the idle process
from using all the CPU time. Is this worth addressing?

regards,
-Bill

[
    word := IDispatch createObject: 'Word.Application'.
    doc := (word getProperty: 'Documents')
        invoke: 'Open'
        with: fileName.
    doc invoke: 'PrintOut'.
    [(word getProperty: 'BackgroundPrintingStatus') isZero]
        whileFalse: [Processor sleep: 100].
    "close without prompts for saving"
    doc invoke: 'Close' with: 0.
    word invoke: 'Quit'.
] fork.

-------------------------------------------
Bill Dargel            [hidden email]
Shoshana Technologies
100 West Joy Road, Ann Arbor, MI 48105  USA


Reply | Threaded
Open this post in threaded view
|

Re: Processor sleep in the UI

Bill Schwab-2
Bill,

> But in general, it would be good if Dolphin could act better when a
> "Processor sleep:" gets handled by the main UI process.

Have you ever watched in amazement while IE sits deadlocked, refusing to pay
attention to the stop button?  It seems that you're better off allowing the
UI to promptly handle messages from its queue, and do any blocking on
background threads.  If you need to disable some or all of your user
interface for the duration, you can do that to prevent the user from getting
into trouble.

However, you might also be able to pump messages "in place" until Word
finishes what it is doing.  Blair posted something along those lines for
waiting for the web browser control to finish a download.  Search the
archives for pumpMessages (7/22/2002).


> I'm thinking
> something along the lines of having the idleLoop detect when it's
> spinning hot, and then (or perhaps just always) inserting a short sleep
> on the Windows thread. Or anything else that would keep the idle process
> from using all the CPU time. Is this worth addressing?

AFAIK, it's already done.  Look (carefully<g>) at InputState>>idleLoop.
When Dolphin goes idle (which happens surprisingly often), it tries to be a
good citizen by waiting on OS-dependent conditions that require attention.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Processor sleep in the UI

Bill Dargel
Bill Schwab wrote:

> Have you ever watched in amazement while IE sits deadlocked, refusing to pay
> attention to the stop button?  It seems that you're better off allowing the
> UI to promptly handle messages from its queue, and do any blocking on
> background threads.  If you need to disable some or all of your user
> interface for the duration, you can do that to prevent the user from getting
> into trouble.

Yep. That's basically where I got to, after running around the block a few
times. Throwing a few things together in a workspace to figure out how to do it,
is one thing. But integrating the functionality into an application is something
else.

> However, you might also be able to pump messages "in place" until Word
> finishes what it is doing.  Blair posted something along those lines for
> waiting for the web browser control to finish a download.  Search the
> archives for pumpMessages (7/22/2002).

Just for fun, I tried putting a "SessionManager inputState pumpMessages" right
before the "Processor sleep: 100" in the script and indeed, it behaved ok
running in the main UI process.

> AFAIK, it's already done.  Look (carefully<g>) at InputState>>idleLoop.
> When Dolphin goes idle (which happens surprisingly often), it tries to be a
> good citizen by waiting on OS-dependent conditions that require attention.

Yes, but the problem is that there _is_ a condition that requires attention.
Only the main UI process is sleeping. Since the idle process is the only process
ready to run, it just goes ahead and checks again, and again, and again, and
again, and again, and again ...

regards,
-Bill

-------------------------------------------
Bill Dargel            [hidden email]
Shoshana Technologies
100 West Joy Road, Ann Arbor, MI 48105  USA


Reply | Threaded
Open this post in threaded view
|

Re: Processor sleep in the UI

Blair McGlashan
In reply to this post by Bill Dargel
You wrote in message news:[hidden email]...
> There's something I'm not understanding. If you do a "Processor sleep:
> 10000" in a workspace with a doIt, Dolphin (5.0.3) grabs 100% of the CPU
> (on Win2k) for the duration of the 10 seconds. Shouldn't the main
> process be doing a wait on the delay semaphore, allowing the idle
> process to run which should call Windows with a
> MsgWaitForMultipleObjectsEx and relinquish the CPU?

There is a known bug in D4/D5 (#969: "Dolphin burns 100% CPU when the main
UI process blocked on a Semaphore", originally reported by Chris Uppal) that
explains this. Here are the fix notes from our bug system:

"Caused by idle process short cycling when message loop stalled:
MsgWaitForMultipleObjects returns immediately if messages have been added to
the queue since the last call to GetQueueStatue/GetMessage/PeekMessage.
Since the main UI process is the only caller of GetMessage/PeekMessage (the
VM calls GetQueueStatus() very occassionally) the idler spins in a tight
loop if a message arrives when the main UI process is blocked.

Required changes to the VM and InputState: Basically arranged such that the
VM sets the wakeup event on detection of input during sampling (so that we
can be sure that MsgWaitForMultipleObjects will wake, regardless of race
conditions), and instead of using return value from
MsgWaitForMultipleObjects in the image to determine what it was that caused
the call to return, we call GetQueueStatus() to see if any messages are
available. GetQueueStatus clears the "new message" flag so the next call to
MsgWaitForMultipleObjects(Ex) will not return immediately even if the UI
process is blocked and cannot process the new message(s)."

As you can see, your analysis is correct in that the problem is that the
idle process goes into a spin because the MsgWaitForMultipleObjects call
does not block. Essentially the fix requires a new VM, as well as image
changes that are not compatible with the old VM, and so is not patchable via
LiveUpdate. We've decided to do a new full release in order to refresh the
VM and compiler DLLs, so this fix will be available shortly, hopefully
within the next two weeks.

Regards

Blair