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 |
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 |
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 |
Free forum by Nabble | Edit this page |