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

Experimental "all" codepath #11

Merged
merged 4 commits into from
Nov 21, 2013
Merged

Experimental "all" codepath #11

merged 4 commits into from
Nov 21, 2013

Conversation

twpayne
Copy link
Contributor

@twpayne twpayne commented Nov 4, 2013

This PR adds a short code path when it's known that all children of a node overlap the target bounding box.

Right now, this code is neither tested nor properly benchmarked. (How do I run the tests?).

Observations:

  • In theory, this should improve performance with large bounding boxes by avoiding bounding box intersection tests and instead switching to fast native code (Array.prototype.push.apply) to collapse common cases.
  • In practice, the limited testing that I've done indicates that it might not be worth it. I'm not sure why.
  • In theory, this should work better with "real life" data where overlapping objects are less common. If objects overlap (e.g. in the debug/perf.js tests) then the advantage will be smaller.

At this stage: comments welcome! Maybe this helps, maybe it doesn't....

@mourner
Copy link
Owner

mourner commented Nov 5, 2013

That's an interesting suggestion to try, thanks Tom! I'll run the perf tests (I did them mostly with node, node perf.js) and see if it really improves the performance, as it's such a common use case to run large-bbox queries. In theory it should, but V8 can be very smart at optimizing and removing dead code paths.

Tests also leave a lot to be desired, I'll try to improve the coverage significantly as one of the next step improvements.

@@ -38,7 +42,11 @@ rbush.prototype = {
childBBox = node.leaf ? this._toBBox(child) : child.bbox;

if (this._intersects(bbox, childBBox)) {
(node.leaf ? result : nodesToSearch).push(child);
if (this._contains(bbox, childBBox)) {
this._all(node, result);
Copy link
Owner

Choose a reason for hiding this comment

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

Here's the culprit! The loop goes through node children, but if the child bbox fits into the search area, you're then running _all on the whole node instead of just the child that fits.

Rewriting this line like this fixes the issue and provides ~3x improvement of 10% searches in my tests:

if (node.leaf) {
    result.push(child);
} else {
    this._all(child, result);
}

Copy link
Owner

Choose a reason for hiding this comment

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

I wonder why the tests pass with this. :) There should a mistake there as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well found @mourner! I've updated the branch to include your fix.

mourner added a commit that referenced this pull request Nov 21, 2013
Experimental "all" codepath
@mourner mourner merged commit a22adcf into mourner:master Nov 21, 2013
@mourner
Copy link
Owner

mourner commented Nov 21, 2013

@twpayne Thanks Tom! Any idea why the test passed before the fix?

mourner added a commit that referenced this pull request Nov 21, 2013
mourner added a commit that referenced this pull request Nov 21, 2013
@twpayne
Copy link
Contributor Author

twpayne commented Nov 21, 2013

I don't know. It may be that it's just a property of the test data that we're using that means that the bug did not manifest in this case. For testing these sort of data structures, I often generate random data and test my code against a known good (but maybe slow, or trivial) implementation, and check that both return the same result.

@twpayne
Copy link
Contributor Author

twpayne commented Nov 21, 2013

Thanks for the second fix :)

@mourner
Copy link
Owner

mourner commented Nov 21, 2013

@twpayne it would be great to find a test case that fails without the fix but passes in both the latest master and the version before the pull, so we could avoid potential regressions when improving something in future.

@twpayne
Copy link
Contributor Author

twpayne commented Nov 21, 2013

OK, will do. It'll take me a few days (very busy at the moment) but I promise to do it!

@mourner
Copy link
Owner

mourner commented Nov 21, 2013

No rush Tom, thanks again! This is a really awesome improvement — dramatically better times on all searches (updating benchmark results now).

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.

None yet

2 participants