Skip to content

Commit

Permalink
Optimize parallel compile_objects: Sleep/yield if no progress is made
Browse files Browse the repository at this point in the history
Signed-off-by: Jiahao XU <[email protected]>
  • Loading branch information
NobodyXu committed Oct 22, 2023
1 parent 4132acd commit 70160b4
Showing 1 changed file with 41 additions and 3 deletions.
44 changes: 41 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,7 @@ impl Build {
crate::job_token::JobToken,
)>::new());
let is_disconnected = Cell::new(false);
let has_made_progress = Cell::new(false);

let mut wait_future = async {
let mut error = None;
Expand All @@ -1363,13 +1364,16 @@ impl Build {
match try_wait_on_child(cmd, program, &mut child.0, &mut stdout) {
Ok(Some(())) => {
// Task done, remove the entry
has_made_progress.set(true);
false
}
Ok(None) => true, // Task still not finished, keep the entry
Err(err) => {
// Task fail, remove the entry.
// Since we can only return one error, log the error to make
// sure users always see all the compilation failures.
has_made_progress.set(true);

let _ = writeln!(stdout, "cargo:warning={}", err);
error = Some(err);

Expand Down Expand Up @@ -1408,6 +1412,8 @@ impl Build {
pendings.push((cmd, program, KillOnDrop(child), token));
pendings
});

has_made_progress.set(true);
}
is_disconnected.set(true);

Expand All @@ -1424,7 +1430,11 @@ impl Build {
let waker = unsafe { Waker::from_raw(NOOP_RAW_WAKER) };
let mut context = Context::from_waker(&waker);

while wait_future.is_some() || spawn_future.is_some() {
let mut backoff_cnt = 0;

loop {
has_made_progress.set(false);

if let Some(fut) = spawn_future.as_mut() {
if let Poll::Ready(res) = fut.as_mut().poll(&mut context) {
spawn_future = None;
Expand All @@ -1438,9 +1448,37 @@ impl Build {
res?;
}
}
}

return Ok(());
if wait_future.is_none() && spawn_future.is_none() {
return Ok(());
}

if !has_made_progress.get() {
if backoff_cnt > 3 {
// We have yielded at least three times without making'
// any progress, so we will sleep for a while.
let duration =
std::time::Duration::from_millis(100 * (backoff_cnt - 3).min(10));
thread::sleep(duration);
} else {
// Given that we spawned a lot of compilation tasks, it is unlikely
// that OS cannot find other ready task to execute.
//
// If all of them are done, then we will yield them and spawn more,
// or simply returns.
//
// Thus this will not be turned into a busy-wait loop and it will not
// waste CPU resource.
thread::yield_now();
}
}

backoff_cnt = if has_made_progress.get() {
0
} else {
backoff_cnt + 1
};
}

struct KillOnDrop(Child);

Expand Down

0 comments on commit 70160b4

Please sign in to comment.