From 0517f376be3054ab736006dcfc24b404dcd8626c Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Wed, 31 Aug 2016 21:16:17 -0700 Subject: [PATCH] Eliminate extra renders Currently has a bug where screen is blank at startup. That aside, Alacritty uses basically 0 CPU now. The input thread is still separate from the render thread, but, given the ability to wake the event loop, it may be possible to merge them again. I'm not sure if that's actually desirable. Performance is seemingly unchanged. --- Cargo.lock | 6 +-- Cargo.toml | 2 +- src/main.rs | 122 ++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 98 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c9f89f6..7b630691 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,7 +7,7 @@ dependencies = [ "errno 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "font 0.1.0", "gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "glutin 0.6.1 (git+https://github.com/jwilm/glutin?rev=45092a8e2f6706a7b2c613ff212341754e346c9c)", + "glutin 0.6.1 (git+https://github.com/jwilm/glutin?rev=16ed800f68022a37203434bd3b542ff5400c1403)", "libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "notify 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -285,7 +285,7 @@ dependencies = [ [[package]] name = "glutin" version = "0.6.1" -source = "git+https://github.com/jwilm/glutin?rev=45092a8e2f6706a7b2c613ff212341754e346c9c#45092a8e2f6706a7b2c613ff212341754e346c9c" +source = "git+https://github.com/jwilm/glutin?rev=16ed800f68022a37203434bd3b542ff5400c1403#16ed800f68022a37203434bd3b542ff5400c1403" dependencies = [ "android_glue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -906,7 +906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "65256ec4dc2592e6f05bfc1ca3b956a4e0698aa90b1dff1f5687d55a5a3fd59a" "checksum gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1d8edc81c5ae84605a62f5dac661a2313003b26d59839f81d47d46cf0f16a55" "checksum gleam 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "13a363b2a5264b600e530db2f14b3c487098e6dee0655f2810ea779385cbac5a" -"checksum glutin 0.6.1 (git+https://github.com/jwilm/glutin?rev=45092a8e2f6706a7b2c613ff212341754e346c9c)" = "" +"checksum glutin 0.6.1 (git+https://github.com/jwilm/glutin?rev=16ed800f68022a37203434bd3b542ff5400c1403)" = "" "checksum heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "abb306abb8d398e053cfb1b3e7b72c2f580be048b85745c52652954f8ad1439c" "checksum inotify 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8458c07bdbdaf309c80e2c3304d14c3db64e7465d4f07cf589ccb83fd0ff31a" "checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1" diff --git a/Cargo.toml b/Cargo.toml index d556a26c..9e8f8b81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ notify = "2.6" bitflags = "*" font = { path = "./font" } errno = "0.1.6" -parking_lot = "0.3.1" +parking_lot = { version = "0.3.1", features = ["nightly"] } serde = "0.8" serde_yaml = "0.4" serde_macros = "0.8" diff --git a/src/main.rs b/src/main.rs index 29201adf..5c1bca68 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,21 +52,45 @@ mod io; mod sync; use std::sync::{mpsc, Arc}; +use std::sync::atomic::{AtomicBool, Ordering}; -use sync::PriorityMutex; +use parking_lot::{Condvar, Mutex}; use config::Config; +use io::{Utf8Chars, Utf8CharsError}; use meter::Meter; use renderer::{QuadRenderer, GlyphCache}; +use sync::PriorityMutex; use term::Term; use tty::process_should_exit; use util::thread; -use io::{Utf8Chars, Utf8CharsError}; - /// Channel used by resize handling on mac static mut resize_sender: Option> = None; +struct Waiter { + mutex: Mutex, + cond: Condvar, +} + +impl Waiter { + pub fn new() -> Waiter { + Waiter { + mutex: Mutex::new(false), + cond: Condvar::new(), + } + } + + pub fn notify(&self) { + self.cond.notify_one(); + } + + pub fn wait(&self) { + let mut guard = self.mutex.lock(); + self.cond.wait(&mut guard); + } +} + /// Resize handling for Mac fn window_resize_handler(width: u32, height: u32) { unsafe { @@ -126,6 +150,9 @@ fn main() { let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr); + let waiter = Arc::new(Waiter::new()); + let dirty = Arc::new(AtomicBool::new(false)); + // Create renderer let mut renderer = QuadRenderer::new(width, height); @@ -163,7 +190,11 @@ fn main() { let terminal = Arc::new(PriorityMutex::new(terminal)); - let pty_reader_thread = spawn_pty_reader(terminal.clone(), reader); + let pty_reader_thread = spawn_pty_reader(terminal.clone(), + reader, + waiter.clone(), + dirty.clone(), + window.create_window_proxy()); let window = Arc::new(window); @@ -173,11 +204,15 @@ fn main() { renderer, glyph_cache, render_timer, - rx); + rx, + waiter.clone(), + dirty); handle_window_events(&mut writer, terminal, window); pty_reader_thread.join().ok(); + + waiter.notify(); render_thread.join().ok(); println!("Goodbye"); } @@ -219,12 +254,23 @@ fn handle_window_events(writer: &mut W, &mut input::WriteNotifier(writer), *terminal.mode()) }, + glutin::Event::Awakened => { + if process_should_exit() { + println!("input thread exitting"); + break; + } + } _ => (), } + } } -fn spawn_pty_reader(terminal: Arc>, mut pty: R) -> std::thread::JoinHandle<()> +fn spawn_pty_reader(terminal: Arc>, + mut pty: R, + waiter: Arc, + dirty: Arc, + proxy: ::glutin::WindowProxy) -> std::thread::JoinHandle<()> where R: std::io::Read + Send + 'static, { thread::spawn_named("pty reader", move || { @@ -233,40 +279,51 @@ fn spawn_pty_reader(terminal: Arc>, mut pty: R) -> std::t let mut pty_parser = ansi::Parser::new(); loop { - let got = pty.read(&mut buf[start..]).expect("pty fd active"); - let mut remain = 0; + if let Ok(got) = pty.read(&mut buf[start..]) { + let mut remain = 0; - // if `start` is nonzero, then actual bytes in buffer is > `got` by `start` bytes. - let end = start + got; - let mut terminal = terminal.lock_low(); - for c in Utf8Chars::new(&buf[..end]) { - match c { - Ok(c) => pty_parser.advance(&mut *terminal, c), - Err(err) => match err { - Utf8CharsError::IncompleteUtf8(unused) => { - remain = unused; - break; - }, - _ => panic!("{}", err), + // if `start` is nonzero, then actual bytes in buffer is > `got` by `start` bytes. + let end = start + got; + { + let mut terminal = terminal.lock_low(); + for c in Utf8Chars::new(&buf[..end]) { + match c { + Ok(c) => pty_parser.advance(&mut *terminal, c), + Err(err) => match err { + Utf8CharsError::IncompleteUtf8(unused) => { + remain = unused; + break; + }, + _ => panic!("{}", err), + } + } } } - } - // Move any leftover bytes to front of buffer - for i in 0..remain { - buf[i] = buf[end - (remain - i)]; + dirty.store(true, Ordering::Release); + waiter.notify(); + + // Move any leftover bytes to front of buffer + for i in 0..remain { + buf[i] = buf[end - (remain - i)]; + } + start = remain; + } else { + proxy.wakeup_event_loop(); + break; } - start = remain; } }) } fn spawn_renderer(window: Arc, - terminal: Arc>, + terminal_mutex: Arc>, mut renderer: QuadRenderer, mut glyph_cache: GlyphCache, render_timer: bool, - rx: mpsc::Receiver<(u32, u32)>) -> std::thread::JoinHandle<()> { + rx: mpsc::Receiver<(u32, u32)>, + waiter: Arc, + dirty: Arc) -> std::thread::JoinHandle<()> { thread::spawn_named("render", move || { unsafe { let _ = window.make_current(); @@ -277,7 +334,15 @@ fn spawn_renderer(window: Arc, // Scope ensures terminal lock isn't held when calling swap_buffers { // Acquire term lock - let mut terminal = terminal.lock_high(); + let mut terminal = terminal_mutex.lock_high(); + + if !dirty.load(Ordering::Acquire) { + drop(terminal); + waiter.wait(); + terminal = terminal_mutex.lock_high(); + } + + dirty.store(false, Ordering::Release); // Resize events new_size and are handled outside the poll_events // iterator. This has the effect of coalescing multiple resize @@ -328,6 +393,7 @@ fn spawn_renderer(window: Arc, if process_should_exit() { break; + } else { } } })