Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core, ios] Improve performance of queryRenderedFeatures by reducing # of temp GeometryCollection #15183

Closed
wants to merge 13 commits into from

Conversation

julianrex
Copy link
Contributor

This PR aims to improve performance of queryRenderedFeatures by reducing the number of temporary GeometryCollection that are allocated.

  • getGeometries() is now called once, rather than 3 times; it is passed in to subsequent functions
  • offsetLine(...) now returns a std::unique_ptr - beforehand the copy-constructor & destructor were being called...a lot. (This is the main improvement).
  • iosapp has been updated with a menu entry so that we can test these improvements (and future improvements).

Note - this does NOT have @pozdnyakov's suggestion of using mbgl::Immutable - I started, but I'd need to pair on this - perhaps we can do this as a follow-on PR?

@julianrex julianrex added iOS Mapbox Maps SDK for iOS Core The cross-platform C++ core, aka mbgl querying Issues with querySourceFeatures or queryRenderedFeatures labels Jul 19, 2019
@julianrex julianrex added this to the release-q milestone Jul 19, 2019
@julianrex julianrex requested review from pozdnyakov, alexshalamov and a team July 19, 2019 18:41
@julianrex julianrex added the ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold label Jul 19, 2019
@julianrex
Copy link
Contributor Author

@tobrun can you take a look at this and see what changes are needed for Android.


if (offset == 0) return nullptr;

std::unique_ptr<GeometryCollection> newRings = std::make_unique<GeometryCollection>();
Copy link
Contributor

Choose a reason for hiding this comment

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

After some checks I came to conclusion that we could keep the old semantics with the optional return type.
The problem was caused by implicit copy of the local variable on return, that can be fixed just with adding std::move() call (RVO is failing here as local and return types are different).

optional<GeometryCollection> offsetLine() {
GeometryCollection newRings;
return newRings; // Copy here!
}

optional<GeometryCollection> offsetLine() {
GeometryCollection newRings;
return std::move(newRings); // No copy :)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gotcha - will test out.

Copy link
Contributor

Choose a reason for hiding this comment

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

return std::move(newRings); will prevent copy elision, I think we even have clang check for that.

Another option is to return optional<GeometryCollection>(std::move(newRings));

Copy link
Contributor

Choose a reason for hiding this comment

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

hm, another issue could be that we have two return statements that could prevent RVO.

Copy link
Contributor

Choose a reason for hiding this comment

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

return std::move(newRings); will prevent copy elision

in this case we're creating an instance of another type: optional<GeometryCollection>. Returning rvalue triggers converting move constructor; returning lvalue triggers converting copy constructor.

@julianrex
Copy link
Contributor Author

@pozdnyakov can you help with the node changes? I started to try to understand what needs to be changed but very quickly hit a road block. Would the change back to optional potentially fix the node tests that are failing?

@tobrun
Copy link
Member

tobrun commented Jul 22, 2019

@tobrun can you take a look at this and see what changes are needed for Android.

afaik none at the moment

@pozdnyakov
Copy link
Contributor

@pozdnyakov can you help with the node changes? I started to try to understand what needs to be changed but very quickly hit a road block. Would the change back to optional potentially fix the node tests that are failing?

The proposed change had slightly affected logic in RenderLineLayer::queryIntersectsFeature, which caused render tests failures. Fixed now in 4f5dac6 (it also contains some further refactoring to offsetLine function).

@julianrex
Copy link
Contributor Author

Just forced pushed, which overwrites @pozdnyakov's 4f5dac6 - running through Instruments shows that using optional is slower than std::unique_ptr. Timing went down from an average of 179ms to 128ms (on an iPhone X).

Unfortunately the low average we were seeing earlier was due to the bug mentioned above - not making enough calls :(

@julianrex julianrex removed the ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold label Jul 22, 2019
@julianrex
Copy link
Contributor Author

New low average is around 75ms (Both Release and RelWithDebInfo) - perhaps due to switch to emplace_back (or perhaps the 128ms was a trace using a old framework build).

@julianrex julianrex requested a review from 1ec5 as a code owner July 22, 2019 15:01
@julianrex julianrex removed the request for review from 1ec5 July 22, 2019 15:01
@julianrex
Copy link
Contributor Author

Rebased.

@pozdnyakov
Copy link
Contributor

Optional: could we squash some commits?

@@ -112,8 +112,6 @@ static Feature::geometry_type convertGeometry(const GeometryTileFeature& geometr
);
};

GeometryCollection geometries = geometryTileFeature.getGeometries();
Copy link
Contributor

Choose a reason for hiding this comment

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

@julianrex @pozdnyakov was there a need to pass const GeometryCollection& geometries all the way here when we already have constref to geometryTileFeature?

I think the problem was on line 115 where we made copy. Should have been:

const GeometryCollection& geometries = geometryTileFeature.getGeometries();


if (offset == 0) return nullptr;

std::unique_ptr<GeometryCollection> newRings = std::make_unique<GeometryCollection>();
Copy link
Contributor

Choose a reason for hiding this comment

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

return std::move(newRings); will prevent copy elision, I think we even have clang check for that.

Another option is to return optional<GeometryCollection>(std::move(newRings));

@@ -8,6 +8,9 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT

* Fixed flickering on style change for the same tile set ([#15127](https://github.com/mapbox/mapbox-gl-native/pull/15127))

### Other changes

* Improved feature querying performance (focussed on roads). ([#15183](https://github.com/mapbox/mapbox-gl-native/pull/15183))
Copy link
Contributor

@alexshalamov alexshalamov Jul 22, 2019

Choose a reason for hiding this comment

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

focused? 😄 I've never used focussed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

UK English ;)

Copy link
Contributor

@friedbunny friedbunny Jul 22, 2019

Choose a reason for hiding this comment

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

If even the Europeans are against you... 😅

In any case, this also struck me as wrong. I think we should stick with ‘merican English, given our audience/company/etc.

Alternatively:

Suggested change
* Improved feature querying performance (focussed on roads). ([#15183](https://github.com/mapbox/mapbox-gl-native/pull/15183))
* Improved feature querying performance of road features. ([#15183](https://github.com/mapbox/mapbox-gl-native/pull/15183))

@@ -265,13 +268,14 @@ bool RenderLineLayer::queryIntersectsFeature(
.evaluate(feature, zoom, style::LineOffset::defaultValue()) * pixelsToTileUnits;

// Apply offset to geometry
auto offsetGeometry = offsetLine(feature.getGeometries(), offset);
auto offsetGeometry = offsetLine(geometries, offset);
Copy link
Contributor

Choose a reason for hiding this comment

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

const auto& offsetGeometry = offsetLine(geometries, offset);

@julianrex julianrex added the ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold label Jul 22, 2019
@julianrex
Copy link
Contributor Author

Chatting with @alexshalamov - we're going to continue investigating this.

@@ -8,6 +8,9 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT

* Fixed flickering on style change for the same tile set ([#15127](https://github.com/mapbox/mapbox-gl-native/pull/15127))

### Other changes

* Improved feature querying performance (focussed on roads). ([#15183](https://github.com/mapbox/mapbox-gl-native/pull/15183))
Copy link
Contributor

@friedbunny friedbunny Jul 22, 2019

Choose a reason for hiding this comment

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

If even the Europeans are against you... 😅

In any case, this also struck me as wrong. I think we should stick with ‘merican English, given our audience/company/etc.

Alternatively:

Suggested change
* Improved feature querying performance (focussed on roads). ([#15183](https://github.com/mapbox/mapbox-gl-native/pull/15183))
* Improved feature querying performance of road features. ([#15183](https://github.com/mapbox/mapbox-gl-native/pull/15183))

@@ -17,6 +17,8 @@
#import "../src/MGLMapView_Experimental.h"

#import <objc/runtime.h>
#import <os/log.h>
#import <os/signpost.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

iosapp is larded down and we’ve been trying to trim it back — since this logging functionality could presumably be useful in other/future view controllers, can we move this stuff out into a separate file?

@alexshalamov
Copy link
Contributor

@julianrex @pozdnyakov pushed some experiments to https://github.com/mapbox/mapbox-gl-native/compare/alexshalamov_wip_qrf

Not sure why 'unique_ptr' version is faster than construction / elision of geometrycollection on stack.

@julianrex
Copy link
Contributor Author

julianrex commented Jul 23, 2019

Summarizing chat with @alexshalamov & @pozdnyakov: we are going to split this PR into 2 new ones:

@friedbunny I will address your comments in the new PR!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Core The cross-platform C++ core, aka mbgl ⚠️ DO NOT MERGE Work in progress, proof of concept, or on hold iOS Mapbox Maps SDK for iOS querying Issues with querySourceFeatures or queryRenderedFeatures
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants