-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Adding profiling support for concurrent segment search #14413
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
Conversation
Signed-off-by: Ankit Jain <[email protected]>
Signed-off-by: Ankit Jain <[email protected]>
Signed-off-by: Ankit Jain <[email protected]>
Signed-off-by: Ankit Jain <[email protected]>
Can you explain why we need two impls? I would have assumed that the |
Hence, I felt we don't need to take the overhead of creating breakdown per segment and then merging it together during response. That being said, eventually we can keep just |
Does it make sense to create a separate Can this be implemented as part of the |
@jainankitk OK. In my opinion, it's more important to handle the concurrent and non-concurrent cases consistently than to save some overhead when searches are not concurrent. I'd really like non-concurrent search to look and feel like a concurrent search with a single slice running on a SameThreadExecutorService as far as profiling is concerned. So I wouldn't specialize the class hierarchy for concurrent vs. non-concurrent. |
Actually, create one per slice makes lot of sense.
We can always use |
Let me try and see if we can maintain per slice |
Signed-off-by: Ankit Jain <[email protected]>
Signed-off-by: Ankit Jain <[email protected]>
Signed-off-by: Ankit Jain <[email protected]>
One of the failing check is:
I am wondering if there is a workaround for this? One option is to use |
You just need to replace |
Signed-off-by: Ankit Jain <[email protected]>
Ah, my bad! I tried At a high level, I have unified the concurrent/non-concurrent profiling paths as suggested. The
We can probably have map of slices, with key being the
|
@jpountz - Can you provide your thoughts on above? |
I'd have a top-level tree for everything related to initializing the search and combining results (rewrite(), createWeight(), CollectorManager#reduce) and then a list of trees for each slice. Related, it'd be nice if each per-slice object could also tell us about the thread that it ran in and its start time so that we could understand how exactly Lucene managed to parallelize the search. |
Signed-off-by: Ankit Jain <[email protected]>
Signed-off-by: Ankit Jain <[email protected]>
Signed-off-by: Ankit Jain <[email protected]>
Signed-off-by: Ankit Jain <[email protected]>
While working on the code, I realized it is better to have list of slices within the tree itself at each level, instead of repeating the query structure and information across multiple trees. In this approach, we can easily view the tree for specific
Yes, that would be really useful. I have included the threadId as |
@jpountz - The code changes are ready for review. For now, I have made changes to accommodate all the timers in While this does not modify ( |
I submitted talk on this topic ( |
This PR has not had activity in the past 2 weeks, labeling it as stale. If the PR is waiting for review, notify the [email protected] list. Thank you for your contribution! |
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.
Sorry, I had lost track of this PR. I think that my only concern left is how it computes end times by adding the approximate timing to the start time. I'd rather not report it since this profiler doesn't actually compute an end time, but I'd be fine with reporting the sum of approximate timings if we think that it helps.
} | ||
|
||
/** Retrieve the lucene description of this query (e.g. the "explain" text) */ | ||
public long getId() { |
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 seems to be a mismatch between javadocs and the method signature.
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 seem to have copied these getters from some existing code and missed editing the javadocs. Let me fix that!
|
||
/** The timing breakdown for this node. */ | ||
public Map<String, Long> getTimeBreakdown() { | ||
return Collections.unmodifiableMap(breakdown); |
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.
You could do the wrapping only once in the constructor?
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.
Oh yeah, good point! Since the object is immutable
this.leafLevel = leafLevel; | ||
} | ||
|
||
public boolean isLeafLevel() { |
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.
Add some javadocs? I believe that this means that this operation runs on a LeafReader as opposed to the top-level IndexReader?
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.
Yes, your understanding is correct. Added the javadocs!
|
||
import java.util.List; | ||
|
||
interface QueryLeafProfilerAggregator { |
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 wonder if we actually need this interface since it seems to have a single implementation?
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 planning to introduce other implementations later, but I guess we can add this interface at that point. Removing for now!
Arrays.stream(QueryProfilerTimingType.values()).filter(t -> t.isLeafLevel()).toList(); | ||
|
||
/** The accumulated timings for this query node */ | ||
private final QueryProfilerTimer[] timers; |
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.
What about using an EnumMap
, which will be implemented by an array like this one under the hood?
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.
Although minor, but EnumMap
will initialize the timers for all the possible keys vals = new Object[keyUniverse.length];
. It seemed bit unnecessary to me, but we can change if using EnumMap
improves the readability.
sliceStartTime = Math.min(sliceStartTime, timer.getEarliestTimerStartTime()); | ||
sliceEndTime = | ||
Math.max( | ||
sliceEndTime, timer.getEarliestTimerStartTime() + timer.getApproximateTiming()); |
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 doesn't feel right the compute the end time as the start time plus the approximate timing, since operations will often be interleaved. What about reporting the sum of the approximate timings across operation types instead, ie. the value of toTotalTime()
?
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.
Good catch! That was an oversight from my side. Will change this toTotalTime()
, which should approximately reflect the consumed cpu time for processing this query
SLICE, | ||
// Aggregate leaf level breakdowns based on thread execution | ||
THREAD | ||
} |
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.
Is this actually used? I think that from previous discussions we agreed that SLICE
wouldn't work since Lucene doesn't tell us what slice it's in. And I don't see LEAF being used in this PR
, only THREAD
?
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.
Yeah, only THREAD
is being used for now. I was planning to introduce other implementations like LEAF
later, but I guess we can add this enum at that point.
lucene/sandbox/src/java/org/apache/lucene/sandbox/search/QueryLeafProfilerThreadAggregator.java
Outdated
Show resolved
Hide resolved
lucene/sandbox/src/java/org/apache/lucene/sandbox/search/QueryLeafProfilerThreadAggregator.java
Outdated
Show resolved
Hide resolved
This PR has not had activity in the past 2 weeks, labeling it as stale. If the PR is waiting for review, notify the [email protected] list. Thank you for your contribution! |
No worries @jpountz, thanks for the review. Even I was away for a bit, will try to address the comments and push new revision this week. |
Signed-off-by: Ankit Jain <[email protected]>
This PR does not have an entry in lucene/CHANGES.txt. Consider adding one. If the PR doesn't need a changelog entry, then add the skip-changelog label to it and you will stop receiving this reminder on future updates to the PR. |
Signed-off-by: Ankit Jain <[email protected]>
This PR does not have an entry in lucene/CHANGES.txt. Consider adding one. If the PR doesn't need a changelog entry, then add the skip-changelog label to it and you will stop receiving this reminder on future updates to the PR. |
Signed-off-by: Ankit Jain <[email protected]>
@jpountz - I have addressed all the comments from earlier review. Are you able to take another look, to help close this out? |
This PR has not had activity in the past 2 weeks, labeling it as stale. If the PR is waiting for review, notify the [email protected] list. Thank you for your contribution! |
Thanks all for reviewing this PR. Planning to merge this PR by tomorrow, if there is no new feedback. Again, thanks for helping improve this change with your inputs! |
--------- Signed-off-by: Ankit Jain <[email protected]>
Hi @jainankitk , is |
or if we do need to maintain the Thread association, can we store the Thread.id (an int I think) instead of the Thread? |
Thanks @dungba88 for trying this out.
The |
Description
This code change introduces
AbstractQueryProfilerBreakdown
that can be extended byConcurrentQueryProfilerBreakdown
to show query profiling information for concurrent search executionsIssue
Relates to #14375