-
Notifications
You must be signed in to change notification settings - Fork 56
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
Add find_location_range #196
Conversation
7549f55
to
d2678d3
Compare
Coverage check failure looks unrelated to this change. |
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.
Thanks for the PR! Just letting you know that I'll probably bit a slow to properly review this, since it's a complex change. It'd be good if we could avoid this iterator complexity somehow, but I'm not sure if that will be possible. Also, it's a significant loss in the context_query_location_slice
benchmark:
context_query_location_rc 892,787 1,459,657 566,870 63.49% x 0.61
context_query_location_slice 898,126 1,452,600 554,474 61.74% x 0.62
context_query_with_functions_rc 3,093,417 3,340,108 246,691 7.97% x 0.93
context_query_with_functions_slice 2,763,489 2,912,667 149,178 5.40% x 0.95
src/lib.rs
Outdated
}) | ||
.filter_map(move |i| { | ||
// If this CU doesn't actually contain this address, move to the | ||
// next CU. | ||
if probe > i.range.end { | ||
if probe_low > i.range.end || probe_high <= i.range.begin { |
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.
Should this be probe_low >= i.range.end
?
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 was replicating the original logic - does that mean the original should be probe >= i.range.end
? (I suspect so.)
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.
No I think that's correct, but I got probe_low <= i.max_end
wrong a couple of lines above.
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.
A reason I commented is because this check and the one a couple of lines above need to be consistent, unless my understanding is wrong. They are consistent on master, but this PR made them inconsistent, and 6001cec changes them both again so they are still inconsistent. I think probe_low >= i.range.end
is correct here, because i.range.end
is exclusive (and i.max_end
is exclusive too), meaning this was a bug on master. So you need to change the one a couple of lines above again to be probe_low < i.max_end
.
In my initial implementation I just made it return But I wasn't sure what the conventions were for this library, since none of the other iterator-like return values seem to do this. Iteration is important for me, since quite often I'll not consume the whole range, so there's a benefit to generating the values lazily.
I was wondering about that. The new code is definitely does more for the single lookup case. I was mostly focused on removing any code duplication, but I guess it could be factored in a way that allows the single lookup to have a fastpath. |
I fixed the performance regression by quite a bit:
|
src/lib.rs
Outdated
|
||
match unit_iter.next() { | ||
Some(unit) => unit.find_location(probe, sections), | ||
None => Ok(None), |
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.
Can you change this function back to exactly how it was on master
? It's important that we loop through the units here if required. Unfortunately we don't seem to have any tests that check this case...
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.
Ah, right.
Great! I guess that is mainly due to avoiding the allocation. Can you see if it makes sense to apply the changes in philipc@de7aee3? I haven't tested these, but I think they simplify things a little. |
OK I incorporated your simplifications with a tweak or two and fixed up the boundary check in Bench comparison is now
I think it very slightly regressed with the simplifications, but not enough to be confident. |
This adds `find_location_range` which is the equivalent of `find_location` except that it takes an lower and upper address bounds and returns an iterator of all source locations found in that range.
I think this is due to the correctness fix in |
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.
Thanks!
By the way, what application are you using this for such that you don't want to know the inlined function locations too? |
Yeah I've been thinking about inlining. I'm using find_frames which is not too bad since I know the location boundaries but it would be nice to get better perf. For my use case I'm only interested in the top noninlined frame so I'm thinking it should return a double ended iterator. |
I have a use-case where I want to get the source locations for a range of addresses. The simple approach is to just call
Context::find_location
on each address in the range - this works, but it is extremely slow since:This PR implements
find_location_range
which returns an iterator of all the locations in the range. It is much more efficient because it amortizes all the setup cost and directly returns the locations in the range. In addition to the Location, it also returns the address and length of the byte range the location describes.It also implements
find_location
in terms of returning a single Location from a 1 byte range.