-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[not ready] anno remove bug fix & in-app settings to flex annotations #1061
Conversation
Moving to Hash used for struct Hash {
std::size_t operator()(ID const& i) const {
return std::hash<uint64_t>()(i.to_uint64());
}
}; |
You can use an intrusive list and return the actual object pointer as annotation ID. Deletion is O (1) for intrusive lists. |
Not sure I follow @mb12 — the bottleneck is on iteration of the |
My mistake. I was referring to annotations map in AnnotationManager. It could be safely converted to an intrusive list if it were a performance bottleneck. |
For point annotations you can skip the inner loop once it's annotation tile is found. A point annotation can lie on only one tile. This should help a bit. Full iteration through all tiles is needed only for lines and areas which get clipped into multiple tiles. |
We can also delete the annotation tile itself in the inner loop if all its annotations have been deleted. |
Well, point annotations are in one tile per zoom level. But I could use that knowledge to maybe make things smarter. |
We can also use the following approach for handling point annotations. 1.) With every point annotation, save also the actual latitude, longitude during the add call (if not doing so already). |
Great idea. The |
Greatly increase performance for feature removals with acceptable tradeoff in feature inserts. Remove features by key instead of by pointer identity check. Track annotation features by key instead of weak pointer to actual tile features.
Ok, I was able to restructure things a bit in the way we store live tile features so that removal is much faster at annotation delete time. First improvement in 48d70c4 avoids a high-overhead iteration of all of the annotation manager's tiles for each annotation by calculating an annotation's intersected tile in each zoom upfront, since this is predictable. It uses the same projection math done at annotation creation time, but the overhead is low. Based on @mb12's recommendation in #1061 (comment). Second improvement in b4daad5 avoids a simple assignment operator penalty, which was the new bottleneck. That still left an unacceptable time (~10s) for removal of 10,000 annotations on an iPhone 5s. The third improvement in ee2e32f moves from a vector of live tile features in a layer to an unordered map keying on a unique Other thing I'm a little fuzzy on is the adaption of the interface method util::ptr<const GeometryTileFeature> LiveTileLayer::getFeature(std::size_t i) const {
auto it = features.begin();
std::advance(it, i);
return it->second;
} Review is welcome, particularly by @jfirebaugh since he made I saw, and still see, near-instant adds of 100, 1000, or 10000 annotations, and the noticeable delay for removal of the 10,000 went from over 13 seconds in the original ticket to less than 2 seconds. Considering the 10,000 annotations is meant to be a stress test and not a common use case, I think we're good here perf-wise with a speedup of 6.5x. |
BTW the biggest delay here for adds is actually the GeoJSON parsing of 10,000 features, not the addition & rendering in GL. |
Eh, I'm not super happy with the rendering tradeoffs here. The 10,000 annotations are now visibly tiling when before they weren't. I suspect it's the move to I would want to wait on landing these perf improvements until we get @kkaefer's general API improvements from #1022 landed, even if we don't yet fix the threading problem there. See my latest comment in #1022 (comment). |
A |
Ahhh, but util::ptr<const GeometryTileFeature> LiveTileLayer::getFeature(std::size_t i) const {
return features.find(i)->second;
} |
I don't think moving from a Currently trying going back to a |
No, to improve deletion performance of specific features from a |
Can you convert LiveTileLayer::features to an intrusive list? Basically the next and prev pointer will be come part of LiveTileFeature making deletion and insertion an O(1) operation. |
If I'm understanding right, this runs into problems similar to those described in #1061 (comment) ("complications") because feature getting should be |
Iteration by index is not really needed. Its just a sequential iteration of all objects in the container both in TileParser and SymbolBucket. |
Right. But what is a good way to do this? |
For Why is the Beyond these two things, the more fundamental issue is that the APIs of |
Instead of getFeature, provide an iterator that iterates through all Features in the TileLayer. |
@mb12 Right, tried this per above. The problem is
@jfirebaugh Sure, for points. We'll be doing shapes, too.
I've kept everything layered this way because shapes will eventually need their own layer each for per-annotation styling (so, filter expressions). Points can all go into a single layer, but I suppose they don't have to. Was just trying to keep things simple organizationally. I think splitting point annotations into multiple layers will get complicated when it comes to selection/picking, as well as with rendering when z-ordering issues come into play. I'm not too worried about gestures on shape annotations; even Apple doesn't have this. |
Nice, I like it. This is my inexperience with |
Use of |
If the returns value of getFeatures is a const_iterator wouldn't that ensure that doing iter or iter() return a const T. |
Eh, hashing a
@mb12 Lemme check it out. |
We're currently at about 3 seconds to remove 10,000 annotations from an iPhone 5s. I think we've made enough improvements here, actually. Lots of little stuff, and although the paradox that @jfirebaugh outlines may still hold, it's not worth focusing on so much right now, especially given that the annotations model may change when we move to shapes. I'm cool to squash the improvements here and merge soon. |
@mb12 |
Seems like it should be true for shapes too. |
Right, I was forgetting that |
@jfirebaugh Yes, we would have to create an iterator that wraps around the underlying container (vector, map, intrusive list, unordered_map) iterator and return it instead of vector.begin(). |
Looking like this: https://dl.dropboxusercontent.com/u/575564/100%2C%201000%2C%2010000.mp4 |
Going to wait for tests to pass here, then merge this and leave perf alone for a while. |
Oh, gotta merge |
Squashed over in #1076. |
Add a GeoJSON with ~10,000 point features and allow for addition of 100, 1000, or 10000 of them in-app, plus removal.
Fixes a crasher in annotation removal.
Needs some work for removal of 10000 features per: