How to calculate frame cycle remaining time?

I’m having trouble finding functionality in the Corona SDK API that would let me calculate the time left in a display cycle. Maybe the runtime doesn’t work the way I imagine.

I would think the runtime starts a frame cycle every (e.g.) 16 2/3 ms, paints the screen, then executes my Lua code by servicing any outstanding events. Presumably, the time left in the cycle varies depending on the complexity of what the runtime has been asked to do. I would like to  know how much time is left in that cycle.

Why?  Optional work could be postponed if I’m in danger of dropping frames. More simply, a debug statement could tell me where/when I’m coming closest to dropping frames so I know where it’s worth trying to optimize.

Is there any way to get an accurate calculation of remaining time, or do people have some technique that obviates the need for this?

  1. Frame durations will vary although the SDK will try to match the requested frame rate.

  2. In this blog post I shared one of two techniques (that I know) used to ‘defer work’ if you’re almost  out of frame time:

https://coronalabs.com/blog/2015/05/12/tutorial-responsive-real-time-searching/

Thanks, I hadn’t seen that blog post. So, it appears that the Corona runtime does not expose the crucial data, leaving only the sort of guessing game your code demonstrates.

If Corona SDK would even just guarantee that it services “enterFrame” events before any other callbacks in a given frame cycle, then I could store a “previous” system time and subtract to discover how long the runtime took to paint.

Unfortunately, I see no such promise claimed in the docs. All the “enterFrame” page claims is that it will occur “occur at the FPS interval”, which of course also isn’t guaranteed. I guess I could experiment and see whether it happens to be true that “enterFrame” is always placed at the head of the event queue and, if so, hope that undocumented behavior doesn’t change in some future build.

  1. Considering what Corona can do, I wouldn’t be too critical.  Also, you can always request a feature and post a link back here to the request.  I’d vote for it.

http://feedback.coronalabs.com/forums/188732-corona-sdk-feature-requests-feedback

  1. That is exactly what you can do:

I could store a “previous” system time and subtract to discover how long the runtime took to paint.

You won’t however get the paint time.  You’ll get the time since the last enterFrame event.  

  1. Regarding intervals and guarantees.  In modern computing systems, exact tolerances for tween events cannot be guaranteed.  Too many factors can preempt the current process.  Corona does a pretty good job and usually, if a frame is missed it is because the user has done too much scripting work in one interval.

@ronburk,

You’ve posited an interesting question re: event processing order.  I’ll see if I can come up with a test bench for this and share it when I do.

Also, I’ve asked a similar question before: “How can I know how much time I have left to do ‘work’ in?”   Eventually, I simply chose to approach the effort a different way.  However I mostly make games which often don’t need this info.

This sounds more like a business or technical application.  Do you have any concrete uses for this info in mind that you can share?  I or others may be able to present alternative solutions to measuring/accessing remaining time.

@ronburk,
 
Hi.  I did some testing and have come up with these results:

  • Calls to timer.performWithDelay() with a time of 1 are always deferred till the next frame an NOT processed until after enterFrame listeners.
  • enterFrame listeners are strictly ordered against each other in the order they were added.
  • Multiple calls to timer.performWithDelay() with a time of 1 are NOT strictly ordered against each other.

http://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2016/03/eventOrdering.zip

#3 was a surprise.  I very much expected them to be queued in order, but they are not.  Using a closure for one function seemed to make this worse, but that may simply have been an artifact of my limited data set.

I’ve asked for similar details before without luck.  My interest wasn’t re calcing frame times, but just to confirm the internal order, but might still apply to you.  The best response I’ve yet seen in that regard was here:

https://forums.coronalabs.com/topic/44873-frame-loop-execution-order/

Tho it’s still not as rigorously defined as i myself would have liked.  Corona’s position seems to be that you don’t need to know this sort of stuff and so guards it, see last post here:

https://forums.coronalabs.com/topic/17363-corona-app-execution-loop/

But there are aspects that can get “dicey” say if you have a touch-based physics game that also does heavy enterFrame logic.  Knowing (for SURE) that UI occurs before physics, which occurs before enterFrame, can make or break something based on physics (butterfly effect).

Thanks for the relevant links, guys! Especially this.

That timers disobey times < fps is at least “officially” documented.  +1 for that! :slight_smile:

Without knowing the internals, it’s hard to say whether idle time could be a valid concept for Corona; it may have already been implicitly designed out by other architecture decisions.  The poor approximation would then remain timestamps in enterFrame events, where at least dropped frames might be detected (odd that that’s not an advertised feature in an SDK catering to the inexperienced).

> Knowing (for SURE) that

Yeah, it’s the old closed-source tension. In theory, customers should not rely on undocumented behavior. In practice, any nontrivial API is never documented precisely and thoroughly enough to write complex code without ending up relying on undocumented behavior, intentionally or not. With open source, you may not be better off, but you feel better because you got to decide it wasn’t worth forking over. :slight_smile:

@ ronburk

While I don’t harbor any hopes of rescuing this idea (I think the “1 vote” comes from myself, as the poster), your scenario would, as another use case, lend weight to the start-of-frame variant of frame IDs pitched here: system.getFrameID() or system.getTimerAtStartOfFrame() (Actually, reading it over, it looks like I even allude to your situation. Argh, but most of the text isn’t terribly clear. :()

I’ve had to give up on some approaches (with once-and-only-once per-frame initialization steps) simply because I wanted to be able to drop them willy-nilly into timers, transitions, or arbitrary  enterFrame listeners but am paranoid that sooner or later a wrong priority would catch me out. With the ID thing I could just detect when it switches and only then perform any update.

Cant you make an enterFrame listener that would be the first in the list that would manage an ID for you? Having it as a simple variable would be more efficient than having to call a function and deal with all the stack operations needed to invoke a function?

Rob

@ Rob In this case performance would take a backseat to correctness. 

The big hang-up is being able to tell whether you’re inside a transition, timer, or garden-variety  enterFrame listener. From what Walter says in the “Frame loop execution order” thread (which I’d missed!!), it sounds like timers and transitions fire, followed by any user-supplied enterFrame listeners. Presumably the latter dispatch in insertion order.

Adding an UpdateID() listener at startup is perfectly reasonable, which could for instance increment an ID each frame starting from 0. The trouble is that the timer and transition listeners are already in line ahead of us, so if we want them to respect the ID we need a split-personality getter:

local ID = -1 -- Master ID: which frame is this? function M.GetFrameID (before\_update) if before\_update then return ID + 1 else return ID end end Runtime:addEventListener("enterFrame", function() ID = ID + 1 end)

This is okay if we’ll only be querying the ID in top-level logic, where we know our circumstances, for instance from the body of a timer, but becomes less flexible when we need it, say, in a function called by that same timer, and would need to propagate this context. This is especially onerous if we’d like our routines to be shared freely among timers, transitions, and enterFrame listeners.

Adding a second enterFrame listener would let us do an “are we in enterFrame?” query, but we then need to take special care to keep all (ID-aware) listeners bookended by this and the ID updater, so it just trades one problem for another. (I guess one could monkey-patch Runtime:addEventListener() to always move this second listener to the end…)

Usage-wise, the idea would be for modules to keep their own copy of the ID and then compare it to the “master” value for consistency. On first request (if any) per frame, the local copy is detected as out of sync; the code in question will resync its local ID, and also do any necessary upkeep at the same time. The actual value of the ID is largely irrelevant; it merely serves to detect changes, so updates need not be every frame and arbitrarily many independent systems can be ID’d.

As a contrived example: In some strategy game every unit, when about to perform an action, calls some GetAvailableMoves() function. The first time this is called on a given frame, it does some hefty work, like performing a bunch of A* searches and such to calculate prospective paths. Further calls, however, can simply return this already-available result. This changes the code shape a bit, so that instead of, say:

-- stuff UpdateAvailableMoves() UpdateUnits() -- more stuff&nbsp;

we would have

-- stuff UpdateUnits() -- UpdateAvailableMoves() called on-demand -- more stuff&nbsp;

Often this is a bit of a wash, but can occasionally simplify a few things. For instance, if we don’t update any unit, we don’t need to add extra handling to not update the available moves. Or we might have different types of units needing different systems.

(All that said, I’m hardly losing sleep over this stuff. I more or less gave up these techniques after failing to pry execution order details out of Mr. Beebe… so it’s been a while.  :))

As for how it might be used in the context of the original question:

local my\_id, up\_to local frame\_ms = math.floor(1000 / display.fps) -- might want to err low, say by scaling by .9 or so function TimeLeft () local current = system.getFrameID() local now = system.getTimer() if my\_id ~= current then -- out-of-date? my\_id = current up\_to = now + frame\_ms -- guess about when frame should end -- not so accurate if called later in frame, unfortunately end return math.max(up\_to - now, 0) -- alternatively, and with fewer gotchas: -- return math.max(system.getStartOfFrame() + frame\_ms - now, 0) end -- stuff while TimeLeft() \> 10 do -- still have decent slice left? DoStuff() end

Uff, and that was a lot more writing than I meant to do.  :stuck_out_tongue:

I added this thread to the UserVoice request. Thanks!

Rob

  1. Frame durations will vary although the SDK will try to match the requested frame rate.

  2. In this blog post I shared one of two techniques (that I know) used to ‘defer work’ if you’re almost  out of frame time:

https://coronalabs.com/blog/2015/05/12/tutorial-responsive-real-time-searching/

Thanks, I hadn’t seen that blog post. So, it appears that the Corona runtime does not expose the crucial data, leaving only the sort of guessing game your code demonstrates.

If Corona SDK would even just guarantee that it services “enterFrame” events before any other callbacks in a given frame cycle, then I could store a “previous” system time and subtract to discover how long the runtime took to paint.

Unfortunately, I see no such promise claimed in the docs. All the “enterFrame” page claims is that it will occur “occur at the FPS interval”, which of course also isn’t guaranteed. I guess I could experiment and see whether it happens to be true that “enterFrame” is always placed at the head of the event queue and, if so, hope that undocumented behavior doesn’t change in some future build.

  1. Considering what Corona can do, I wouldn’t be too critical.  Also, you can always request a feature and post a link back here to the request.  I’d vote for it.

http://feedback.coronalabs.com/forums/188732-corona-sdk-feature-requests-feedback

  1. That is exactly what you can do:

I could store a “previous” system time and subtract to discover how long the runtime took to paint.

You won’t however get the paint time.  You’ll get the time since the last enterFrame event.  

  1. Regarding intervals and guarantees.  In modern computing systems, exact tolerances for tween events cannot be guaranteed.  Too many factors can preempt the current process.  Corona does a pretty good job and usually, if a frame is missed it is because the user has done too much scripting work in one interval.

@ronburk,

You’ve posited an interesting question re: event processing order.  I’ll see if I can come up with a test bench for this and share it when I do.

Also, I’ve asked a similar question before: “How can I know how much time I have left to do ‘work’ in?”   Eventually, I simply chose to approach the effort a different way.  However I mostly make games which often don’t need this info.

This sounds more like a business or technical application.  Do you have any concrete uses for this info in mind that you can share?  I or others may be able to present alternative solutions to measuring/accessing remaining time.

@ronburk,
 
Hi.  I did some testing and have come up with these results:

  • Calls to timer.performWithDelay() with a time of 1 are always deferred till the next frame an NOT processed until after enterFrame listeners.
  • enterFrame listeners are strictly ordered against each other in the order they were added.
  • Multiple calls to timer.performWithDelay() with a time of 1 are NOT strictly ordered against each other.

http://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2016/03/eventOrdering.zip

#3 was a surprise.  I very much expected them to be queued in order, but they are not.  Using a closure for one function seemed to make this worse, but that may simply have been an artifact of my limited data set.

I’ve asked for similar details before without luck.  My interest wasn’t re calcing frame times, but just to confirm the internal order, but might still apply to you.  The best response I’ve yet seen in that regard was here:

https://forums.coronalabs.com/topic/44873-frame-loop-execution-order/

Tho it’s still not as rigorously defined as i myself would have liked.  Corona’s position seems to be that you don’t need to know this sort of stuff and so guards it, see last post here:

https://forums.coronalabs.com/topic/17363-corona-app-execution-loop/

But there are aspects that can get “dicey” say if you have a touch-based physics game that also does heavy enterFrame logic.  Knowing (for SURE) that UI occurs before physics, which occurs before enterFrame, can make or break something based on physics (butterfly effect).

Thanks for the relevant links, guys! Especially this.

That timers disobey times < fps is at least “officially” documented.  +1 for that! :slight_smile:

Without knowing the internals, it’s hard to say whether idle time could be a valid concept for Corona; it may have already been implicitly designed out by other architecture decisions.  The poor approximation would then remain timestamps in enterFrame events, where at least dropped frames might be detected (odd that that’s not an advertised feature in an SDK catering to the inexperienced).

> Knowing (for SURE) that

Yeah, it’s the old closed-source tension. In theory, customers should not rely on undocumented behavior. In practice, any nontrivial API is never documented precisely and thoroughly enough to write complex code without ending up relying on undocumented behavior, intentionally or not. With open source, you may not be better off, but you feel better because you got to decide it wasn’t worth forking over. :slight_smile:

@ ronburk

While I don’t harbor any hopes of rescuing this idea (I think the “1 vote” comes from myself, as the poster), your scenario would, as another use case, lend weight to the start-of-frame variant of frame IDs pitched here: system.getFrameID() or system.getTimerAtStartOfFrame() (Actually, reading it over, it looks like I even allude to your situation. Argh, but most of the text isn’t terribly clear. :()

I’ve had to give up on some approaches (with once-and-only-once per-frame initialization steps) simply because I wanted to be able to drop them willy-nilly into timers, transitions, or arbitrary  enterFrame listeners but am paranoid that sooner or later a wrong priority would catch me out. With the ID thing I could just detect when it switches and only then perform any update.