-
Notifications
You must be signed in to change notification settings - Fork 200
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
GeometryGraph and PreparedGeometry multi-threaded (Send) #1198
base: main
Are you sure you want to change the base?
Conversation
geo/src/algorithm/relate/geomgraph/index/rstar_edge_set_intersector.rs
Outdated
Show resolved
Hide resolved
#1197 has been merged - could you do a rebase or merge to minimize the diff? |
I have rebased, but I haven't had time to work any further on this yet (feel free to make changes if you have time). |
Some of the test fails seem like numeric precision errors, they are also present on
|
The lifetime in prepared geometry is tedious to work with. Could that be replaced by a Cow or maybe a owned version of the geometrygraph? |
Just realized that is exactly how it is now... |
This seems to be working now. It appears that a new geometrygraph + intersection matrix is created for every point I want to check against the preparedgeometry. |
Can you expand on this and / or illustrate it with a minimal test case? |
My use case is roaring-landmask, here's a PR where I am running against these changes: gauteh/roaring-landmask#28, in https://github.com/gauteh/roaring-landmask/blob/georust-prepared/src/shapes.rs#L129 I check if a point is in any of the polygons using
this creates a geometrygraph of the point In roaring-landmask this may be tested with e.g.: |
That's right. The difference with The point's graph will be created from scratch, since it's a different point every time, but it should also be a pretty trivial graph.
Note that in the case of points and polygons, The GeometryGraph is a very general tool, built to handle all the de-9im relations for all geometry types. If you are only interested in "point intersects polygon" checks, there is likely a faster approach involving less machinery - maybe ray casting, but I don't think we have an implementation of that yet. |
Indeed, the tree has no members.
Is there any performance difference? Or exactly the same?
So it appears, and that makes sense (to start with). I think that this PR is mostly functional now. I had to make a few slightly messy changes to satisfy borrowing rules, without doing a much greater re-structuring. There is some cleanup to be done, but it should be a useful feature (and actually a pretty cool plus over geos, where it is not safe to share the PreparedGeometry) to other applications. Sadly, I don't think it will make much difference to my issue (#1184). |
let segment_intersector = self | ||
.graph_a | ||
.compute_edge_intersections(&self.graph_b, Box::new(self.line_intersector.clone())); | ||
// let segment_intersector = self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not clear on what's happening here.
@michaelkirk I've rebased and tidied this up and appeased young master Clipperton – I only have one query regarding the "satisfy rust's borrowing rules section" but otherwise this hasn't added any obvious complexity to our |
@@ -35,7 +34,7 @@ where | |||
{ | |||
arg_index: usize, | |||
parent_geometry: GeometryCow<'a, F>, | |||
tree: Option<Rc<RTree<Segment<F>>>>, | |||
tree: Option<RTree<Segment<F>>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some positive changes in this PR, but there is a serious perf regression with:
relate prepared polygons
time: [142.78 ms 143.14 ms 143.63 ms]
change: [+192.56% +193.59% +194.76%] (p = 0.00 < 0.05)
Performance has regressed.
I haven't zeroed in on the cause yet - but this line is suspect. The point of the Rc<Tree>
is that it was cheap to clone. It seems like we've removed that and now have a "cache the tree and invalidate it as necessary" approach.
Note there are also some nice performance wins to the non-prepared geometry operations in this PR, but I personally don't think it's worth it as phrased.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooof yeah that regression is a show-stopper at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whoops - didn't mean to approve yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's nice to get rid of the Rc<RefCell<T>>
, but there is a lot of new complexity for the sake of Send. In the meanwhile, people can Send their geometry and make a PreparedGeometry on each thread.
Is there a way it can be simplified?
} | ||
} | ||
|
||
fn invalidate_tree(&mut self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got a little more complex.
edge_1, | ||
segment_1.segment_idx, | ||
); | ||
if segment_1.edge_idx == segment_0.edge_idx { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got quite a lot more complex.
@@ -95,25 +94,85 @@ where | |||
false | |||
} | |||
|
|||
// Copy of `add_intersections` specialized for a single 'edge' against itself. | |||
pub fn add_intersections_against_self( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got quite a lot more complex.
// this is a copy of the above functionality to satisfy rust borrowing rules. | ||
// from here [... | ||
let mut segment_intersector = | ||
SegmentIntersector::new(Box::new(self.line_intersector.clone()), false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got a bit more complex.
Make GeometryGraph and PreparedGeometry Send so that it can be used by multiple threads.
Based on and depends on: #1197