Trace grouping details and timing on content nodes - #37986
Open
dainiusjocas wants to merge 4 commits into
Open
dainiusjocas wants to merge 4 commits into
dainiusjocas wants to merge 4 commits into
Conversation
At trace level 6, add a "grouping" trace entry describing how each grouping request was handled in this pass: whether the pass continued a cached grouping session and whether the session was kept for later passes, and per grouping its levels, hit count, and the number of groups returned per level vs. held by the session before pruning. Details are collected by GroupingSession::continueExecution only when requested, so there is no cost when tracing is off. Continued passes (served from a cached session) previously produced no content node trace at all. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
At trace level 6, record where grouping time is spent so that it can be attributed separately from matching and sorting: - Each match thread traces "grouping_timing" with the time spent aggregating hits into its groupings (sorting excluded). - The "grouping" entry gets the total time spent merging grouping results across threads and pruning the merged result (multi-threaded only), and the time spent producing the result for the pass (continue_ms), also for passes served from a cached session. - Each grouping in the "grouping" entry gets the time spent producing its result in the pass. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Address review feedback on the grouping trace: - Always emit top_n (-1 for no limit) like max_groups and precision, and document the convention: request limits are always present, fields that only apply to results produced from the session (session_done, time_ms, session_groups) are left out when from_session is false. - Rename hits to summary_hits and document that it counts hits from hits aggregations in the returned result, not documents grouped. - Document when from_session is false and what session_groups counts (the session's full result before this pass pruned it). - Add serialize_ms (via the new GroupingPassTrace) and merge_count, and narrow per grouping time_ms to pruning and merging only. - Only read the clock when grouping details are collected, and explain why accumulating merge time across threads is not a data race. - Test from_session false, summary_hits on a matched pass, merge_count, and that continue_ms covers the per grouping times and serialization. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Grouping on content nodes was hardly visible in the query trace. Nothing specific to grouping was traced, and passes served from a cached grouping session produced no content node trace at all. This adds grouping details and timing to the trace at level 6, which is what
trace.explainLevel=1/vespa query --profilegives on the content nodes. The field names are fixed so thatvespa inspect profilecan use them later. The tracedoctor is not changed in this PR.What is traced
A
groupingentry for each pass, from both the first pass (ResultProcessor::makeReply) and continued passes (handleGroupingSession):{ "tag": "grouping", "continued_session": false, "session_cached": true, "continue_ms": 0.31, "serialize_ms": 0.04, "merge_ms": 0.42, "merge_count": 3, "prune_ms": 0.05, "groupings": [ { "id": 0, "first_level": 0, "last_level": 0, "top_n": -1, "summary_hits": 3, "from_session": true, "session_done": false, "time_ms": 0.12, "levels": [ { "max_groups": 10, "precision": 30, "groups": 27, "session_groups": 27 }, { "max_groups": -1, "precision": -1, "groups": 0, "session_groups": 412 } ] } ] }Pass level:
continued_session: the pass was served from a cached grouping session, without matching.session_cached: the session was kept for later passes.continue_ms: time spent producing the result for the pass. This includes the per-groupingtime_msandserialize_ms(time spent serializing the result).merge_ms,merge_count,prune_ms(first pass only, and only when more than one thread was used): time spent in and number of merges of grouping results across threads, and time spent pruning the merged result.merge_msis a sum over merges that may have run in parallel, not wall clock time.Per grouping:
top_n,max_groups,precisionare request limits. They are always present and use -1 for no limit.summary_hits: number of document hits from hits aggregations (e.g.each(output(summary()))) in the returned result. It is not the number of documents that were grouped.from_session: the result was produced from the full result kept by the grouping session. This is true on every pass of a grouping that needs more than one pass, including the first. It is false when the grouping completed in a single pass (all levels requested at once, or no session id), in which case hits were aggregated directly into the request. When it is false,session_done,time_msandsession_groupsare left out.groupsis the number of groups returned in this pass.session_groupsis the number of groups in the session's full result at the start of the pass, before this pass pruned it to the groups the container asked for. That pruning shows up in the next pass'ssession_groups.time_ms: time spent pruning the session's full result and merging it into the request for this grouping.Each match thread's trace also gets a
grouping_timingentry withaggregate_ms: the time the thread spent aggregating hits into its groupings, with sorting excluded.Implementation
searchcore/grouping/grouping_pass_details.{h,cpp}holdsGroupingPassDetails(per grouping) andGroupingPassTrace(per pass), the group counting, and the slime rendering. The field conventions are documented in the header.GroupingSession::continueExecutiontakes an optionalGroupingPassTrace*. When it is null, nothing is counted and the clock is not read.Testing
grouping_test: a three-pass session checks the counts in each pass (including the session's result shrinking after pruning) and the rendered JSON. A test without a session id checksfrom_sessionfalse and that the session-only fields are left out.matching_test: checks the real trace for a first pass that caches the session (summary_hits3 out of 9 matched documents), a continued pass served from it, no output at trace level 5, and a 4-thread pass (merge_count3,from_sessionfalse). It also checks thatcontinue_mscovers the per-grouping times plusserialize_ms.Both suites pass (14 and 69 tests), and
searchcore_protonbuilds without warnings.I confirm that this contribution is made under the terms of the license found in the root directory of this repository's source tree and that I have the authority necessary to make this contribution on behalf of its copyright owner.
🤖 Generated with Claude Code