Webview (chromium) misses frames for no reason? - android

I have trouble debugging an performance issue on a div with overflow:auto. As you can see in the image below (and read in the the breakdown below that) it looks like the webview is wasting precious time by not delivering frames.
Weirdest thing is that the same content scrolls pretty smoothly on two older devices (Moto G and X 2013, Lollipop 5.1) but shows noticeable framedrops on newer ones (Moto X 2014 (Marshmallow 6.0) and Pixel C (Nougat 7.0)).
Between 990 and 995ms it does some compositing, rasterizing and gpu stuff. Then it sits idly for 15ms (that's almost an entire frame), updates the layer tree, then waits for another 18ms.
So we've missed ~2 frames by now even when it looks like it should have been able to deliver at least one.
Then it fires a scroll event and gets to chew on the javascript that is tied to that. That takes ~5ms and now it does some painting and compositing, then waits ANOTHER 10ms and updates the layer tree, then more waiting and then, finally, delivers it's first new frame since 990ms.
This entire thing took 66ms but, according to the timeline, the webview used most of that time to sit on its ass. And this is not an exception, I'm seeing this pattern during the entire recording of the scroll.
When I look at a timeline taken from the Moto X 1st gen it looks like the webview wastes a lot less time and tries to deliver frames as often as possible. Sure, it's not doing 60fps all the time but at this point I'm happy it does 40 instead of 20 or even lower.
The obvious question here is "what the hell is happening?" - or maybe more accurate: "why are things (read: frames) NOT happening?"
PS: I've checked the Android System Webview version and all of the devices I tested this on have v52 installed. The only thing I can think of is that the OS is 'causing' this. Did something change since Marshmallow?
UPDATE
I've been able to solve most of the lag by relaying most of the onscroll-logic I did to requestAnimationFrame and hide content that is off-screen (with visibility:hidden). But this doesn't really explain why Chrome seems to just skip frames when it's not really doing anything. It seems it has to do with scrolling a large area fairly complex content but I'd expect to see that in the timeline in some form. Instead, it just shows large empty spaces that block frames from rendering..?

Related

Video Lag and FPS drop on Android Lollipop on touching screen

I am using MediaCodec to play 1080p#60fps video. This is on freescale SabreSD platform with Android Lollipop 5.1.
Initially because of BufferQueue Synchronous Mode, the FPS was way below 60.I could now manage to play at 70FPS by changing the BufferQueue to Asynchronous as in JB.
Now the next challenge I am facing is the video lags and FPS drops drastically to 40 when I start interacting with the screen (pulling down notification bar , pressing volume button etc).
So I ran rafika MultiSurfaceActivity and Record GL, I can see all the test play smoothly when no screen is touched or disturbed, but as soon as I start scrolling the notification bar from top and continue that for long time, the fps gets reduced to 35-40FPS.
I have confirmed the same test on Kitkat 4.4.2 and JB 4.2.2 and they seems to work fine.
Same behaviour when playing MP4 from Gallery. The video gets stuck and lags a lot when we start playing with Notification bar
Can anyone explain what has change from Kitkat to Lollipop which can cause this issue (VSync, Triple Buffering ?).
Regurgitating a bit from the Grafika issue tracker:
The bouncing ball is software-rendered, so anything that soaks up CPU time is going to make it slow down. On devices with medium-grade CPUs and big displays (e.g. Nexus 10) it never gets close to 60fps. So a slowdown while you are playing with the nav bar doesn't surprise me, but if it continues to be slow even after you stop playing with the nav bar, then that's a little weird.
Video playback should be less affected, as that does less with the CPU.
Investigation into such problems usually begins by using systrace to capture traces in "good" and "bad" states, and comparing the two.
The key point of BufferQueue "async mode" is to allow frames to drop if the consumer can't keep up with the producer. It's primarily meant for SurfaceTexture, where producer and consumer are in the same app, potentially on the same thread, so having the producer stall waiting for the consumer could cause the program to hang. I'm not sure what you mean by needing it to exceed 60fps, but I would guess you're throwing frames at the display faster than it can render them... so you're not really increasing the frame rate, you're just using the BufferQueue to drop the frames instead of using Choreographer to decide when you need to drop them yourself.
In any event, I left Google back in June 2014, well before Lollipop was completed. If something works correctly on KitKat but weirdly on Lollipop, I'm afraid I can't provide much insight. If you can reproduce the behavior easily, it might be worth capturing a video that demonstrates the problem (point a second smart phone at the device exhibiting the problem, so they can see how you manipulate the device) and filing a bug on http://b.android.com/.
Some traces uploaded by the OP:
https://www.dropbox.com/s/luwovq7ohozccdy/Lollipop_bad.zip
https://www.dropbox.com/s/zkv0aqw0shecpw2/lollipop_good.zip
https://www.dropbox.com/s/g7qe01xvmfyvpak/kitkat.zip
Looking at the kitkat trace, something weird is going on in SurfaceFlinger. The main thread is sitting in postFrameBuffer for a very long time (23-32ms). It eventually wakes up, and the CPU row suggests it was waiting on activity from a "galcore daemon", which I'm not familiar with (seems particular to Vivante GPU).
The lollipop traces only show the CPU rows, as if the capture were done without the necessary tags. I don't believe the systrace capture command changed significantly between kitkat and lollipop, so I'm puzzled as to why the user-space-initiated logging would vanish but the kernel thread scheduling stuff would remain. Make sure you have sched gfx view specified.
The newer lollipop traces only have about a second of good data. When you see "Did Not Finish" it means a "start" record had no matching "end" record. You can increase the systrace logging buffer size with the -b flag. I think there's enough there though.
Looking at the /system/bin/surfaceflinger row you can see that, in the "good" trace, postFrameBuffer usually finishes in about 16ms, but it's still waiting on galcore. Zoom in on 388ms (use WASD keys). At 388.196ms, on the CPU 2 row, you can see galcore do something. Right after it completes, the thin line at the top of the surfaceflinger row changes from light grey (sleeping) to green (running). At 388.548ms, again on CPU 2, galcore runs again, and right after that on the surfaceflinger row you see queueBuffer start to execute.
The "bad" trace looks identical. For example, you can see two galcore executions at 101.146ms and 101.666ms, with what appear to be similar effects on the surfaceflinger row. The key difference is the time spent in postFrameBuffer, which is around 16ms for "good" and around 30ms for "bad".
So this doesn't appear to be a behavioral shift; rather, things are taking longer and deadlines are being missed.
As far as I can tell, SurfaceFlinger is being held up by galcore daemon. This is true in both "good" and "bad" cases. To see what the timing should look like you can run systrace on a Nexus device, or compare to traces from other devices (e.g. the one in this case study or this SO question). If you zoom in you can see doComposition executing in a few milliseconds, and postFrameBuffer finishing in a few tenths of a millisecond.
Summing up: you don't have good and bad, you have bad and worse. :-) I don't know what galcore is, but you'll likely need to have a conversation with the GPU OEM.

Determine exact screen flip times on Android

I am attempting to determine (to within 1 ms) when particular screen flips happen on Android. Choreographer fires every time a frame flips, but gives no way of determining which frame is actually being displayed. According to https://source.android.com/devices/graphics/architecture.html, there are several layers in the process: the user land buffer, which flips to a triple-buffered queue, which flips to the surface flinger, which flips to the hardware. Each of these layers can potentially drop a frame, but at this point I have only determined how to to monitor the user land buffer. Is there a way to monitor the other buffers/flips (in real time, on a non-rooted, non-custom phone)?
I have observed unexpected frame delays on the HTC M8 (about 1 every 5 minutes), but the Nexus 7 does not appear to have this problem. I measure the delays by using a Cedrus StimTracker (http://cedrus.com/stimtracker/) with a photo sensor and the Lab Streaming Layer (https://github.com/sccn/labstreaminglayer). I have tried using eglPresentationTimeANDROID to control when screens are flipped, and that has not fixed the problem.
Note that I'm using the ndk, but I can usually use the JNI to get access to non-ndk features when I need to.
The reason I care is in order to use Android for psychological and neurological experiments, where 1 ms precision is highly desirable.
As far as accessible APIs go, it sounds like you've found the relevant bits and pieces. If you haven't yet, please read through this stackoverflow item.
Using Choreographer and extrapolation, you can guess at when the next display refresh will occur. Using eglPresentationTimeANDROID() on an Android 5.0+ device, you can tell SurfaceFlinger when you want a particular frame to be sent to the display. Assuming SurfaceFlinger is properly accounting for all latency (such as additional frames added by "smart" panels), that should get you reliable timing.
(Bear in mind that the timing is based on when the display latches the next frame, not when the next frame is fully visible on the display... the latency there will depend on the panel.)
Grafika's "scheduled swap" Activity uses this feature, but it sounds like you're already familiar.
The only way to get signaled by the display when it does the swap would be to dup() the display-retire fence fd from the previous frame, and wait on it. Some of the code in SurfaceFlinger does this, notably DispSync watches the retire fences to see if the software "VSYNC" is drifting. There is no public API for fences, and the user-space response time could certainly be more than 1ms anyway... it usually works out better to schedule ahead than it does to react. Your requirement for non-rooted non-custom devices makes this problematic.
If you're mostly seeing correct behavior, but occasionally seeing a miss, your best bet is to use systrace to track down the cause.

How to get real FPS with createjs

I created a game with createjs, but it runs very slowly on a mobile.
I added a function to show FPS obtained with createjs.Ticker.getMeasuredFPS(). However, the FPS shown by the function is quite normal. I set the FPS to 60, and the result of getMeasuredFPS() is about 55-60, while the animation is laggy and the FPS shouldn't be so high (it might be 5-10).
How can I get the real FPS on the device?
How can I profile it on a mobile?
getMeasuredFPS() is well tested, and should be accurate. That said, there's always a chance your mobile browser is doing something tricky (running the code every tick, but not rendering). There's also a chance your code may not be updating properly.
Either way, it's worth looking at a couple of alternatives. You can check getMeasuredTickTime(), which will tell you the average time spent in each tick (see the docs for more info).
You should also take a look at profiling using devtools.
http://google.com?q=profile+mobile+chrome

How can I fix jumpy Android rendering performance due to GPU throttling? I don't need a high framerate, just a consistent one

I'm developing a GL live wallpaper that uses very little CPU and only modest GPU. On my older test phone, it can run at a full 58fps or so most of the time. But occasionally the effects ramp up, and then the render times jitter between 16ms and 50ms per frame. For example, it'll render several frames at 16ms, slide up to 50ms over a dozen frames or so, render several more frames at 50ms, then slide back down to 16ms and repeat. I discovered that if I set the CPU governor to "performance" (or "conservative", curiously enough) instead of the default "ondemand" it'll render with full effects at full speed. Alternatively, if I leave the governor alone and insert a busy loop in my code (increment a variable 100,000 times per frame) that bumps my CPU usage up enough to transition to a higher clock rate and render smoothly as well.
So it seems on this phone my app is bottlenecked by the GPU, but only when it throttles down. Now, I wouldn't mind if the GLSurfaceView rendered at a slower rate according to the GPU clock, but my problem here is that I'm getting the bursts of alternating high and low frame rates which makes my animation look fluid/frameskippy/fluid/frameskippy/etc. several times per second. It seems like the GPU clock is ramping up and down like crazy?
I got a visible improvement by using RENDERMODE_WHEN_DIRTY and calling requestRender() on a strictly timed thread, but the darn GPU keeps ramping up and down. Why won't it either render as fast as it can at the slower clock, or just jump to and STAY AT the higher clock?
The best solution I've come up with so far is using a sliding window to detect the average frame update time, then applying the difference from the target frame time until the two values converge. The time between render updates is slower but at least it's roughly constant. So that works in theory, but it takes several seconds to reach a steady state and it looks bad in the meantime.
I think a third option might be to cannibalize the GLSurfaceView source and make a custom version. From what I understand, the blocking GL calls are made in there, so it would be much easier for me to time render calls and react accordingly. I'm not very comfortable attempting that though because there's a lot of code in there that I'd have to spend a lot of time understanding before I could even begin to mess with it. Plus I'd then have to worry about how well version X of GLSurfaceView plays with any version Y of Android.
So, with all that said, do I have any other options here? Is there an easier fix to this?
try fixing the frame rate by pausing the thread (thread sleep) for the remaining time to reach a constant frame rate.

Open GL stutter when rendering on Galaxy S2

Our Android game has an issue which appears unique to the Galaxy S2.
Occasionally the render will stutter. By this I mean it basically seems to render the last two frames (as though its swapping the last two render buffers without updating either).
What's really odd about this is that the game continues to update, so say the stutter lasts for 2 seconds, the game will have progressed 2 seconds behind the scenes.
This is odd because our code is basically like this:
function Update()
DoGameLogic()
DoRender()
So this means that if our the game has updated, the game has also rendered. The maximum delta time is capped to 1 frame so there must have been more than one Update and thus multiple renders during the stutter.
My current theory is that on most devices the game lags during render, but on the S2 the render calls are executed but they "fall through" without updating the render buffer.
Has anyone run into this problem? I would really appreciate any suggestions about what this could be.
We found out what the problem is.
The Galaxy S 2 was for some reason running out of GL memory. This wasn't apparent on the devices we were testing with, but on other devices it would crash on some Open GL call - not the offending call mind you.
Eventually we tracked it down to using Point sprite VBO's. As the S 2 is a powerful device, we replaced Point sprites with Quad's mimicking point sprites as a workaround.
Incidentally, SoundPool would also run out of memory on this device, requiring another workaround.

Categories

Resources