The serverMode flag and some thoughts on event polling

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

The serverMode flag and some thoughts on event polling

Dimitry Golubovsky
 
Hi,

[this is not really about VM alone, but rather how image and VM
interact - hence posting to multiple lists]

In the process of porting Cog to Android, I observed the following
pattern. If a scrollbar's "up" or "down" button is held pressed
(prolonged tap on a button) for few seconds, the VM freezes, and gets
killed by Android. Digging down the code got me to the
WorldState>>interCyclePause: method. When there are morphs requesting
stepping by shorter than certain time interval, the process
responsibke for running step methods keeps looping without giving up
to lower priority processes (and the host OS). ScrollBar seems to
decrease the stepping interval over time to simulate accelerated
scrolling.

In order to port Cog to Android, I turned it into an event-driven VM
based on ideas found in [1]. The same was done by Andreas for his
earlier Classic VM port. My approach is a bit different such as the
longjmp call is made as part of the relinquishProcessor primitive.
Such primitive is called only from the lowest priority (idle) process
which only can run when there are no external events to deal with. The
event-driven VM needs to exit from the interpreter to the host process
in order to obtain any input events. Thus, non-interrupted polling
just deadlocks the interpreter as it cannot exit to the host process
to get more events, yet keeps polling for them.

The serverMode flag [2] (aka Mantis #6581) came to rescue. With such
flag set to true, polling for events always yields CPU for 50ms (which
in the Android case is meaningless anyway: I would not give the VM
idle timer more often than 10 times per sec, so 50ms granularity is
just not handleable). Anyway this does the trick as the lowest
priority process gets its CPU time, and exits the interpreter to the
host process. With serverMode = true I can tap a scroller button as
long as I want, and even the text cursor in a workspace keeps blinking
which means that stepping works and VM is alive. BTW in Android, the
interpreter will be called as soon as any user action is intercepted,
so responsiveness is not degraded regardless of the delay introduced
by serverMode.

I have found at least one place (this is in PharoCore) where
serverMode is not honored: PolygonMorph class >> fromHand: (this
method creates a polygon drawn by the mouse)

This method has code pieces (repeating multiple times btw - why is it
not a separate method?)

[Sensor anyButtonPressed] whileFalse:
  [self currentWorld displayWorldSafely; runStepMethods].

which is clearly grabbing the event sensor to the polygon morph while
keeping other morphs stepped, so the VM does not seem dead entirely.
In my case though executing PolygonMorph fromHand: defaultHand freezes
the VM immediately as this is uninterrupted polling again.

While I'll try to experiment with inserting interCyclePause somewhere
in these loops, there are broader questions on how event polling is
done these days:

1. Are there other morphs in packages not included in PharoCore where
event grabbing is done such way?

1a. Is this possible in general to have such functionality properly
embedded in WorldState instead of having it in a morph itself, if
event grabbing is needed?

2. Are there images in active development (other than PharoCore, and
Squeak) where event polling is done without an option to relinquish
processor?

In fact, this VM freezing on stepping morphs was a big issue, and it
mainly kept me from moving towards the public release. Now that it
seems to be solved (unless there is a flaw in my logic above) it takes
me closer to finishing the Cog for Android port.

Thanks.

------------------------------------------
[1] http://lists.squeakfoundation.org/pipermail/vm-dev/2009-November/003385.html
[2] http://bugs.squeak.org/view.php?id=6581

--
Dimitry Golubovsky

Anywhere on the Web
Reply | Threaded
Open this post in threaded view
|

Re: The serverMode flag and some thoughts on event polling

David T. Lewis
 
On Thu, Aug 25, 2011 at 01:01:10PM -0400, Dimitry Golubovsky wrote:
>  
> Hi,
>
> [this is not really about VM alone, but rather how image and VM
> interact - hence posting to multiple lists]

Dimitry,

Thank you for this detailed and helpful explanation. I hope it
generates some follow up discussion.

Dave


>
> In the process of porting Cog to Android, I observed the following
> pattern. If a scrollbar's "up" or "down" button is held pressed
> (prolonged tap on a button) for few seconds, the VM freezes, and gets
> killed by Android. Digging down the code got me to the
> WorldState>>interCyclePause: method. When there are morphs requesting
> stepping by shorter than certain time interval, the process
> responsibke for running step methods keeps looping without giving up
> to lower priority processes (and the host OS). ScrollBar seems to
> decrease the stepping interval over time to simulate accelerated
> scrolling.
>
> In order to port Cog to Android, I turned it into an event-driven VM
> based on ideas found in [1]. The same was done by Andreas for his
> earlier Classic VM port. My approach is a bit different such as the
> longjmp call is made as part of the relinquishProcessor primitive.
> Such primitive is called only from the lowest priority (idle) process
> which only can run when there are no external events to deal with. The
> event-driven VM needs to exit from the interpreter to the host process
> in order to obtain any input events. Thus, non-interrupted polling
> just deadlocks the interpreter as it cannot exit to the host process
> to get more events, yet keeps polling for them.
>
> The serverMode flag [2] (aka Mantis #6581) came to rescue. With such
> flag set to true, polling for events always yields CPU for 50ms (which
> in the Android case is meaningless anyway: I would not give the VM
> idle timer more often than 10 times per sec, so 50ms granularity is
> just not handleable). Anyway this does the trick as the lowest
> priority process gets its CPU time, and exits the interpreter to the
> host process. With serverMode = true I can tap a scroller button as
> long as I want, and even the text cursor in a workspace keeps blinking
> which means that stepping works and VM is alive. BTW in Android, the
> interpreter will be called as soon as any user action is intercepted,
> so responsiveness is not degraded regardless of the delay introduced
> by serverMode.
>
> I have found at least one place (this is in PharoCore) where
> serverMode is not honored: PolygonMorph class >> fromHand: (this
> method creates a polygon drawn by the mouse)
>
> This method has code pieces (repeating multiple times btw - why is it
> not a separate method?)
>
> [Sensor anyButtonPressed] whileFalse:
>   [self currentWorld displayWorldSafely; runStepMethods].
>
> which is clearly grabbing the event sensor to the polygon morph while
> keeping other morphs stepped, so the VM does not seem dead entirely.
> In my case though executing PolygonMorph fromHand: defaultHand freezes
> the VM immediately as this is uninterrupted polling again.
>
> While I'll try to experiment with inserting interCyclePause somewhere
> in these loops, there are broader questions on how event polling is
> done these days:
>
> 1. Are there other morphs in packages not included in PharoCore where
> event grabbing is done such way?
>
> 1a. Is this possible in general to have such functionality properly
> embedded in WorldState instead of having it in a morph itself, if
> event grabbing is needed?
>
> 2. Are there images in active development (other than PharoCore, and
> Squeak) where event polling is done without an option to relinquish
> processor?
>
> In fact, this VM freezing on stepping morphs was a big issue, and it
> mainly kept me from moving towards the public release. Now that it
> seems to be solved (unless there is a flaw in my logic above) it takes
> me closer to finishing the Cog for Android port.
>
> Thanks.
>
> ------------------------------------------
> [1] http://lists.squeakfoundation.org/pipermail/vm-dev/2009-November/003385.html
> [2] http://bugs.squeak.org/view.php?id=6581
>
> --
> Dimitry Golubovsky
>
> Anywhere on the Web
Reply | Threaded
Open this post in threaded view
|

Re: The serverMode flag and some thoughts on event polling

Andreas.Raab
In reply to this post by Dimitry Golubovsky
 
Hi Dimitry -

On 8/25/2011 19:01, Dimitry Golubovsky wrote:
> In order to port Cog to Android, I turned it into an event-driven VM
> based on ideas found in [1]. The same was done by Andreas for his
> earlier Classic VM port. My approach is a bit different such as the
> longjmp call is made as part of the relinquishProcessor primitive.

I think that relying exclusively on relinquishProcessor is a mistake.
It's a fine approach for situations where there is low CPU utilization
and relinquishProcessor is called often, but it doesn't really work
under high load.

Rather than relying on relinquishProcessor implicitly, I would suggest
you either change (or add another) primitive that such that ioRelinquish
always executes the return to the OS. This is advantageous to the
serverMode flag (which for other reasons is somewhat silly) as you can
modify the Morphic base loops to Do The Right Thing, for example by
adding the primitiveRelinquish to WorldState>>interCyclePause. This
means that even if there is more computational power needed than there
is available (in other words, relinquishProcessor never gets called from
the idle loop) you are making sure that you do get back to the OS at
well-defined points (such as after completing a Morphic cycle) which
prevents the OS from thinking we're non-responsive.

> The serverMode flag [2] (aka Mantis #6581) came to rescue. With such
> flag set to true, polling for events always yields CPU for 50ms (which
> in the Android case is meaningless anyway: I would not give the VM
> idle timer more often than 10 times per sec, so 50ms granularity is
> just not handleable).

But this only works if your UI is eating up all the cycles. If, for
example, you have a simulation running at lower (or higher) priority,
Android will still think that the app is dead. That's why the explicit
relinquish primitive is advantageous from my point of view - it gives
you control over when and where to hand back control.

> This method has code pieces (repeating multiple times btw - why is it
> not a separate method?)
>
> [Sensor anyButtonPressed] whileFalse:
>     [self currentWorld displayWorldSafely; runStepMethods].
>
> which is clearly grabbing the event sensor to the polygon morph while
> keeping other morphs stepped, so the VM does not seem dead entirely.
> In my case though executing PolygonMorph fromHand: defaultHand freezes
> the VM immediately as this is uninterrupted polling again.

With an explicit relinquish primitive you can 'fix' those loops simply
by inserting a "Processor relinquishProcessor" or somesuch. It might be
better to rewrite code like the above entirely, but at the very least
you have an easy workaround.

> While I'll try to experiment with inserting interCyclePause somewhere
> in these loops, there are broader questions on how event polling is
> done these days:
>
> 1. Are there other morphs in packages not included in PharoCore where
> event grabbing is done such way?

Almost certainly, yes. Historically, the way to grab modal input used to
be along the lines of, e.g., "[Sensor anyButtonPressed] whileTrue" and
there are definitely more packages out there that do stuff like it.

> 1a. Is this possible in general to have such functionality properly
> embedded in WorldState instead of having it in a morph itself, if
> event grabbing is needed?

Absolutely. One just needs to write the proper code :-)

> 2. Are there images in active development (other than PharoCore, and
> Squeak) where event polling is done without an option to relinquish
> processor?

Yes. But likely nobody will want to run these in unmodified form on
Android so I wouldn't worry about too much about it.

Cheers,
   - Andreas