performance improvements

This commit is contained in:
Aram Drevekenin 2020-07-24 17:07:03 +02:00
parent 37f9d1ae4f
commit fe163f3831

View file

@ -1,8 +1,9 @@
use std::time::{Duration, Instant};
use std::{mem, io}; use std::{mem, io};
use ::std::fmt::{self, Display, Formatter}; use ::std::fmt::{self, Display, Formatter};
use std::cmp::max; use std::cmp::max;
use std::io::{stdin, stdout, Read, Write}; use std::io::{stdin, stdout, Read, Write};
use std::collections::{HashMap, HashSet, VecDeque}; use std::collections::{BTreeSet, HashMap, VecDeque};
use nix::unistd::{read, write, ForkResult}; use nix::unistd::{read, write, ForkResult};
use nix::fcntl::{fcntl, FcntlArg, OFlag}; use nix::fcntl::{fcntl, FcntlArg, OFlag};
use nix::sys::termios::SpecialCharacterIndices::{VMIN, VTIME}; use nix::sys::termios::SpecialCharacterIndices::{VMIN, VTIME};
@ -36,7 +37,8 @@ fn read_from_pid (pid: RawFd) -> Option<Vec<u8>> {
let read_result = read(pid, &mut read_buffer); let read_result = read(pid, &mut read_buffer);
match read_result { match read_result {
Ok(res) => { Ok(res) => {
Some(read_buffer[..=res].to_vec()) let res = Some(read_buffer[..=res].to_vec());
res
// (res, read_buffer) // (res, read_buffer)
}, },
Err(e) => { Err(e) => {
@ -184,9 +186,10 @@ struct TerminalOutput {
pub characters: Vec<char>, // we use a vec rather than a string here because one char can take up multiple characters in a string pub characters: Vec<char>, // we use a vec rather than a string here because one char can take up multiple characters in a string
pub display_rows: u16, pub display_rows: u16,
pub display_cols: u16, pub display_cols: u16,
pub should_render: bool,
cursor_position: usize, cursor_position: usize,
newline_indices: HashSet<usize>, // canonical line breaks we get from the vt interpreter newline_indices: BTreeSet<usize>, // canonical line breaks we get from the vt interpreter
linebreak_indices: HashSet<usize>, // linebreaks from line wrapping linebreak_indices: BTreeSet<usize>, // linebreaks from line wrapping
unhandled_ansi_codes: HashMap<usize, String>, unhandled_ansi_codes: HashMap<usize, String>,
pending_ansi_code: Option<String>, // this is used eg. in a carriage return, where we need to preserve the style pending_ansi_code: Option<String>, // this is used eg. in a carriage return, where we need to preserve the style
} }
@ -196,10 +199,11 @@ impl TerminalOutput {
TerminalOutput { TerminalOutput {
characters: vec![], characters: vec![],
cursor_position: 0, cursor_position: 0,
newline_indices: HashSet::new(), newline_indices: BTreeSet::new(),
linebreak_indices: HashSet::new(), linebreak_indices: BTreeSet::new(),
display_rows: 0, display_rows: 0,
display_cols: 0, display_cols: 0,
should_render: false,
unhandled_ansi_codes: HashMap::new(), unhandled_ansi_codes: HashMap::new(),
pending_ansi_code: None, pending_ansi_code: None,
} }
@ -207,10 +211,12 @@ impl TerminalOutput {
pub fn reduce_width(&mut self, count: u16) { pub fn reduce_width(&mut self, count: u16) {
self.display_cols -= count; self.display_cols -= count;
self.reflow_lines(); self.reflow_lines();
self.should_render = true;
} }
pub fn increase_width(&mut self, count: u16) { pub fn increase_width(&mut self, count: u16) {
self.display_cols += count; self.display_cols += count;
self.reflow_lines(); self.reflow_lines();
self.should_render = true;
} }
pub fn set_size(&mut self, ws: &Winsize) { pub fn set_size(&mut self, ws: &Winsize) {
let orig_cols = self.display_cols; let orig_cols = self.display_cols;
@ -269,6 +275,7 @@ impl TerminalOutput {
output.push_front(Vec::from(empty_line.clone())); output.push_front(Vec::from(empty_line.clone()));
} }
} }
self.should_render = false;
Vec::from(output) Vec::from(output)
} }
pub fn cursor_position_in_last_line (&self) -> usize { pub fn cursor_position_in_last_line (&self) -> usize {
@ -285,13 +292,17 @@ impl TerminalOutput {
None None
} else { } else {
// return last // return last
Some(self.newline_indices.iter().fold(0, |acc, i| if acc > *i { acc } else { *i })) // TODO: better? // None
Some(*self.newline_indices.iter().last().unwrap())
// Some(self.newline_indices.iter().fold(0, |acc, i| if acc > *i { acc } else { *i })) // TODO: better?
}; };
let last_linebreak_index = if self.linebreak_indices.is_empty() { let last_linebreak_index = if self.linebreak_indices.is_empty() {
None None
} else { } else {
// return last // return last
Some(self.linebreak_indices.iter().fold(0, |acc, i| if acc > *i { acc } else { *i })) // TODO: better? // None
Some(*self.linebreak_indices.iter().last().unwrap())
// Some(self.linebreak_indices.iter().fold(0, |acc, i| if acc > *i { acc } else { *i })) // TODO: better?
}; };
match (last_newline_index, last_linebreak_index) { match (last_newline_index, last_linebreak_index) {
(Some(last_newline_index), Some(last_linebreak_index)) => { (Some(last_newline_index), Some(last_linebreak_index)) => {
@ -307,13 +318,42 @@ impl TerminalOutput {
None None
} else { } else {
// return last less than index_in_line // return last less than index_in_line
Some(self.newline_indices.iter().fold(0, |acc, n_i| if *n_i > acc && *n_i <= index_in_line { *n_i } else { acc })) // TODO: better? // None
let last_newline_index = *self.newline_indices.iter().last().unwrap();
if last_newline_index <= index_in_line {
Some(last_newline_index)
} else {
let mut last_newline_index = 0;
for n_i in self.newline_indices.iter() {
if *n_i > last_newline_index && *n_i <= index_in_line {
last_newline_index = *n_i;
} else if *n_i > index_in_line {
break;
}
}
Some(last_newline_index)
}
// Some(self.newline_indices.iter().fold(0, |acc, n_i| if *n_i > acc && *n_i <= index_in_line { *n_i } else { acc })) // TODO: better?
}; };
let last_linebreak_index = if self.linebreak_indices.is_empty() { let last_linebreak_index = if self.linebreak_indices.is_empty() {
None None
} else { } else {
// return last less than index_in_line // return last less than index_in_line
Some(self.linebreak_indices.iter().fold(0, |acc, l_i| if *l_i > acc && *l_i <= index_in_line { *l_i } else { acc })) // TODO: better? // None
let last_linebreak_index = *self.linebreak_indices.iter().last().unwrap();
if last_linebreak_index <= index_in_line {
Some(last_linebreak_index)
} else {
let mut last_linebreak_index = 0;
for l_i in self.linebreak_indices.iter() {
if *l_i > last_linebreak_index && *l_i <= index_in_line {
last_linebreak_index = *l_i;
} else if *l_i > index_in_line {
break;
}
}
Some(last_linebreak_index)
}
}; };
match (last_newline_index, last_linebreak_index) { match (last_newline_index, last_linebreak_index) {
(Some(last_newline_index), Some(last_linebreak_index)) => { (Some(last_newline_index), Some(last_linebreak_index)) => {
@ -327,6 +367,7 @@ impl TerminalOutput {
fn add_newline (&mut self) { fn add_newline (&mut self) {
self.newline_indices.insert(self.characters.len()); // -1? self.newline_indices.insert(self.characters.len()); // -1?
self.cursor_position = self.characters.len(); // -1? self.cursor_position = self.characters.len(); // -1?
self.should_render = true;
} }
fn move_to_beginning_of_line (&mut self) { fn move_to_beginning_of_line (&mut self) {
let last_newline_index = if self.newline_indices.is_empty() { let last_newline_index = if self.newline_indices.is_empty() {
@ -335,6 +376,7 @@ impl TerminalOutput {
self.newline_indices.iter().fold(0, |acc, i| if acc > *i { acc } else { *i }) // TODO: better? self.newline_indices.iter().fold(0, |acc, i| if acc > *i { acc } else { *i }) // TODO: better?
}; };
self.cursor_position = last_newline_index; self.cursor_position = last_newline_index;
self.should_render = true;
} }
} }
@ -367,6 +409,7 @@ impl vte::Perform for TerminalOutput {
} }
self.cursor_position += 1; self.cursor_position += 1;
} }
// println!("\rDONE PRINT {:?}", now.elapsed().as_millis());
} }
fn execute(&mut self, byte: u8) { fn execute(&mut self, byte: u8) {
@ -590,7 +633,6 @@ impl Screen {
let mut last_character_was_changed = false; let mut last_character_was_changed = false;
for i in 0..last_frame.len() { for i in 0..last_frame.len() {
let current_character = frame.get(i).unwrap(); let current_character = frame.get(i).unwrap();
// TODO:
if !character_is_already_onscreen(&last_frame, &frame, i) { if !character_is_already_onscreen(&last_frame, &frame, i) {
let row = i / full_screen_ws.ws_col as usize + 1; let row = i / full_screen_ws.ws_col as usize + 1;
let col = i % full_screen_ws.ws_col as usize + 1; let col = i % full_screen_ws.ws_col as usize + 1;
@ -694,23 +736,29 @@ fn main() {
match (read_from_pid(first_terminal_pid), read_from_pid(second_terminal_pid)) { match (read_from_pid(first_terminal_pid), read_from_pid(second_terminal_pid)) {
(Some(first_terminal_read_bytes), Some(second_terminal_read_bytes)) => { (Some(first_terminal_read_bytes), Some(second_terminal_read_bytes)) => {
let mut terminal1_output = terminal1_output.lock().unwrap(); let mut terminal1_output = terminal1_output.lock().unwrap();
let mut terminal2_output = terminal2_output.lock().unwrap();
for byte in first_terminal_read_bytes.iter() { for byte in first_terminal_read_bytes.iter() {
vte_parser_terminal1.advance(&mut *terminal1_output, *byte); vte_parser_terminal1.advance(&mut *terminal1_output, *byte);
} }
let mut terminal2_output = terminal2_output.lock().unwrap();
for byte in second_terminal_read_bytes.iter() { for byte in second_terminal_read_bytes.iter() {
vte_parser_terminal2.advance(&mut *terminal2_output, *byte); vte_parser_terminal2.advance(&mut *terminal2_output, *byte);
} }
buffer_has_unread_data = true; buffer_has_unread_data = true;
} }
(Some(first_terminal_read_bytes), None) => { (Some(first_terminal_read_bytes), None) => {
let now = Instant::now();
let mut terminal1_output = terminal1_output.lock().unwrap(); let mut terminal1_output = terminal1_output.lock().unwrap();
let mut terminal2_output = terminal2_output.lock().unwrap(); // let mut terminal2_output = terminal2_output.lock().unwrap();
// println!("\rread bytes, parsing...");
let now = Instant::now();
for byte in first_terminal_read_bytes.iter() { for byte in first_terminal_read_bytes.iter() {
vte_parser_terminal1.advance(&mut *terminal1_output, *byte); vte_parser_terminal1.advance(&mut *terminal1_output, *byte);
} }
let active_terminal = active_terminal.lock().unwrap(); // println!("\rdone parsing bytes in {:?}", now.elapsed());
screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid); // println!("\rprint time: {:?}", terminal1_output.debug_print_time.as_millis());
buffer_has_unread_data = true;
// let active_terminal = active_terminal.lock().unwrap();
// screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid);
} }
(None, Some(second_terminal_read_bytes)) => { (None, Some(second_terminal_read_bytes)) => {
let mut terminal1_output = terminal1_output.lock().unwrap(); let mut terminal1_output = terminal1_output.lock().unwrap();
@ -718,20 +766,27 @@ fn main() {
for byte in second_terminal_read_bytes.iter() { for byte in second_terminal_read_bytes.iter() {
vte_parser_terminal2.advance(&mut *terminal2_output, *byte); vte_parser_terminal2.advance(&mut *terminal2_output, *byte);
} }
let active_terminal = active_terminal.lock().unwrap(); buffer_has_unread_data = true;
screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid); // let active_terminal = active_terminal.lock().unwrap();
// screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid);
} }
(None, None) => { (None, None) => {
let mut terminal1_output = terminal1_output.lock().unwrap(); // let mut terminal1_output = terminal1_output.lock().unwrap();
let mut terminal2_output = terminal2_output.lock().unwrap(); // let mut terminal2_output = terminal2_output.lock().unwrap();
if buffer_has_unread_data { // if buffer_has_unread_data {
let active_terminal = active_terminal.lock().unwrap(); // let active_terminal = active_terminal.lock().unwrap();
screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid); // screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid);
buffer_has_unread_data = false; // buffer_has_unread_data = false;
} // }
::std::thread::sleep(std::time::Duration::from_millis(50)); // TODO: adjust this ::std::thread::sleep(std::time::Duration::from_millis(50)); // TODO: adjust this
} }
} }
let mut terminal1_output = terminal1_output.lock().unwrap();
let mut terminal2_output = terminal2_output.lock().unwrap();
if terminal1_output.should_render || terminal2_output.should_render {
let active_terminal = active_terminal.lock().unwrap();
screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid);
}
} }
} }
}) })