Conversation
|
r? @madsmtm rustbot has assigned @madsmtm. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
r? @nnethercote Since you have already looked at #149849 I thought you could also take a look at this. |
break_query_cyclesbreak_query_cycles into a single function
|
cc @Zoxc |
This comment has been minimized.
This comment has been minimized.
| pub struct QueryWaiter<'tcx> { | ||
| pub query: Option<QueryJobId>, | ||
| pub condvar: Condvar, | ||
| pub span: Span, |
There was a problem hiding this comment.
The removal of spans here doesn't seem great.
There was a problem hiding this comment.
Leaving unused struct fields doesn't seem like a good long-term approach either. I can split its removal into a separate commit for a fast revert if necessary.
There was a problem hiding this comment.
I mean it should still be used. Each query call has an associated span and that should be propagated to the cycle error.
There was a problem hiding this comment.
But the span is currently unused, correct?
compiler/rustc_query_impl/src/job.rs
Outdated
| let mut root_query = None; | ||
| for (&query, info) in &query_map.map { | ||
| if info.job.parent.is_none() { | ||
| assert!(root_query.is_none(), "found multiple threads without start"); |
There was a problem hiding this comment.
There can be multiple roots if queries are called in parallel from outside a query.
There was a problem hiding this comment.
How would queries ever be called in parallel from outside a query? If I would relax this requirement I would also like to know the context.
There was a problem hiding this comment.
Say a program join(|| a(), || b()) where a() and b() are queries. It's trivial to do.
There was a problem hiding this comment.
Well, this is not what I've meant. But I see you are saying I shouldn't assume anything more than that.
Done in 2e0fbb9.
|
Under the assumption that #149849 doesn't land, what's the motivation for these changes? Code size? |
|
I don't know much about the cycle breaking / waiter / latch stuff, so I will need to spend some time reading closely over that code before I can do a sensible review here. @zetanumbers, can you explain in some more detail what this PR is doing and why? Feel free to assume I don't know anything and make your explanation as detailed as you like :) Thank you. |
Reduction of code complexity. We don't need 8 functions do to this after considering two theorems I've written down mid |
|
And I had draft of a code removing "rustc query cycle handler" thread from rust/compiler/rustc_query_impl/src/job.rs Lines 133 to 134 in d7a2352 |
|
I started looking over the existing @zetanumbers: you said this matches the current implementation. Is it exactly the same? You haven't given the expanded explanation I requested yet so I'm still guessing. As a newcomer to this code both the old code and the new code in this PR are very difficult to follow. |
| #[allow(rustc::potential_query_instability)] | ||
| fn find_cycle_in_graph<'tcx>( | ||
| query_map: &QueryJobMap<'tcx>, | ||
| ) -> (QueryJobId, usize, CycleError<QueryStackDeferred<'tcx>>) { |
There was a problem hiding this comment.
The function comment should explain the return type, especially the usize. Alternatively, you could introduce a new struct and use that instead of the tuple.
| .map | ||
| .iter() | ||
| .find(|(_, info)| info.job.parent.is_none()) | ||
| .expect("no root query was found"); |
There was a problem hiding this comment.
If you use values() instead of iter() you won't need to filter out the keys.
| id: QueryJobId, | ||
| span: Span, | ||
| /// Waiter index or `usize::MAX` if subquery was executed | ||
| waiter_idx: usize, |
There was a problem hiding this comment.
Can you change to Option<usize> instead of using MAX for the exceptional case?
|
|
||
| true | ||
| // Per statement above we should have wait at either of two occurrences of the duplicate query | ||
| let waiter_idx = if last.waiter_idx != usize::MAX { |
There was a problem hiding this comment.
If last.waiter_idx is an Option<usize> you can use unwrap_or_else here.
| for _ in 0..wakelist.len() { | ||
| rustc_thread_pool::mark_unblocked(registry); | ||
| } | ||
| // And so this `Vec::remove` shouldn't cause a panic |
There was a problem hiding this comment.
This comment reads strangely, like it's referring to an earlier comment.
| /// uses a query latch and then resuming that waiter. | ||
| /// There may be multiple cycles involved in a deadlock, so this searches | ||
| /// all active queries for cycles before finally resuming all the waiters at once. | ||
| pub fn break_query_cycles<'tcx>( |
There was a problem hiding this comment.
This function should have at least a short doc comment.
|
A few minor comments above but I think this generally looks good. I don't understand every detail but it's a lot shorter and easier to follow that the existing code. I would still appreciate it if you modified the PR description to include some more details about what this PR does, and why. |
|
Also, I guess the PR title should now say "two functions"? |
break_query_cycles into a single functionbreak_query_cycles
|
This PR seems highly questionable to me. My initial concerns suggest @zetanumbers does not fully understand the problem, so I question the correctness of the rest of the code too. We're trying to find cycles in the directed graph of active query jobs. The straightforward solution is a DFS search for cycles in that graph, which is what my code does. I have no clue what this PR is doing. |
I will write a detailed description later, but this is also a DFS search for cycles in that graph. |
This is
break_query_cyclesimplementation from #149849 (f466828) modified to be non-deterministic to match its current implementation and removeTreeNodeIndexplumbing code.I thought I could be a bit more brave with changes.