fix performance regression in revlog

This commit is contained in:
Stephan Dilly 2020-05-22 22:41:17 +02:00
parent df43ea03aa
commit 2497c4fe9e
3 changed files with 80 additions and 38 deletions

View file

@ -12,7 +12,7 @@ pub mod sync;
pub use crate::{ pub use crate::{
diff::{AsyncDiff, DiffParams}, diff::{AsyncDiff, DiffParams},
revlog::AsyncLog, revlog::{AsyncLog, FetchStatus},
status::{AsyncStatus, StatusParams}, status::{AsyncStatus, StatusParams},
sync::{ sync::{
diff::{DiffLine, DiffLineType, FileDiff}, diff::{DiffLine, DiffLineType, FileDiff},

View file

@ -13,16 +13,32 @@ use std::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
Arc, Mutex, Arc, Mutex,
}, },
thread,
time::Duration,
}; };
///
#[derive(PartialEq)]
pub enum FetchStatus {
/// previous fetch still running
Pending,
/// no change expected
NoChange,
/// new walk was started
Started,
}
/// ///
pub struct AsyncLog { pub struct AsyncLog {
current: Arc<Mutex<Vec<Oid>>>, current: Arc<Mutex<Vec<Oid>>>,
sender: Sender<AsyncNotification>, sender: Sender<AsyncNotification>,
pending: Arc<AtomicBool>, pending: Arc<AtomicBool>,
background: Arc<AtomicBool>,
} }
static LIMIT_COUNT: usize = 1000; static LIMIT_COUNT: usize = 3000;
static SLEEP_FOREGROUND: Duration = Duration::from_millis(2);
static SLEEP_BACKGROUND: Duration = Duration::from_millis(1000);
impl AsyncLog { impl AsyncLog {
/// ///
@ -31,6 +47,7 @@ impl AsyncLog {
current: Arc::new(Mutex::new(Vec::new())), current: Arc::new(Mutex::new(Vec::new())),
sender, sender,
pending: Arc::new(AtomicBool::new(false)), pending: Arc::new(AtomicBool::new(false)),
background: Arc::new(AtomicBool::new(false)),
} }
} }
@ -58,6 +75,11 @@ impl AsyncLog {
self.pending.load(Ordering::Relaxed) self.pending.load(Ordering::Relaxed)
} }
///
pub fn set_background(&mut self) {
self.background.store(true, Ordering::Relaxed)
}
/// ///
fn current_head(&self) -> Result<Oid> { fn current_head(&self) -> Result<Oid> {
Ok(self.current.lock()?.first().map_or(Oid::zero(), |f| *f)) Ok(self.current.lock()?.first().map_or(Oid::zero(), |f| *f))
@ -79,29 +101,44 @@ impl AsyncLog {
} }
/// ///
pub fn fetch(&mut self) -> Result<()> { pub fn fetch(&mut self) -> Result<FetchStatus> {
if !self.is_pending() && self.head_changed()? { self.background.store(false, Ordering::Relaxed);
self.clear()?;
let arc_current = Arc::clone(&self.current); if self.is_pending() {
let sender = self.sender.clone(); return Ok(FetchStatus::Pending);
let arc_pending = Arc::clone(&self.pending);
rayon_core::spawn(move || {
scope_time!("async::revlog");
arc_pending.store(true, Ordering::Relaxed);
AsyncLog::fetch_helper(arc_current, &sender)
.expect("failed to fetch");
arc_pending.store(false, Ordering::Relaxed);
Self::notify(&sender);
});
} }
Ok(())
if !self.head_changed()? {
return Ok(FetchStatus::NoChange);
}
self.clear()?;
let arc_current = Arc::clone(&self.current);
let sender = self.sender.clone();
let arc_pending = Arc::clone(&self.pending);
let arc_background = Arc::clone(&self.background);
rayon_core::spawn(move || {
scope_time!("async::revlog");
arc_pending.store(true, Ordering::Relaxed);
AsyncLog::fetch_helper(
arc_current,
arc_background,
&sender,
)
.expect("failed to fetch");
arc_pending.store(false, Ordering::Relaxed);
Self::notify(&sender);
});
Ok(FetchStatus::Started)
} }
fn fetch_helper( fn fetch_helper(
arc_current: Arc<Mutex<Vec<Oid>>>, arc_current: Arc<Mutex<Vec<Oid>>>,
arc_background: Arc<AtomicBool>,
sender: &Sender<AsyncNotification>, sender: &Sender<AsyncNotification>,
) -> Result<()> { ) -> Result<()> {
let mut entries = Vec::with_capacity(LIMIT_COUNT); let mut entries = Vec::with_capacity(LIMIT_COUNT);
@ -121,6 +158,14 @@ impl AsyncLog {
break; break;
} else { } else {
Self::notify(&sender); Self::notify(&sender);
let sleep_duration =
if arc_background.load(Ordering::Relaxed) {
SLEEP_BACKGROUND
} else {
SLEEP_FOREGROUND
};
thread::sleep(sleep_duration);
} }
} }

View file

@ -10,7 +10,7 @@ use crate::{
ui::calc_scroll_top, ui::calc_scroll_top,
ui::style::Theme, ui::style::Theme,
}; };
use asyncgit::{sync, AsyncLog, AsyncNotification, CWD}; use asyncgit::{sync, AsyncLog, AsyncNotification, CWD, FetchStatus};
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use crossterm::event::Event; use crossterm::event::Event;
use std::{borrow::Cow, cmp, convert::TryFrom, time::Instant}; use std::{borrow::Cow, cmp, convert::TryFrom, time::Instant};
@ -32,7 +32,6 @@ pub struct Revlog {
items: ItemBatch, items: ItemBatch,
git_log: AsyncLog, git_log: AsyncLog,
visible: bool, visible: bool,
first_open_done: bool,
scroll_state: (Instant, f32), scroll_state: (Instant, f32),
tags: Tags, tags: Tags,
current_size: (u16, u16), current_size: (u16, u16),
@ -52,7 +51,6 @@ impl Revlog {
selection: 0, selection: 0,
count_total: 0, count_total: 0,
visible: false, visible: false,
first_open_done: false,
scroll_state: (Instant::now(), 0_f32), scroll_state: (Instant::now(), 0_f32),
tags: Tags::new(), tags: Tags::new(),
current_size: (0, 0), current_size: (0, 0),
@ -73,20 +71,22 @@ impl Revlog {
/// ///
pub fn update(&mut self) { pub fn update(&mut self) {
if self.visible { if self.visible {
self.git_log.fetch().unwrap(); let log_changed =
} self.git_log.fetch().unwrap() == FetchStatus::Started;
let old_total = self.count_total; self.count_total = self.git_log.count().unwrap();
self.count_total = self.git_log.count().unwrap();
if self.items.needs_data(self.selection, self.selection_max()) if self
|| old_total != self.count_total .items
{ .needs_data(self.selection, self.selection_max())
self.fetch_commits(); || log_changed
} {
self.fetch_commits();
}
if self.tags.is_empty() { if self.tags.is_empty() {
self.tags = sync::get_tags(CWD).unwrap(); self.tags = sync::get_tags(CWD).unwrap();
}
} }
} }
@ -340,14 +340,11 @@ impl Component for Revlog {
fn hide(&mut self) { fn hide(&mut self) {
self.visible = false; self.visible = false;
self.git_log.set_background();
} }
fn show(&mut self) { fn show(&mut self) {
self.visible = true; self.visible = true;
self.git_log.fetch().unwrap();
if !self.first_open_done {
self.first_open_done = true;
self.git_log.fetch().unwrap();
}
} }
} }