Rename things related to the main thread's operations.
It took me some time to understand how the main thread can lend a jobserver token to an LLVM thread. This commit renames a couple of things to make it clearer. - Rename the `LLVMing` variant as `Lending`, because that is a clearer description of what is happening. - Rename `running` as `running_with_own_token`, which makes it clearer that there might be one additional LLVM thread running (with a loaned token). Also add a comment to its definition.
This commit is contained in:
parent
fd017d3c17
commit
5bef04ed38
1 changed files with 46 additions and 30 deletions
|
@ -998,9 +998,14 @@ struct Diagnostic {
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Copy, Debug)]
|
#[derive(PartialEq, Clone, Copy, Debug)]
|
||||||
enum MainThreadWorkerState {
|
enum MainThreadWorkerState {
|
||||||
|
/// Doing nothing.
|
||||||
Idle,
|
Idle,
|
||||||
|
|
||||||
|
/// Doing codegen, i.e. MIR-to-LLVM-IR conversion.
|
||||||
Codegenning,
|
Codegenning,
|
||||||
LLVMing,
|
|
||||||
|
/// Idle, but lending the compiler process's Token to an LLVM thread so it can do useful work.
|
||||||
|
Lending,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_executing_work<B: ExtraBackendMethods>(
|
fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
|
@ -1296,7 +1301,13 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
|
|
||||||
let mut main_thread_worker_state = MainThreadWorkerState::Idle;
|
let mut main_thread_worker_state = MainThreadWorkerState::Idle;
|
||||||
let mut running = 0;
|
|
||||||
|
// How many LLVM worker threads are running while holding a Token. This
|
||||||
|
// *excludes* the LLVM worker thread that the main thread is lending a
|
||||||
|
// Token to (when the main thread is in the `Lending` state).
|
||||||
|
// In other words, the number of LLVM threads is actually equal to
|
||||||
|
// `running + if main_thread_worker_state == Lending { 1 } else { 0 }`.
|
||||||
|
let mut running_with_own_token = 0;
|
||||||
|
|
||||||
let prof = &cgcx.prof;
|
let prof = &cgcx.prof;
|
||||||
let mut llvm_start_time: Option<VerboseTimingGuard<'_>> = None;
|
let mut llvm_start_time: Option<VerboseTimingGuard<'_>> = None;
|
||||||
|
@ -1307,8 +1318,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
// only apply if codegen hasn't been aborted as they represent pending
|
// only apply if codegen hasn't been aborted as they represent pending
|
||||||
// work to be done.
|
// work to be done.
|
||||||
while codegen_state == Ongoing
|
while codegen_state == Ongoing
|
||||||
|| running > 0
|
|| running_with_own_token > 0
|
||||||
|| main_thread_worker_state == MainThreadWorkerState::LLVMing
|
|| main_thread_worker_state == MainThreadWorkerState::Lending
|
||||||
|| (codegen_state == Completed
|
|| (codegen_state == Completed
|
||||||
&& !(work_items.is_empty()
|
&& !(work_items.is_empty()
|
||||||
&& needs_fat_lto.is_empty()
|
&& needs_fat_lto.is_empty()
|
||||||
|
@ -1323,13 +1334,14 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
if main_thread_worker_state == MainThreadWorkerState::Idle {
|
if main_thread_worker_state == MainThreadWorkerState::Idle {
|
||||||
// Compute the number of workers that will be running once we've taken as many
|
// Compute the number of workers that will be running once we've taken as many
|
||||||
// items from the work queue as we can, plus one for the main thread. It's not
|
// items from the work queue as we can, plus one for the main thread. It's not
|
||||||
// critically important that we use this instead of just `running`, but it
|
// critically important that we use this instead of just
|
||||||
// prevents the `queue_full_enough` heuristic from fluctuating just because a
|
// `running_with_own_token`, but it prevents the `queue_full_enough` heuristic
|
||||||
// worker finished up and we decreased the `running` count, even though we're
|
// from fluctuating just because a worker finished up and we decreased the
|
||||||
// just going to increase it right after this when we put a new worker to work.
|
// `running_with_own_token` count, even though we're just going to increase it
|
||||||
let extra_tokens = tokens.len().checked_sub(running).unwrap();
|
// right after this when we put a new worker to work.
|
||||||
|
let extra_tokens = tokens.len().checked_sub(running_with_own_token).unwrap();
|
||||||
let additional_running = std::cmp::min(extra_tokens, work_items.len());
|
let additional_running = std::cmp::min(extra_tokens, work_items.len());
|
||||||
let anticipated_running = running + additional_running + 1;
|
let anticipated_running = running_with_own_token + additional_running + 1;
|
||||||
|
|
||||||
if !queue_full_enough(work_items.len(), anticipated_running) {
|
if !queue_full_enough(work_items.len(), anticipated_running) {
|
||||||
// The queue is not full enough, process more codegen units:
|
// The queue is not full enough, process more codegen units:
|
||||||
|
@ -1352,7 +1364,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
cgcx.config(item.module_kind()),
|
cgcx.config(item.module_kind()),
|
||||||
&mut llvm_start_time,
|
&mut llvm_start_time,
|
||||||
);
|
);
|
||||||
main_thread_worker_state = MainThreadWorkerState::LLVMing;
|
main_thread_worker_state = MainThreadWorkerState::Lending;
|
||||||
spawn_work(cgcx, item);
|
spawn_work(cgcx, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1363,7 +1375,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
// going to LTO and then push a bunch of work items onto our
|
// going to LTO and then push a bunch of work items onto our
|
||||||
// queue to do LTO
|
// queue to do LTO
|
||||||
if work_items.is_empty()
|
if work_items.is_empty()
|
||||||
&& running == 0
|
&& running_with_own_token == 0
|
||||||
&& main_thread_worker_state == MainThreadWorkerState::Idle
|
&& main_thread_worker_state == MainThreadWorkerState::Idle
|
||||||
{
|
{
|
||||||
assert!(!started_lto);
|
assert!(!started_lto);
|
||||||
|
@ -1401,7 +1413,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
cgcx.config(item.module_kind()),
|
cgcx.config(item.module_kind()),
|
||||||
&mut llvm_start_time,
|
&mut llvm_start_time,
|
||||||
);
|
);
|
||||||
main_thread_worker_state = MainThreadWorkerState::LLVMing;
|
main_thread_worker_state = MainThreadWorkerState::Lending;
|
||||||
spawn_work(cgcx, item);
|
spawn_work(cgcx, item);
|
||||||
} else {
|
} else {
|
||||||
// There is no unstarted work, so let the main thread
|
// There is no unstarted work, so let the main thread
|
||||||
|
@ -1410,16 +1422,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
// We reduce the `running` counter by one. The
|
// We reduce the `running` counter by one. The
|
||||||
// `tokens.truncate()` below will take care of
|
// `tokens.truncate()` below will take care of
|
||||||
// giving the Token back.
|
// giving the Token back.
|
||||||
debug_assert!(running > 0);
|
debug_assert!(running_with_own_token > 0);
|
||||||
running -= 1;
|
running_with_own_token -= 1;
|
||||||
main_thread_worker_state = MainThreadWorkerState::LLVMing;
|
main_thread_worker_state = MainThreadWorkerState::Lending;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MainThreadWorkerState::Codegenning => bug!(
|
MainThreadWorkerState::Codegenning => bug!(
|
||||||
"codegen worker should not be codegenning after \
|
"codegen worker should not be codegenning after \
|
||||||
codegen was already completed"
|
codegen was already completed"
|
||||||
),
|
),
|
||||||
MainThreadWorkerState::LLVMing => {
|
MainThreadWorkerState::Lending => {
|
||||||
// Already making good use of that token
|
// Already making good use of that token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1431,7 +1443,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
|
|
||||||
// Spin up what work we can, only doing this while we've got available
|
// Spin up what work we can, only doing this while we've got available
|
||||||
// parallelism slots and work left to spawn.
|
// parallelism slots and work left to spawn.
|
||||||
while codegen_state != Aborted && !work_items.is_empty() && running < tokens.len() {
|
while codegen_state != Aborted
|
||||||
|
&& !work_items.is_empty()
|
||||||
|
&& running_with_own_token < tokens.len()
|
||||||
|
{
|
||||||
let (item, _) = work_items.pop().unwrap();
|
let (item, _) = work_items.pop().unwrap();
|
||||||
|
|
||||||
maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time);
|
maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time);
|
||||||
|
@ -1440,22 +1455,22 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
CodegenContext { worker: get_worker_id(&mut free_worker_ids), ..cgcx.clone() };
|
CodegenContext { worker: get_worker_id(&mut free_worker_ids), ..cgcx.clone() };
|
||||||
|
|
||||||
spawn_work(cgcx, item);
|
spawn_work(cgcx, item);
|
||||||
running += 1;
|
running_with_own_token += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relinquish accidentally acquired extra tokens
|
// Relinquish accidentally acquired extra tokens.
|
||||||
tokens.truncate(running);
|
tokens.truncate(running_with_own_token);
|
||||||
|
|
||||||
// If a thread exits successfully then we drop a token associated
|
// If a thread exits successfully then we drop a token associated
|
||||||
// with that worker and update our `running` count. We may later
|
// with that worker and update our `running_with_own_token` count.
|
||||||
// re-acquire a token to continue running more work. We may also not
|
// We may later re-acquire a token to continue running more work.
|
||||||
// actually drop a token here if the worker was running with an
|
// We may also not actually drop a token here if the worker was
|
||||||
// "ephemeral token"
|
// running with an "ephemeral token".
|
||||||
let mut free_worker = |worker_id| {
|
let mut free_worker = |worker_id| {
|
||||||
if main_thread_worker_state == MainThreadWorkerState::LLVMing {
|
if main_thread_worker_state == MainThreadWorkerState::Lending {
|
||||||
main_thread_worker_state = MainThreadWorkerState::Idle;
|
main_thread_worker_state = MainThreadWorkerState::Idle;
|
||||||
} else {
|
} else {
|
||||||
running -= 1;
|
running_with_own_token -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_worker_ids.push(worker_id);
|
free_worker_ids.push(worker_id);
|
||||||
|
@ -1471,13 +1486,13 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
Ok(token) => {
|
Ok(token) => {
|
||||||
tokens.push(token);
|
tokens.push(token);
|
||||||
|
|
||||||
if main_thread_worker_state == MainThreadWorkerState::LLVMing {
|
if main_thread_worker_state == MainThreadWorkerState::Lending {
|
||||||
// If the main thread token is used for LLVM work
|
// If the main thread token is used for LLVM work
|
||||||
// at the moment, we turn that thread into a regular
|
// at the moment, we turn that thread into a regular
|
||||||
// LLVM worker thread, so the main thread is free
|
// LLVM worker thread, so the main thread is free
|
||||||
// to react to codegen demand.
|
// to react to codegen demand.
|
||||||
main_thread_worker_state = MainThreadWorkerState::Idle;
|
main_thread_worker_state = MainThreadWorkerState::Idle;
|
||||||
running += 1;
|
running_with_own_token += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -1523,7 +1538,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||||
// to exit as soon as possible, but we want to make sure all
|
// to exit as soon as possible, but we want to make sure all
|
||||||
// existing work has finished. Flag codegen as being done, and
|
// existing work has finished. Flag codegen as being done, and
|
||||||
// then conditions above will ensure no more work is spawned but
|
// then conditions above will ensure no more work is spawned but
|
||||||
// we'll keep executing this loop until `running` hits 0.
|
// we'll keep executing this loop until `running_with_own_token`
|
||||||
|
// hits 0.
|
||||||
Message::CodegenAborted => {
|
Message::CodegenAborted => {
|
||||||
codegen_state = Aborted;
|
codegen_state = Aborted;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue