Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid XHR when possible for faster raster tile loading #7008

Closed
wants to merge 4 commits into from

Conversation

mourner
Copy link
Member

@mourner mourner commented Jul 23, 2018

A proposal for addressing #6643. If we see that a raster tile we requested with XHR should be cached for a long time (currently set to 1 hr), we switch from XHR to simple new Image tile loads for that source. This fixes a lot of the jank when using raster tile sources.

Launch Checklist

  • briefly describe the changes in this PR
  • write tests for all new functionality (we don't have tests for image loading, and they probably won't be useful anyway as long as we use jsdom and stubbing)
  • document any changes to public APIs
  • post benchmark scores
  • manually test the debug page

src/util/ajax.js Outdated
}
img.onload = () => callback(null, img);
img.src = url;
return {cancel: () => { img.src = transparentPngUrl; }};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't callback(err) be handled here as well?

Copy link

@hyperknot hyperknot Jul 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think an onerror handler would solve it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, added.

@mourner
Copy link
Member Author

mourner commented Jul 23, 2018

Ran LayerRaster benchmarks — they are unaffected because they don't exercise the performance impact of tile loading.

@hyperknot
Copy link

XHR heuristics works perfectly, both cases are working well.

@jfirebaugh
Copy link
Contributor

What are you using to evaluate this versus the prior behavior? In light testing, I'm not sure I can distinguish the difference.

@mourner
Copy link
Member Author

mourner commented Jul 23, 2018

@jfirebaugh I'm using the original test case here https://codesandbox.io/s/zl761nnr3m — the difference is very noticeable, especially if you have #6995 (another big perf hit) pulled in when comparing.

@hyperknot
Copy link

hyperknot commented Jul 23, 2018

Here is a source with short expires time:

https://a.tile.opentopomap.org/{z}/{x}/{y}.png

And Mapbox satellite for example is with long expires time.

@jfirebaugh
Copy link
Contributor

I'm comparing e9e08e2 and f3f9357 side-by-side on each half of an external monitor and I can't really tell the difference. You're saying it should be really obvious?

@hyperknot
Copy link

@jfirebaugh make sure you don't have developer tools open, as that introduced janks for me in Chrome.

old: https://codesandbox.io/s/zl761nnr3m
new (both PRs merged): https://codepen.io/hyperknot/full/vaxvJN/

@jfirebaugh
Copy link
Contributor

This is with developer tools closed. Subjectively, the behavior I see is:

  • Approximately equal jank between the two. With this PR, maybe slightly less, but that also might be conditioning.
  • This PR shows less blank white space when zooming out.
  • This PR shows more pixelated, overzoomed tiles when zooming in.

@mourner
Copy link
Member Author

mourner commented Jul 23, 2018

@jfirebaugh on the examples above (make sure both are viewed fullscreen), I get heavy stuttering on the old example (on my MBP Retina 15'' screen), especially in the middle of zooming in and zooming out, and almost no jank on the new one.

Perf recording before (optimize-tile-retention) (notice the red dots and big gaps):

image

After (optimize-tile-retention + faster-raster-tiles-load merged in):

image

I also noticed like @hyperknot that it still stutters when devtools are open, but stops stuttering when you start recording a timeline perf profile — I guess Chrome disables some debug stuff while recording.

@jfirebaugh
Copy link
Contributor

With developer tools open, looking at a performance recording, it looks like the time spent sending the requests might just be delayed until the end of the frame, rather than interspersed with JS execution:

image

@jfirebaugh jfirebaugh closed this Jul 23, 2018
@jfirebaugh jfirebaugh reopened this Jul 23, 2018
@mourner
Copy link
Member Author

mourner commented Jul 23, 2018

Here's another comparison, JS profiler. Before:

screen shot 2018-07-23 at 23 53 16

After:

screen shot 2018-07-23 at 23 53 25

Also, subjectively, if I disable the fly animation and just browse the map fullscreen, it's barely usable before the PR with unbearable stuttering, and smooth and pleasant after.

@jfirebaugh
Copy link
Contributor

Yeah, I don't see results as definitive as that. I'm testing locally with this file: https://gist.github.com/jfirebaugh/7cf3e57c359513f980d6aad56283d75e.

image

I wonder what causes such different results for us?

@mourner
Copy link
Member Author

mourner commented Jul 23, 2018

@jfirebaugh I think it's important to have all the other raster perf PRs merged in for this to have pronounced effect. I just rebased both PRs (this and #6995) on master. Now can you compare this PR vs this PR + #6995 merged?

@jfirebaugh
Copy link
Contributor

I've been testing with optimize-tile-retention rebased on master and faster-raster-tiles-load rebased on top of that.

Does someone else want to step in and try? Must be some other variable unaccounted for here.

@hyperknot
Copy link

hyperknot commented Jul 23, 2018

I've ported the example to OpenLayers, with a similar animation (the easing is different).
In my opinion OL is super smooth even with developer tools open. FPS meter shows constant 60 FPS with one or two occasional frames at 30 FPS, or maybe 20 FPS.

https://611v4nk57z.codesandbox.io/
https://codesandbox.io/s/611v4nk57z

@mourner
Copy link
Member Author

mourner commented Aug 2, 2018

@hyperknot @jfirebaugh I just pushed a new WIP branch based on this one that adds a basic image queue (cbb059f), limiting parallel image loads to 16 at a time. Can you try it out and see if it makes a difference for performance?

@mourner
Copy link
Member Author

mourner commented Sep 24, 2018

@hyperknot any comment on the above?

@hyperknot
Copy link

hyperknot commented Sep 24, 2018

@mourner sorry for not responding earlier. So do I understand right that the now stable release (0.49) has the previously discussed improvements, but not the tile queue one? And for tile queue I should check out cbb059f?

@mourner
Copy link
Member Author

mourner commented Sep 24, 2018

@hyperknot the last release includes all improvements except this PR (avoiding XHR for image loading). And additionally cbb059f explores the concept of limiting concurrency for image loads — let's see if it's any faster than this branch.

@hyperknot
Copy link

@mourner OK, I'll check out the improvements and report back today.

@mourner
Copy link
Member Author

mourner commented Oct 17, 2018

@hyperknot any updates?

@hyperknot
Copy link

Oh, sorry, I promised to get back but I didn't. I'll do it now.

@hyperknot
Copy link

@mourner this is absolutely wonderful performance wise! The 2 fps parts are now totally gone, even with console open.

I did a comparison between 0.50 and cbb059f here:
https://codepen.io/hyperknot/pen/bmvzQx
https://codepen.io/hyperknot/pen/xyWMMO

My only problem now is that I'm yet 100% confident in how the code is implemented. What isn't clear is both handleImageLoad and getImage checks for numImageLoads < > maxParallelImageLoads.
Shouldn't one of them be the reference for this test?

Also, are you sure it can never happen that the queue explodes? I mean getImage adds handlers for handleImageLoad which calls getImage.

Having said that, if all the delicate parts of these are thought out by you then I'm happy with the added huge performance improvements!

@mourner
Copy link
Member Author

mourner commented Oct 18, 2018

@hyperknot awesome, thanks a lot for checking! This was a quick proof of concept so likely pretty buggy — and now since this seems promising, I'll probably explore it more. Note that while FPS is improved, the branch codepen version seems to have more blurry tiles when zooming in because new ones aren't loaded fast enough.

We're also exploring raster loading performance from another angle in #7405, which will hopefully bring more improvements too.

@hyperknot
Copy link

hyperknot commented Oct 18, 2018 via email

@hyperknot
Copy link

hyperknot commented Oct 18, 2018

OK, I had some proper look again, at how is blurriness handled, and found some interesting discoveries.

  1. The old behaviour, in the Mapbox GL 0.50 example goes terrible if I select Fast 3G network condition + disable caching in Chrome. Like many second long pauses on totally frozen screen.

  2. The tilequeue version is insanely better in this condition. Like it's actually usable. Blurriness is exactly how it should be.

  3. The 0.50 version really doesn't handle packet loss well. With a 10% or 20% packet loss in Network Link Conditioner, it really quickly generates 3000+ requests, most of them cancelled. Tilequeue handles this case much better as well.

I was using this custom profile in NLC (and "Online" in the browser), it was really good to test this behaviour:

nlc

As the difference in behaviour is extremely big, I even recommend making a universal tile queue and use it for vector tiles as well maybe? This is something which we never see when developing on reliable network connections but mobile clients in the real world can have really high packet losses.

@kkaefer
Copy link
Contributor

kkaefer commented Oct 19, 2018

I can confirm that cbb059f is much smoother on my computer as well. It seems to load the maximum number of image loads that are loaded in parallel. However, I'm still seeing more than one image per frame being uploaded (call to texImage2D). That's something that we should limit to 1 image per second as well, i.e. only fire one onload event per animation frame.

@kkaefer
Copy link
Contributor

kkaefer commented Oct 19, 2018

@hyperknot thank you for these wonderful test cases; they're very useful for debugging this issue!

@mourner
Copy link
Member Author

mourner commented Nov 27, 2018

I have a feeling this PR won’t have much effect after #7497, so I’m going to close for now.

@mourner mourner closed this Nov 27, 2018
@asheemmamoowala asheemmamoowala deleted the faster-raster-tiles-load branch March 9, 2021 05:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants