B4i Library [CLASS] A dynamic self calibrating more accurate Timer

Impressive title - hope the content lives up to it.

I have discovered that Timers appear to be quite inaccurate in B4I - on my iPhone 4S I am observing elapsed times to timeout being of the order of 10% more than the assigned Interval.

In most situations that would not matter, however in my particular app it creates an unprofessional appearance (at least to a perfectionist).

Searching the community with "timer accuracy" reveals it is a well known phenomenon - although nearly all the hits are B4A.

In this thread:

https://www.b4x.com/android/forum/threads/timer-in-microseconds.21938/#post-158521

At post #5
Timers work by sending a messages to the message loop. As they are processed by the main thread they cannot be 100% accurate.

This is a B4A thread and I'm assuming the same applies to B4I (someone correct me if I am wrong).

This explains the source of the inaccuracy and also implies it has some volatility.

In the same thread, at post #6, Informatix posits a solution around "busy loops" - ultimately involving DoEvents - no DoEvents in B4I so that's not going to work.

In this thread (again B4A):

https://www.b4x.com/android/forum/threads/countdown-accuracy.25771/#post-149310

Erel suggests a scheme involving a short fuse timer (100 msec) and checking against the system clock - which looks like it would give accuracies of the order of 100 msec or better but at (I suspect) a considerable amount of cycle chewing (again, correct me if I am wrong).

-------------------------------------------------------------

I have managed to come up with a class that wraps the B4I timer object and dynamically adjusts the timer interval to drive down inaccuracy to typically less than 1% (after a cycle or 2) and involves no real increase in resource consumption.

It is also essentially a drop-in replacement for the B4I timer object...

Change:
B4X:
Private xxx as Timer
...
xxx.Initialize("Event_xxx", interval)

to:
B4X:
Private xxx as XTimer
...
xxx.Initialize(Me, "Event_xxx", interval)

and you are done.

-------------------------------------------------------------

The attached zip file has the class wrapped in a B4I test rig which allows you to test up to 3 timers simultaneously:
  • Move the sliders to change the timers desired interval.
  • Set desired interval to 0 if you want to disable timer.
  • Toggle switch ON/OFF to Enable/Disable interval adjusting by XTimer, when OFF XTimer behaves just like B4I Timer.
  • Click anywhere on screen to start testing, then click anywhere on the screen to stop.
5.PNG

-------------------------------------------------------------

The class header documentation pretty well explains the intent:
B4X:
'************************************************************************************
'
'This class module wraps Timer object
'
'Features:
'
'   o Does a dynamic self calibrating adjustment of Timer object interval to correct
'     for inaccuracies in Timer object countdown timeout
'
'Methods:
'
'   Initialize
'
'Events:
'
'   Tick
'
'       Indicates XTimer countdown has timed out
'
'Properties:
'
'   Interval -  interval (measured in milliseconds)
'
'   Enabled - enabled state
'
'   Adjust - adjust state (True = will adjust intervals (default), False = it will
'            not)
'
'Requirements:
'
'   None
'
'Update history:
'
'   21 Feb 16 - 1.0
'   23 Feb 16 - 1.1
'       o Improved interval adjustment algorithm - seems to correct inaccuracies
'         better and more rapidly
'       o Added simple filter to control rare extreme corrections in short fuse
'         timers (e.g. 500 milliseconds)
'   24 Feb 16 - 1.2
'       o Fixed bug in Interval setting
'
'************************************************************************************

And the documentation of the Initialization method of the class describes the parameters that need to be passed:
B4X:
'************************************************************************************
'
'This procedure gets control when Initialize method is called by parent module
'
'Input parameters are:
'
'       XTimer_Parent = pointer to module creating instance of this class
'       XTimer_Event_Name = event name stub
'       XTimer_Interval = desired interval (milliseconds)
'
'Returns:
'
'       None
'
'Notes on this procedure:
'
'       o Initializes XTimer
'
'************************************************************************************
-------------------------------------------------------------

This solution seems pretty fundamental - I am a bit worried that I may be missing something basic that renders it a no-go - all comments are welcome.

I haven't tried it, but from what I can see this class should be able to be dropped in B4A without change. It may well be unnecessary - B4A may not exhibit the magnitude of errors that B4I seems to.

Happy coding...

=================================================

UPDATES - the zip in this post has been replaced on several occasions:

23 Feb 16 - improved interval adjustment algorithm - seems to correct inaccuracies better and more rapidly and added simple filter to control rare extreme corrections in short fuse timers (e.g. 500 milliseconds).

24 Feb 16 - fixed bug in Interval setting
 

Attachments

  • XTimer_iOS.zip
    3.8 KB · Views: 21
Last edited:

JackKirk

Well-Known Member
Licensed User
Well my curiosity was raised so I ported the B4I class and test rig code in the first post to B4A.

Turns out that B4A exhibits very little in the way of timer inaccuracies - well on my Samsung S5 anyrate:

4.png

The above image is a rerun of the B4I/iPhone 4S test in the first post that exhibited timer inaccuracies of the order of 10%.

Which sort of raises some questions:
  • Has B4A timer accuracy been improved since all the B4A posts related to it?
  • Why is B4I so much worse than B4A?
  • Am I missing something?
Please feel free to play with the attached B4A class and test rig - maybe on different Android devices...

=================================================

UPDATES - the zip in this post has been replaced on several occasions:

23 Feb 16 - improved interval adjustment algorithm - seems to correct inaccuracies better and more rapidly and added simple filter to control rare extreme corrections in short fuse timers (e.g. 500 milliseconds).

24 Feb 16 - fixed bug in Interval setting
 

Attachments

  • XTimer_Android.zip
    13.4 KB · Views: 6
Last edited:

Erel

Administrator
Staff member
Licensed User
  • Has B4A timer accuracy been improved since all the B4A posts related to it?
No. The performance was always good. In some of the cases developers test the performance in debug mode instead of release. The other possible reason is that another code is being executed and it slows down the main thread.

Why is B4I so much worse than B4A?
The B4i timer is indeed less accurate. Both implementations are based on the internal message queue. It seems like the iOS message queue handling is less accurate.

Note that your are not building the layout correctly. Use the visual designer. It will be much simpler.
 

JackKirk

Well-Known Member
Licensed User
Note that your are not building the layout correctly. Use the visual designer. It will be much simpler.

The apps I am developing as an excuse to come to grips with B4A/B4I have ultra simple UIs - essentially 3 buttons and a scrolling log area.

However the guts involve GPS, barcode scanners, audio prompts, website downloads, phone calls, SMS and email.

I had a quick look at the visual designer at the start and decided it was something I could put to one side for the time being.

I am finding it quite easy to create the UI from code - and I suspect it maybe a better way of learning the nitty-gritty.

But I will eventually tackle the visual designer...
 
Last edited:

tman

Member
Licensed User
I have a B4A app that utilizes a 1 second timer and it is very accurate. I ported my code over to B4I and the the timer loses 2.5 seconds per minute. I was wondering why it was off so much and was happy to find this thread.
 
Top