How to Test Performances
When developing a GUI application, the performances may matter. The most obvious use case is to have smooth animations, but it can also be the time of opening a new page (between the user interaction and the page visible on the screen).
This section presents tools that:
Help to analyze performances issues. It comes in complement of other tools such as System View.
Can be included in a test suite to validate the performances of an application and ensure non-regression.
Monitor Widgets
Widgets can be monitored using the WidgetListener. It can be enabled by defining 2 constants: ej.mwt.debug.widget.enabled and ej.mwt.debug.widget.monitor.
The first one is set to true, the second one to the FQN of the monitor implementation class.
Example:
ej.mwt.debug.widget.enabled=true
ej.mwt.debug.widget.monitor=my.app.MyWidgetMonitor
The monitor must implement WidgetListener and will receive notifications:
When a widget is created.
When a widget is attached and detached.
When a widget is shown and hidden.
When a widget style is updating and once it is updated.
When a widget is computing its optimal size and once it is computed.
When a widget is layouting and once it is laid out.
When a widget is rendering and once it is rendered.
Monitor Animations
There are two ways to monitor animations:
Using an
AnimationListenerthat receives notifications for animation related events (start, tick, stop).Using an
AnimationBenchmarkthat can track specific animations and do some measurements regarding their performances.
Animation Listener
Animations can be monitored using the AnimationListener. It can be enabled by defining 2 constants: ej.mwt.debug.animation.enabled and ej.mwt.debug.animation.monitor.
The first one is set to true, the second one to the FQN of the monitor implementation class.
Example:
ej.mwt.debug.animation.enabled=true
ej.mwt.debug.animation.monitor=my.app.MyAnimationMonitor
The monitor must implement AnimationListener and will receive notifications:
When an animation is started.
When an animation is ticked.
When an animation is stopped.
Animation Benchmark
AnimationBenchmark is a static debug utility that measures frame rate and timing of any Animation
running through the Animator. It is opt-in and has no effect when disabled.
Its main purpose is to test on device the performance of an application regarding its animations and prevent regression.
Note
Available since MWT 3.7.0.
To track animations across your application, set Constant:
ej.mwt.debug.animation.benchmark.enabled=true
The AnimationBenchmark static class olds a FIFO queue of labels to assign to the next tracked animation and provides synchronization utility to retrieve a TrackedAnimation when the associated animation is finished.
Labels are consumed in FIFO order: if multiple animations are started in sequence, pre-queue all their labels in the same order.
Animations started without a label are not tracked, thus cannot be waited on.
The TrackedAnimation tracks Animation performance and provides various metrics once completed:
Method |
Description |
|---|---|
|
Raw list of tick timestamps (ms) |
|
Elapsed time from first to last tick (ms) |
|
Average frames per second over the full duration |
|
List of inter-frame intervals (ms), size = ticks − 1 |
|
Longest inter-frame interval — indicates stalls |
|
Frames whose inter-frame duration ≥ threshold |
The utility is usually used for test scenarios. These test scenarios must be run in embedded in order to have consistent results (the simulator running on a PC with several other applications).
AnimationBenchmark.addNextLabel("myAnim"); // register label for the next animation
// Some logic triggering the start of the Animation to test…
TrackedAnimation t = AnimationBenchmark.wait("myAnim", timeout); // blocks until animation ends and retrieves tracked animation
// Assert on t.getAverageFps() / t.getDuration() / t.getMaxFrameTime()…
Note
AnimationBenchmark is meant for test environments but nothing prevents the user to use the class
inside and application for debugging purposes. If doing that, be careful of where wait(String label, long timeout)
is called, as many Animator.startAnimation(Animation animation) are called inside the UI Thread (in an event
handler for example) and waiting for the UI Thread to progress while locking it will cause an IllegalStateException.
A way to wait for an Animation to end would be to inject an AnimationListener and cast animations to
TrackedAnimation in onStoppedAnimation(Animation animation) (would be safe because if AnimationBenchmark
is enabled, all animations become tracked).
It is possible to call AnimationBenchmark.clear() between test runs to ensure a clean environment.
This resets the label queue and locks.
Animations that started before a clear() and complete after it are silently ignored.
