-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Make queries thread safe #49045
Make queries thread safe #49045
Conversation
1836db4
to
61b5c59
Compare
src/librustc/ty/maps/plumbing.rs
Outdated
let job = if let Some(job) = job { | ||
job | ||
} else { | ||
break lock; |
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 there a reason why this line is not just return Ok(lock);
? I think that would be clearer.
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, that would be better. The break
is there because this used to be part of another function.
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've fixed this.
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.
👍
37bb29d
to
31c0581
Compare
Ping from triage @michaelwoerister! The PR author pushed new commits, could you review them? |
I haven't forgotten about this, I'm just busy with bug fixing the last few days. |
Same here. I have some time scheduled for review later today, though I expect i'm largely going to defer to @michaelwoerister and/or @eddyb here since I don't have a ton of time right now. |
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.
Epic PR @Zoxc =)
I did a first read. I'm basically happy for now with the overall setup, which is what I expected. One obvious problem is that the code could use a lot more comments.
This is to some extent a pre-existing problem: the whole query setup is woefully underdocumented as is, but this is as good a time as any to fix that. In general, we should aim to make this stuff maximally readable.
(Once this has landed, I would like to iterate on some of the details, such as whether to use lazy or eager cycle detection, and the best way to handle blocking jobs -- but that can wait.)
src/librustc/ty/context.rs
Outdated
use rustc_data_structures::sync::Lrc; | ||
|
||
#[derive(Clone)] | ||
pub struct ImplicitCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { |
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.
Needs documentation. What is an ImplicitCtxt
?
src/librustc/ty/context.rs
Outdated
@@ -1484,11 +1486,25 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { | |||
|
|||
impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { | |||
/// Call the closure with a local `TyCtxt` using the given arena. | |||
pub fn enter_local<F, R>(&self, arena: &'tcx DroplessArena, f: F) -> R | |||
pub fn enter_local<F, R>(&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.
If we're going to reformat, let's adopt the modern style:
pub fn enter_local<F, R>(
&self,
arena: &'tcx DroplessArena,
f: F,
) -> R
where
F: ...
{
src/librustc/ty/context.rs
Outdated
}) | ||
} | ||
|
||
pub fn with_thread_locals<F, R>(f: F) -> R |
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.
Comment please. (I know... the original code isn't that documented either...c'est la vie)
src/librustc/ty/context.rs
Outdated
}) | ||
} | ||
|
||
pub fn enter_context<'a, 'gcx: 'tcx, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'gcx, 'tcx>, |
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.
Nit: as above, let's adopt the modern style
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.
Also, comment =)
One thing I am wondering about: why does this take an &ImplicitCtxt
versus creating one locally?
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.
Typically you'd get the current ImplicitCtxt
make a copy which changes a single field (queries modify the query
field only, creating an new interner would modify tcx
). Then you'd use enter_context
to use this new ImplicitCtxt
. We don't need to take ownership of the ImplicitCtxt
so we pass it by reference.
src/librustc/ty/context.rs
Outdated
} | ||
} | ||
|
||
pub fn with_fully_related_context<'a, 'gcx, 'tcx, F, R>(tcx: TyCtxt<'a, 'gcx, 'tcx>, f: F) -> R |
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.
Comment: what is a "fully related" context?
src/librustc/ty/maps/job.rs
Outdated
} | ||
|
||
impl<'tcx> QueryJob<'tcx> { | ||
pub fn new(entry: StackEntry<'tcx>, |
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 please run rustfmt on this file? <3
@@ -389,7 +393,7 @@ define_maps! { <'tcx> | |||
[] fn normalize_projection_ty: NormalizeProjectionTy( | |||
CanonicalProjectionGoal<'tcx> | |||
) -> Result< | |||
Lrc<Canonical<'tcx, QueryResult<'tcx, NormalizationResult<'tcx>>>>, | |||
Lrc<Canonical<'tcx, canonical::QueryResult<'tcx, NormalizationResult<'tcx>>>>, |
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.
Hmm. We should probably rename canonical::QueryResult
, but not in this PR.
src/librustc/ty/maps/plumbing.rs
Outdated
fn try_get_lock(tcx: TyCtxt<'a, $tcx, 'lcx>, | ||
mut span: Span, | ||
key: &$K) | ||
-> Result<LockGuard<'a, QueryMap<$tcx, 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.
Can we make a custom enum here? This type is sort of incomprehensible. Something with named variants seems better. Like:
enum TryGetLock {
NotYetStarted(Guard), // Today: Ok(guard)
JobCompleted(...), // Today: Err(Ok(...))
CycleDetected(...), // Today: Err(Err...))
}
I guess it means:
Ok(guard)
-- no job yet started, lock is still heldErr(Ok(...))
-- cache hit, or else we blocked on a job and it completedErr(Err(..))
-- cycle detected
src/librustc/ty/maps/plumbing.rs
Outdated
profq_msg!(tcx, ProfileQueriesMsg::CacheHit); | ||
tcx.dep_graph.read_index(value.index); | ||
return Ok((&value.value).clone()); | ||
macro_rules! get_lock { |
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.
why is this a macro and not a function?
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, because it returns I guess? Hmm. OK. Maybe we can rename it get_lock_or_return
or something.
// Also signal the completion of the job, so waiters | ||
// will continue execution | ||
job.signal_complete(); | ||
}); |
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.
Neat.
@bors try |
1 similar comment
@bors try |
⌛ Trying commit 31c0581aa0a405f94d031f8570ba2f2938ccf2d1 with merge c83390e645c0ae1d55d6f56636824a76fe084663... |
☀️ Test successful - status-travis |
@Mark-Simulacrum Can I get a perf run? |
Perf queued. |
…nt to their parents instead.
bc428e1
to
fa563bd
Compare
I've renamed |
Sorry for not getting to this yet, @Zoxc. Either we'll take a look at this together during the work week or I'll do an in-depth review on Tuesday after Easter. |
OK, I finally had time to review this. The comments you added since the initial version make things a lot clearer, thanks, @Zoxc! I think we can go ahead an merge this. The basic strategy seems sound to me and a good starting point. @nikomatsakis, are you satisfied with the comments added or do you want more? Otherwise, r=me. |
I'm going to go ahead and r+ this for now. We can always add more comments later. @bors r+ |
📌 Commit 4f7d0fd has been approved by |
Make queries thread safe This makes queries thread safe by removing the query stack and making queries point to their parents. Queries write to the query map when starting and cycles are detected by checking if there's already an entry in the query map. This makes cycle detection O(1) instead of O(n), where `n` is the size of the query stack. This is mostly corresponds to the method I described [here](https://internals.rust-lang.org/t/parallelizing-rustc-using-rayon/6606). cc @rust-lang/compiler r? @michaelwoerister
Make queries thread safe This makes queries thread safe by removing the query stack and making queries point to their parents. Queries write to the query map when starting and cycles are detected by checking if there's already an entry in the query map. This makes cycle detection O(1) instead of O(n), where `n` is the size of the query stack. This is mostly corresponds to the method I described [here](https://internals.rust-lang.org/t/parallelizing-rustc-using-rayon/6606). cc @rust-lang/compiler r? @michaelwoerister
☀️ Test successful - status-appveyor, status-travis |
🎉 |
This makes queries thread safe by removing the query stack and making queries point to their parents. Queries write to the query map when starting and cycles are detected by checking if there's already an entry in the query map. This makes cycle detection O(1) instead of O(n), where
n
is the size of the query stack.This is mostly corresponds to the method I described here.
cc @rust-lang/compiler
r? @michaelwoerister