Measuring the load time of individual GUI elements - android

I am writing a program to measure the load time of every GUI element (like button, Text box etc.). Right now I am working on Windows Phone and I plan to expand it to Android and iOS (using swift probably, still undecided) and Java desktop.
I am using the click event of a button to generate a GUI element (a button in this case)
private void btnCreate_Click(object sender, RoutedEventArgs e)
{
CleanUp(); // to Garbage collect
watch.Start();
Button btn = new Button();
btn.Width = 110;
btn.Height = 56;
btn.Foreground = new SolidColorBrush(Windows.UI.Colors.White);
btn.Content = "Button";
btn.Click += btn_Click;
gridMain.Children.Add(btn);
watch.Stop();
}
I use a different button, with the following code in its event handler, to show the results
private void btnResults_Click(object sender, RoutedEventArgs e)
{
long ticks = watch.ElapsedTicks;
double ms = 1000.0 * (double)ticks / Stopwatch.Frequency;
// show results in a message box
}
I also have a button to remove the generated button and garbage collect so that I can remove and recreate and take several readings
private void btnRemove_Click(object sender, RoutedEventArgs e)
{
gridMain.Children.RemoveAt(3); //the dynamically generated button is at 3
watch.Reset();
}
The problem is that I am getting some what inconsistent results.
Here are few of my results (excluding the first run):
0.6028 ms
0.7217 ms
0.9596 ms
1.3834 ms
0.5626 ms
1.3814 ms
0.7343 ms
I don't understand the reason. Is this significantly inconsistent? if yes, then is my method flawed? is there a better way to do this? Thanks

Right now you're measuring constructing two objects (a Button and a SolidColorBrush), setting various properties, inserting a couple of things into vectors (the event handler and the children), etc. but I don't think the button is actually visible when you call Stop (there is probably a layout and render pass still to happen). So you're measuring some random things.
Off-hand (and I'm not a XAML perf guru by any stretch of the imagination) a variance of +/- 1ms wall-clock time for adding a Button to a Grid seems reasonable given the way you're measuring (eg, what else is your computer doing at the same time?). If you want to do perf analysis, use the performance analyzer tools.

Related

I can't handle this method: Thread.sleep()

I can't handle this method: Thread.sleep() in Android Studio.
I want to fill a 9x9 size TextView with a number every 0.1 seconds.
And, this is my codes.
public class MainActivity extends AppCompatActivity {
TextView[][] basicCell=new TextView[9][9];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initVar();
int cnt=0;
for(int i=0; i<9; i++){
for(int j=0; j<9; j++){
basicCell[i][j].setText(j+"");
basicCell[i][j].setTextColor(Color.BLACK);
basicCell[i][j].setTextSize(20);
basicCell[i][j].setGravity(Gravity.CENTER);
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
Log.d("COUNT", ""+cnt++);
}
}
}
TextView[][] basicCell=new TextView[9][9]
All textviews are linked with basicCells.
And, The expected results screen is as follows.
In the middle of the code,
By inserting
try {Thread.sleep (100); }
catch (InterruptedException e) { e.printStackTrace();}
I tried to get the number one every 0.1 seconds ...
When you run the app, it stays on for a few seconds and the numbers come up at once.
I took a look at the log,
Log.d ("COUNT", "" + cnt ++);
In log chat, the logs are working hard,
The screen is in a state of jamming for a few seconds,
Since cnt is 80, the numbers are displayed on the screen at once.
I thought it was an emulator lag, so I ran it on my smartphone, and the result is the same.
I do not know what the problem is.
Is there a way to see the results as intended?
Please, take a look at the official guide for Processes and Threads. Your code is being executed on the main thread, but you can't just make it sleep, because it will freeze your UI. Also, onCreate is executed in order to create your activity, so you won't be able to update your UI just by sleeping the thread in onCreate, because Android will wait until onCreated is executed, then it will show your UI.
You need to create an AsyncTask. Please, read here:
https://developer.android.com/guide/components/processes-and-threads.html
setText(...), setTextColor(...), etc. don't change anything on the screen. They only change values recorded in the TextView objects to which you apply them. The framework will then ask the TextView objects to render themselves to the screen after your function has returned.
I don't know Android, so I don't know the proper names of things, but if you want things on the screen to change over time (i.e., if you want to animate your display), then you'll need to set up some kind of a timer task---a callback function that gets called periodically. Each time it gets called, it should change one thing (e.g., update one cell), and then it should return so that the cell will have a chance to render itself to the screen.

How to fix Slow Rendering (Android vitals)

I have an app that is listed as in the bottom 25% in the new Google Play Console - Android vitals section for Slow Rendering. I am concerned of this because of such articles that seem to say Google Play may penalize your app in the Play Store rankings if you fall in the bottom 25%.
However, it seems impossible to improve this metric for my app. It plays music and has a SeekBar and TextView which is updated every 250ms as any music player would. I made the minimum basic program to demonstrate:
public class MainActivity extends AppCompatActivity {
int count;
SeekBar seekBar;
TextView textView;
Runnable runnable =
new Runnable() {
#Override
public void run() {
textView.setText(Integer.toString(count));
seekBar.setProgress(count);
++count;
seekBar.postDelayed(runnable, 250);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
seekBar = (SeekBar) findViewById(R.id.seek);
textView = (TextView) findViewById(R.id.text);
seekBar.post(runnable);
}
}
Full project here: https://github.com/svenoaks/SlowRendering.git
When I run this program on hardware similar to the Nexus devices, I get these results for a
adb shell dumpsys gfxinfo com.example.xyz.slowrendering command:
Stats since: 19222191084749ns
Total frames rendered: 308
Janky frames: 290 (94.16%)
90th percentile: 32ms
95th percentile: 36ms
99th percentile: 44ms
Number Missed Vsync: 2
Number High input latency: 0
Number Slow UI thread: 139
Number Slow bitmap uploads: 0
Number Slow issue draw commands: 283
This would mean almost all my frames taking >16ms to render, I guess due to the periodic nature of the updating. All other music player apps I have tested also have this Slow Rendering problem as far as I can see. I fear Google's algorithm ruining my app ranking, is there any way I can improve my score?
The TextView in your layout is causing the problem. Because it has layout width of wrap_content, which said that it's width has to be equals to the width of the content (the text in this example). Therefore, every time you call TextView.setText an expensive measure/layout pass has to occur. Simple setting the layout_width to match_parent will solve the issue.
Here are two images what is taken from systrace, it demonstrate the work run on the UI thread in 1 frame. The top one is done with layout_width=wrap_content and the bottom one is with layout_width=match_parent.
Two following methods that i have tested will improve the frame rate:
If you post the runnable in shorter span like 16ms (seekBar.postDelayed(runnable, 16)), you get this smooth 60fps:
P/s: I am not sure why yet.
Use some other way to update the count value instead of inside the Runnable. Use View.postOnAnimation(Runnable) to reschedule the Runnable. The result is 60FPS for the sample project.
EDIT:
two Runnable that uses postOnAnimation(Runnable)
Runnable runnable =
new Runnable() {
#Override
public void run() {
textView.setText(Integer.toString(count));
seekBar.setProgress(count);
seekBar.postOnAnimation(this);
}
};
Runnable updateCount = new Runnable() {
#Override public void run() {
++count;
seekBar.postDelayed(this, 250);
}
};
I checked your code. Not sure if this is the actual code or if you have more to this. In any case I will draw attention to some of the Rendering issues in android.
1. OverDraw
Overdraw is where you waste GPU processing time by coloring in pixels that only get colored in again by something else. These can be common if you have added a background to your parent container layout and then the children are also added a background or if you have added a common background on you styles file for the application theme and then added backgrounds to the rest of the xml layout files you have created.
The causes for the overdraw can be anything, try checking your code for this. There is a developer tool installed in all mobile devices to check Overdraw in developer options. Here is the official documentation for overdraw.
2. View hierarchy
To render each view, Android goes through three stages:
1.measure
2.layout
3.draw
The time it takes Android to complete these stages is proportional to the number of views in your hierarchy. I see in your layout file that you have constraint layout which includes a linear layout. I don't see the use of this. Constraint layout was introduced to help developers reduce view hierarchy. Reduce the number of childs a particular layout can have. There is also a tool to help you with this. Here is the official android guide to it.
Try these steps to figure out the GPU rendering issues.

Android real-time game - implement time unit

I'll try to explain what I mean.
I'm developing a 2d game. When I run the code below on the small screen it works more quickly than the same code on the big screen. I think it depends on an iteration of the game loop takes more time on the big screen than on the small. How can I implement time unit or something else to it doesn't depend on the iteration of the game loop?
private void createDebris(){
if(dx<=0) return;
if(stepDebris==2){
Debris debris = new Debris(gameActivity, dx-=1280*coefX/77, 800*coefY-50*coefY, coefX, coefY);
synchronized (necessaryObjects) {
necessaryObjects.add(debris);
}
stepDebris=-1;
Log.e("COUNT", (count++)+"");
}
stepDebris++;
}
P.S. Debris is visual object which is drawn on canvas. I'll appreciate your answers. Thanks.
If, stepDebris is the unit by which you move objects on the screen - then incrementing it per draw call is wrong, because it ties the rate of movement to the framerate.
What you want is something like this
stepDebris += elapsedMilliseconds * speedFactor
where elapsedMilliseconds is the time elapsed since the game started (in mS). Once you find the correct speedFactor for stepDebris - it will move at the same speed on different machines/resolutions irrespective of framerate.
Hope this helps!
You can make an 'iteration' take x milliseconds by measuring the time it takes to do the actual iteration (= y), and afterwards sleeping (x-y) millisecs.
See also step 3 of this tutorial
Android provies the Handler API, which implements timed event loops, to control the timing of computation. This article is pretty good.
You will save battery life by implementing a frame rate controller with this interface rather redrawing as fast as you can.

Android: How to find the frame rate of a device?

Frame rate: I'm referring to the rate at which display changes. i.e. Ondraw() is called and the canvas is redrawn.
Is there a default rate for all android devices ? As this rate depends on the processing power of the device , How to find out the frame rate of a device , before starting to program for that mobile device ?
This may be a follow-up to this question, where I suggested that having a redraw loop that just kept drawing over and over again might be a bit excessive. There may be an api to find out the capabilities of the devices display, but if there is I'm not aware of it. When you're writing your own event loop / thread function you can control the framerate by how often you call your 'draw' method. Typically, I think for most purposes, you would be ok with a refresh rate of 30 or so. If you're writing a fast action game, that needs rapid animation then you may want to run as fast as you can, the more fps, the smoother it will be.
A typical event loop (thread run function) might look something like this:
// define the target fps
private static final int UPDATE_RATE = 30; // Frames per second (fps)
public void run() {
while(running) { // volatile flag, set somewhere else to shutdown
long beginTimeMillis, timeTakenMillis, timeLeftMillis;
// get the time before updates/draw
beginTimeMillis = System.currentTimeMillis();
// do the thread processing / draw
performUpdates(); // move things if required
draw(); // draw them on the screen
// get the time after processing and calculate the difference
timeTakenMillis = System.currentTimeMillis() - beginTimeMillis;
// check how long there is until we reach the desired refresh rate
timeLeftMillis = (1000L / UPDATE_RATE) - timeTakenMillis;
// set some kind of minimum to prevent spinning
if (timeLeftMillis < 5) {
timeLeftMillis = 5; // Set a minimum
}
// sleep until the end of the current frame
try {
TimeUnit.MILLISECONDS.sleep(timeLeftMillis);
} catch (InterruptedException ie) {
}
}
}
You can use the dumpsys tool provided by Android. To obtain information about the display of the device execute the command:
adb shell dumpsys display
The information about the frame rate of the device is provided in the attribute "mPhys".
You will find something like:
mPhys=PhysicalDisplayInfo{1080x1920, 60.000004 fps, densitiy 3.0,
480.0x480.0 dpi, secure true}
The frame rate of the device is in the second field, in my case is 60.000004 fps
You can't rely on a certain framerate. Android is a using multitasking operating system. If there are some threads running in the background that do some heavy lifting, you might not be able to reach the framerate you want. Even if you're the only active process, the framerate depends on your GPU and CPU, and the clock of each. Maybe the user has a hacked ROM that changes the clock to a custom value.
Some phones might be locked to a certain framerate. The HTC EVO was locked to 30fps for the longest time, until custom ROMs came out that removed that limitation. Newer EVO ROMs also removed that limitation.
I don't know what you're trying to do, but your best bet is to measure the time after each frame and use that delta for your animations. If you're trying to display the FPS, then use a smoothed average.
There is a simple tricky way to find device FPS during runtime.
Just call the following method:
long oneSecondLater=0;
int FPS=0;
int counter=0;
ValueAnimator v_animator;
private void logFPS()
{
oneSecondLater = System.currentTimeMillis()+1000;
v_animator = ValueAnimator.ofFloat(0.0f, 1.0f);
v_animator.setRepeatCount(ValueAnimator.INFINITE);
v_animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
FPS++;
if(System.currentTimeMillis() > oneSecondLater)
{
counter++;
if(counter>1)//ignore the first onAnimationUpdate call (it is not correct)
Log.i("checkFPS","FPS:" + FPS);
FPS=0;
oneSecondLater = System.currentTimeMillis()+1000;
}
}
});
v_animator.start();
}
I log FPS every second, The output of my Logcat was as follows
It works because for ValueAnimator, onAnimationUpdate() method will call according to device FPS;
This might be an old question, but for future reference, I found this library named Takt
https://github.com/wasabeef/Takt.
Takt is Android library for measuring the FPS using Choreographer.

Android loading and showing a lot of images in ImageView(frame by frame animation) hangs in certain moments

I've created an application that show around 250 images in ImageView. Images are loaded one after another, 15-30 images per second. Basically the whole thing gives an illusion of a rotating 3D object, at least it should.
The problem is next, app hangs when loading certain images(i.e. I see a few seconds of fluid animation and then animation hangs, jump 10-15 frames(images) ahead and continues. It always happens at the same places in animation cycle.
I though that Android might not have enough resources to handle something like this, so I've resized images to half their size, but it did't help. I've tried buffering images but that did't help either(actually, maybe a little, I think that animation looks a little bit smoother).
And now the weirdest thing. I use the touch screen to allow users to "rotate" the 3D object on those images, and while rotating I again experience those hangs at exactly the same places as with the animation.
All images are in .png format and their size vary from 15kB to 40kB.
I use the following code for the animation:
new Thread(new Runnable() {
#Override
public void run() {
while (!stopStartupAnimation && li < images_360.length) {
final int fli = li;
handler.post(new Runnable() {
#Override
public void run() {
//Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
//imageCanvas.setImageResource(images_360[fli]);
imageCanvas.setImageBitmap(imageStackNext.pop());
System.out.println("rawX = " + fli);
}
});
int ti = fli +25;
if(ti > images_360.length-1){
ti = ti - images_360.length;
}
imageStackNext.push(BitmapFactory.decodeResource(getResources(), images_360[ti]));
synchronized (this) {
try {
wait(1000 / 25);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
li++;
li++;
if (li >= images_360.length) {
li = 0;
}
}
}
}).start();
First, 15-40KB is their compressed form. Uncompressed, as Bitmaps, they are probably substantially larger. 250 of them may be using many MB of RAM, which is not a good idea.
Second, given a choice between using OpenGL for 3D (which is its purpose), or the 2D drawing primitives on the Canvas, or using ImageView, you chose the worst-performing option.
Third, postRunnable() does not take effect immediately, but rather puts things on a message queue for the main application thread to process when it gets a chance. If it gets tied up -- say, handling touch events -- it may well skip over some seemingly redundant ImageView redraws, or have them go by so fast they appear to not happen. All your 40ms wait() does is ensure that you are only raising events every 40ms, not that they will paint every 40ms. Besides, you could have more easily just used postDelayed() for your 40ms timing.
Bitmaps should be loaded efficiently.
Refer example on official page: https://developer.android.com/training/displaying-bitmaps/index.html

Categories

Resources