-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
queryRenderFeatures continued [not ready] #2224
queryRenderFeatures continued [not ready] #2224
Conversation
What's the memory impact of switching to grid index and storing it in both the main thread and the worker? |
I'm very 👍 on the high-level changes in this PR. Before shipping, I'd like for us to think about
|
9b3a74d
to
d342793
Compare
Good question. I hadn't benchmarked that yet. It is generally only stored in one thread at a time. Async queries create a duplicate but that duplicate is discarded at the end of the query. We could maintain a duplicate version to reduce the cpu cost, but the cpu cost is pretty low and async queries should only be used for expensive queries. For each of the benchmarks I cropped the window so that it loaded only one tile. I used mapbox-streets-v6 because v7 merges features into huge multigeometries. This branch implements subfeature indexing (a bbox for each ring, not each feature) but the old one doesn't so it isn't a fair comparison when using v7.
The Grid in FeatureTree uses far less memory than rbush. 340 KB vs 1843 KB and 117 KB vs 420 KB. The Grid in CollisionTile uses more memory than rbush. 225 KB vs 20 KB and 280 KB.
Summary:
|
Buffer does a whole bunch of extra calculations like scaling values and it doesn't provide an interface for reading values. I think it might make sense to wait until dds settles down before trying to merge the two.
How would stateless workers help us write better integration tests?
Yes, I definitely want to write reusable benchmarks. Do we want to start using a framework for this or continue writing it ourselves (like with the buffer benchmark)? |
ceb13b8 reduces Grid memory usage from 225 KB to 85 KB for the z12 case and from 280 KB to 169 KB for the z17 case. |
@ansis fantastic! I'm all 👍 on the changes then. I'll review the code in more detail. |
That's not correct. Those "extra calculations" are done in
It has a
The
Out of scope for this PR. I'm excited about the implications of a simpler interface for writing better integration tests through
I'm going to design a simple benchmark interface specification today. It'll be similar to how the buffer benchmark works. |
Yeah, you're right. I confused the two. I'll take a closer look at this today.
Great!
Is it worth writing our own? Should we just use something like https://github.com/bestiejs/benchmark.js/ ? |
benchmark interface specification pushed to #2231 😄 |
ceb13b8
to
806a77b
Compare
8bdf3c7
to
68f186d
Compare
806a77b
to
ca23cca
Compare
Rebased on master. Latest commit used to be 3fc75bd3127436715d0ec2e88d52aade617ea526. |
e7b49f1
to
3530bb2
Compare
A convention I've been using, and have found fruitful:
|
1ac623a
to
1d8b595
Compare
68f186d
to
506bec5
Compare
21dddbc
to
4a48755
Compare
and accept only an array of strings. fix #2230
It's faster, but not fast enough to be worth it.
let's try to get by with just queryRenderedFeatures
and split intersection tests into a separate file
6e8bcef
to
056fbc0
Compare
9a5432d
to
e5a4152
Compare
🎉 |
This builds on #2052.
This is not ready, but it could use some high level 👀. I probably should have gotten some 👀 a bit earlier. Let me know if any of the high level ideas here concern you. I'll comment again later when this is more polished.
The raw vector tile pbf, FeatureTree and CollisionTile are now transferred to the main thread when a tile finishes loading. This lets use have a synchronous
queryRenderedFeatures
, it lets us eliminateincludeGeometry
without a performance hit, and it starts moving us towards more state-less workers.A synchronous queryRenderedFeatures
This adds a synchronous version of
queryRenderedFeatures
.There is still an async version. It transfers data back to workers.
Despite being parallelized, the async version is not faster than the sync version. It ends up parsing from the pbfs twice instead of once. It spends less time on the main thread though which could be useful for large, expensive queries. I think it could be worthwhile to keep both versions as
queryRenderedFeatures
andqueryRenderedFeaturesAsync
Getting rid of
includeGeometry
The
includeGeometry
param forqueryRenderedFeatures
only exists because sending geometries from the worker back to the main thread was slow. When the pbf is on the main thread individual geometries can be deserialized lazily. This lets us dropincludeGeometry
without a performance penalty.indexing with Grid
I replaced rbush with a
Grid
, a different kind of spatial index.Grid
can be serialized to an ArrayBuffer to make it transferrable. The serialized version can be queried directly without deserializing individual elements to javascript objects. It is faster than rbush for collision detection and comparable for rendered feature querying. It's faster because insertions are faster.Grid is a grid of cells. When a bbox is inserted it is added to all the cells it intersects. When a bbox is queried it looks in all cells that intersects with that bbox. That's it.
It isn't faster than rbush generally, but it is faster for what we use it for: a fixed extent, mostly evenly sized bboxes, and a high number of insertions. More importantly, it's transferable.
Storing arrays of "structs" in ArrayBuffers
There are a bunch of cases where we have giant arrays of fixed size objects. I added a new abstraction, StructArray, that makes it easier to store these kinds of objects in ArrayBuffers. It's inspired by the new Buffer implementation. It:
see 9a2e5fd 's commit message for an example
Reducing worker state
Both Grid and StructArrays are transferrable and don't need to be deserialized to individual objects before they can be used. This makes moving them between workers and the main thread really fast and reduces the amount of data that is "stuck" on workers. When
symbolInstances
is made completely transferable we could get rid of WorkerTiles that live after parsing has finished.The work requests would transfer all the data that is needed and not rely on the worker having any unique data. I think this is also more similar to how we want work requests to work in -native.
Since work won't be tied to a specific thread, it should be possible to distribute work more consistently and speed things up.
Benchmarks
Compared to #2052
next steps
Cleaning things up. Fixing tests. Fixing a couple remaining bugs.
Do all the high level changes sound ok?
@lucaswoj @jfirebaugh @mourner