mirror of
https://github.com/rust-lang/cargo
synced 2024-09-13 21:11:44 +00:00
Auto merge of #11800 - Byron:progress-bar-fixes, r=weihanglo
gitoxide progress bar fixes This PR makes the progress bar shown when fetching git repositories with `-Zgitoxide` feel more similar to the `git2` implementation. The main difference is that it separates the indexing and delta-resolution stage at 50%, instead of at ~33%. Furthermore it 'cools' the hot loop that was dealing with progress display, which previously used one whole core. Here is how it looks now: [![asciicast](https://asciinema.org/a/loJcLDNng0H9fSWkzDmA2u2e0.svg)](https://asciinema.org/a/loJcLDNng0H9fSWkzDmA2u2e0) ### Videos * how it looks with `git2` https://user-images.githubusercontent.com/63622/222902630-9cc5cd60-beff-4a70-a791-c264aec46e3b.mov * `gitoxide` before the fix: https://user-images.githubusercontent.com/63622/222902777-1272982c-8c35-4b41-8350-80ac0f2296de.mov * and `gitoxide` after the fix: https://user-images.githubusercontent.com/63622/222902878-9f35d9a9-9603-49d4-b751-e05884684d52.mov
This commit is contained in:
commit
e5e5d21ffd
|
@ -30,8 +30,8 @@ filetime = "0.2.9"
|
|||
flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] }
|
||||
git2 = "0.16.0"
|
||||
git2-curl = "0.17.0"
|
||||
gix = { version = "0.38.0", default-features = false, features = ["blocking-http-transport-curl", "progress-tree"] }
|
||||
gix-features-for-configuration-only = { version = "0.27.0", package = "gix-features", features = [ "parallel" ] }
|
||||
gix = { version = "0.39.0", default-features = false, features = ["blocking-http-transport-curl", "progress-tree"] }
|
||||
gix-features-for-configuration-only = { version = "0.28.0", package = "gix-features", features = [ "parallel" ] }
|
||||
glob = "0.3.0"
|
||||
hex = "0.4"
|
||||
hmac = "0.12.1"
|
||||
|
|
|
@ -69,18 +69,34 @@ fn translate_progress_to_bar(
|
|||
|
||||
// We choose `N=10` here to make a `300ms * 10slots ~= 3000ms`
|
||||
// sliding window for tracking the data transfer rate (in bytes/s).
|
||||
let mut last_update = Instant::now();
|
||||
let mut counter = MetricsCounter::<10>::new(0, last_update);
|
||||
let mut last_percentage_update = Instant::now();
|
||||
let mut last_fast_update = Instant::now();
|
||||
let mut counter = MetricsCounter::<10>::new(0, last_percentage_update);
|
||||
|
||||
let mut tasks = Vec::with_capacity(10);
|
||||
let update_interval = std::time::Duration::from_millis(300);
|
||||
let short_check_interval = Duration::from_millis(50);
|
||||
let slow_check_interval = std::time::Duration::from_millis(300);
|
||||
let fast_check_interval = Duration::from_millis(50);
|
||||
let sleep_interval = Duration::from_millis(10);
|
||||
debug_assert_eq!(
|
||||
slow_check_interval.as_millis() % fast_check_interval.as_millis(),
|
||||
0,
|
||||
"progress should be smoother by keeping these as multiples of each other"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
fast_check_interval.as_millis() % sleep_interval.as_millis(),
|
||||
0,
|
||||
"progress should be smoother by keeping these as multiples of each other"
|
||||
);
|
||||
|
||||
while let Some(root) = root.upgrade() {
|
||||
let not_yet = last_update.elapsed() < update_interval;
|
||||
if not_yet {
|
||||
std::thread::sleep(short_check_interval);
|
||||
std::thread::sleep(sleep_interval);
|
||||
let needs_update = last_fast_update.elapsed() >= fast_check_interval;
|
||||
if !needs_update {
|
||||
continue;
|
||||
}
|
||||
let now = Instant::now();
|
||||
last_fast_update = now;
|
||||
|
||||
root.sorted_snapshot(&mut tasks);
|
||||
|
||||
fn progress_by_id(
|
||||
|
@ -96,13 +112,14 @@ fn translate_progress_to_bar(
|
|||
tasks.iter().find_map(|(_, t)| cb(t))
|
||||
}
|
||||
|
||||
const NUM_PHASES: usize = 2; // indexing + delta-resolution, both with same amount of objects to handle
|
||||
if let Some(objs) = find_in(&tasks, |t| progress_by_id(resolve_objects, t)) {
|
||||
// Resolving deltas.
|
||||
let objects = objs.step.load(Ordering::Relaxed);
|
||||
let total_objects = objs.done_at.expect("known amount of objects");
|
||||
let msg = format!(", ({objects}/{total_objects}) resolving deltas");
|
||||
|
||||
progress_bar.tick(objects, total_objects, &msg)?;
|
||||
progress_bar.tick(total_objects + objects, total_objects * NUM_PHASES, &msg)?;
|
||||
} else if let Some((objs, read_pack)) =
|
||||
find_in(&tasks, |t| progress_by_id(read_pack_bytes, t)).and_then(|read| {
|
||||
find_in(&tasks, |t| progress_by_id(delta_index_objects, t))
|
||||
|
@ -114,15 +131,15 @@ fn translate_progress_to_bar(
|
|||
let total_objects = objs.done_at.expect("known amount of objects");
|
||||
let received_bytes = read_pack.step.load(Ordering::Relaxed);
|
||||
|
||||
let now = Instant::now();
|
||||
if !not_yet {
|
||||
let needs_percentage_update = last_percentage_update.elapsed() >= slow_check_interval;
|
||||
if needs_percentage_update {
|
||||
counter.add(received_bytes, now);
|
||||
last_update = now;
|
||||
last_percentage_update = now;
|
||||
}
|
||||
let (rate, unit) = human_readable_bytes(counter.rate() as u64);
|
||||
let msg = format!(", {rate:.2}{unit}/s");
|
||||
|
||||
progress_bar.tick(objects, total_objects, &msg)?;
|
||||
progress_bar.tick(objects, total_objects * NUM_PHASES, &msg)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue