Further optimize performance and CPU usage

- Optimize by avoiding cloning the whole app in each iteration of the main
loop.
- Increase the input poll timeout from 1 to 200. This works because the
poll will not apply to key hold.
- Do not read input pipe if it hasn't been modified.
pull/135/head
Arijit Basu 3 years ago committed by Arijit Basu
parent e7ec27e359
commit c8dba61d4b

@ -14,7 +14,8 @@ pub fn keep_reading(tx_msg_in: Sender<Task>, rx_event_reader: Receiver<bool>) {
is_paused = paused;
};
if !is_paused && event::poll(std::time::Duration::from_millis(1)).unwrap_or_default() {
if !is_paused && event::poll(std::time::Duration::from_millis(200)).unwrap_or_default()
{
match event::read() {
Ok(Event::Key(key)) => {
let key = Key::from_event(key);

@ -1,13 +1,22 @@
use crate::app::{ExternalMsg, MsgIn, Task};
use std::fs;
use std::io::prelude::*;
use std::path::PathBuf;
use std::sync::mpsc::Sender;
use std::thread;
use std::time::Duration;
pub fn keep_reading(pipe: String, tx: Sender<Task>) {
let mut last_modified = None;
thread::spawn(move || loop {
if let Ok(mut file) = fs::OpenOptions::new()
let modified = PathBuf::from(&pipe)
.metadata()
.and_then(|m| m.modified())
.ok();
if modified == last_modified {
thread::sleep(Duration::from_millis(50));
} else if let Ok(mut file) = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
@ -35,9 +44,7 @@ pub fn keep_reading(pipe: String, tx: Sender<Task>) {
.unwrap_or_default();
}
});
} else {
thread::sleep(Duration::from_millis(50));
}
};
} else {
tx.send(Task::new(
MsgIn::External(ExternalMsg::LogError(format!(
@ -49,5 +56,7 @@ pub fn keep_reading(pipe: String, tx: Sender<Task>) {
.unwrap_or_default();
thread::sleep(Duration::from_secs(3));
}
last_modified = modified;
});
}

@ -96,6 +96,7 @@ pub fn run(mut app: app::App, focused_path: Option<String>) -> Result<Option<Str
)?;
let mut result = Ok(None);
let session_path = app.session_path().to_owned();
term::enable_raw_mode()?;
let mut stdout = get_tty()?;
@ -113,146 +114,142 @@ pub fn run(mut app: app::App, focused_path: Option<String>) -> Result<Option<Str
pwd_watcher::keep_watching(app.pwd(), tx_msg_in.clone(), rx_pwd_watcher)?;
'outer: for task in rx_msg_in {
let last_app = app.clone();
let (new_app, new_result) = match app.handle_task(task) {
Ok(a) => (a, Ok(None)),
Err(err) => (last_app.clone(), Err(err)),
};
app = new_app;
result = new_result;
if result.is_err() {
break;
}
while let Some(msg) = app.pop_msg_out() {
match msg {
// NOTE: Do not schedule critical tasks via tx_msg_in in this loop.
// Try handling them immediately.
app::MsgOut::Enque(task) => {
tx_msg_in.send(task)?;
}
match app.handle_task(task) {
Ok(a) => {
app = a;
while let Some(msg) = app.pop_msg_out() {
match msg {
// NOTE: Do not schedule critical tasks via tx_msg_in in this loop.
// Try handling them immediately.
app::MsgOut::Enque(task) => {
tx_msg_in.send(task)?;
}
app::MsgOut::Quit => {
result = Ok(None);
break 'outer;
}
app::MsgOut::Quit => {
result = Ok(None);
break 'outer;
}
app::MsgOut::PrintResultAndQuit => {
result = Ok(Some(app.result_str()));
break 'outer;
}
app::MsgOut::PrintResultAndQuit => {
result = Ok(Some(app.result_str()));
break 'outer;
}
app::MsgOut::PrintAppStateAndQuit => {
let out = serde_yaml::to_string(&app)?;
result = Ok(Some(out));
break 'outer;
}
app::MsgOut::PrintAppStateAndQuit => {
let out = serde_yaml::to_string(&app)?;
result = Ok(Some(out));
break 'outer;
}
app::MsgOut::Debug(path) => {
fs::write(&path, serde_yaml::to_string(&app)?)?;
}
app::MsgOut::Debug(path) => {
fs::write(&path, serde_yaml::to_string(&app)?)?;
}
app::MsgOut::ClearScreen => {
terminal.clear()?;
}
app::MsgOut::ClearScreen => {
terminal.clear()?;
}
app::MsgOut::ExplorePwd => {
match explorer::explore_sync(
app.explorer_config().clone(),
app.pwd().clone(),
app.focused_node().map(|n| n.relative_path().clone()),
) {
Ok(buf) => {
let pwd = buf.parent().clone();
app = app.add_directory(pwd.clone(), buf)?;
app::MsgOut::ExplorePwd => {
match explorer::explore_sync(
app.explorer_config().clone(),
app.pwd().clone(),
app.focused_node().map(|n| n.relative_path().clone()),
) {
Ok(buf) => {
let pwd = buf.parent().clone();
app = app.add_directory(pwd.clone(), buf)?;
}
Err(e) => {
app = app.log_error(e.to_string())?;
}
};
tx_pwd_watcher.send(app.pwd().clone())?;
}
Err(e) => {
app = app.log_error(e.to_string())?;
app::MsgOut::ExplorePwdAsync => {
explorer::explore_async(
app.explorer_config().clone(),
app.pwd().clone(),
app.focused_node().map(|n| n.relative_path().clone()),
tx_msg_in.clone(),
);
tx_pwd_watcher.send(app.pwd().clone())?;
}
};
tx_pwd_watcher.send(app.pwd().clone())?;
}
app::MsgOut::ExplorePwdAsync => {
explorer::explore_async(
app.explorer_config().clone(),
app.pwd().clone(),
app.focused_node().map(|n| n.relative_path().clone()),
tx_msg_in.clone(),
);
tx_pwd_watcher.send(app.pwd().clone())?;
}
app::MsgOut::ExploreParentsAsync => {
explorer::explore_recursive_async(
app.explorer_config().clone(),
app.pwd().clone(),
app.focused_node().map(|n| n.relative_path().clone()),
tx_msg_in.clone(),
);
tx_pwd_watcher.send(app.pwd().clone())?;
}
app::MsgOut::ExploreParentsAsync => {
explorer::explore_recursive_async(
app.explorer_config().clone(),
app.pwd().clone(),
app.focused_node().map(|n| n.relative_path().clone()),
tx_msg_in.clone(),
);
tx_pwd_watcher.send(app.pwd().clone())?;
}
app::MsgOut::Refresh => {
// $PWD watcher
tx_pwd_watcher.send(app.pwd().clone())?;
// UI
terminal.draw(|f| ui::draw(f, &app, &hb))?;
}
app::MsgOut::Refresh => {
// $PWD watcher
tx_pwd_watcher.send(app.pwd().clone())?;
// UI
terminal.draw(|f| ui::draw(f, &app, &hb))?;
}
app::MsgOut::CallSilently(cmd) => {
tx_event_reader.send(true)?;
app.write_pipes()?;
let status = call(&app, cmd, false)
.map(|s| {
if s.success() {
Ok(())
} else {
Err(format!("process exited with code {}", &s))
}
})
.unwrap_or_else(|e| Err(e.to_string()));
if let Err(e) = status {
app = app.log_error(e.to_string())?;
};
tx_event_reader.send(false)?;
}
app::MsgOut::CallSilently(cmd) => {
tx_event_reader.send(true)?;
app.write_pipes()?;
let status = call(&app, cmd, false)
.map(|s| {
if s.success() {
Ok(())
} else {
Err(format!("process exited with code {}", &s))
}
})
.unwrap_or_else(|e| Err(e.to_string()));
if let Err(e) = status {
app = app.log_error(e.to_string())?;
app::MsgOut::Call(cmd) => {
tx_event_reader.send(true)?;
terminal.clear()?;
terminal.set_cursor(0, 0)?;
term::disable_raw_mode()?;
terminal.show_cursor()?;
app.write_pipes()?;
let status = call(&app, cmd, false)
.map(|s| {
if s.success() {
Ok(())
} else {
Err(format!("process exited with code {}", &s))
}
})
.unwrap_or_else(|e| Err(e.to_string()));
if let Err(e) = status {
app = app.log_error(e.to_string())?;
};
terminal.clear()?;
term::enable_raw_mode()?;
terminal.hide_cursor()?;
tx_event_reader.send(false)?;
}
};
tx_event_reader.send(false)?;
}
}
app::MsgOut::Call(cmd) => {
tx_event_reader.send(true)?;
terminal.clear()?;
terminal.set_cursor(0, 0)?;
term::disable_raw_mode()?;
terminal.show_cursor()?;
app.write_pipes()?;
let status = call(&app, cmd, false)
.map(|s| {
if s.success() {
Ok(())
} else {
Err(format!("process exited with code {}", &s))
}
})
.unwrap_or_else(|e| Err(e.to_string()));
if let Err(e) = status {
app = app.log_error(e.to_string())?;
};
terminal.clear()?;
term::enable_raw_mode()?;
terminal.hide_cursor()?;
tx_event_reader.send(false)?;
}
};
Err(e) => {
result = Err(e);
break;
}
}
}
@ -262,7 +259,7 @@ pub fn run(mut app: app::App, focused_path: Option<String>) -> Result<Option<Str
term::disable_raw_mode()?;
terminal.show_cursor()?;
fs::remove_dir_all(app.session_path())?;
fs::remove_dir_all(session_path)?;
result
}

Loading…
Cancel
Save