diff options
author | Christian Duerr <contact@christianduerr.com> | 2021-07-08 20:35:58 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-08 20:35:58 +0000 |
commit | 8cb1acc27d863942401df80c3acb8b4016ad6083 (patch) | |
tree | 5772b74e40235ef4e9367d33014646a36666e320 /alacritty_terminal | |
parent | 4a3bcdb49d2027d4cbf6a2f147b07da38a4b0238 (diff) | |
download | alacritty-8cb1acc27d863942401df80c3acb8b4016ad6083.tar.gz alacritty-8cb1acc27d863942401df80c3acb8b4016ad6083.zip |
Fix PTY performance regressions
The patch 9e7655e introduced some changes which improved rendering with
very dense grids, but the automatic benchmarks indicated a slight
performance difference in the `dense_cells` benchmark.
Caching the terminal lock between iterations rather than always calling
`try_lock` resolves that issue.
While breaking early in the `WouldBlock` case with `unprocessed != 0`
does also help resolve these issues, it shows some more significant
fluctuations. Combining both fixes does not help.
Additionally on Windows receiving `Ok(0)` from the PTY will also occur
instead of a `WouldBlock` error, so handling that fixes freezing on
Windows.
Fixes #5305.
Diffstat (limited to 'alacritty_terminal')
-rw-r--r-- | alacritty_terminal/src/event_loop.rs | 45 |
1 files changed, 40 insertions, 5 deletions
diff --git a/alacritty_terminal/src/event_loop.rs b/alacritty_terminal/src/event_loop.rs index 1a6ee8f3..b0676e4d 100644 --- a/alacritty_terminal/src/event_loop.rs +++ b/alacritty_terminal/src/event_loop.rs @@ -221,10 +221,13 @@ where // Reserve the next terminal lock for PTY reading. let _terminal_lease = Some(self.terminal.lease()); + let mut terminal = None; loop { // Read from the PTY. match self.pty.reader().read(&mut buf[unprocessed..]) { + // This is received on Windows/macOS when no more data is readable from the PTY. + Ok(0) if unprocessed == 0 => break, Ok(got) => unprocessed += got, Err(err) => match err.kind() { ErrorKind::Interrupted | ErrorKind::WouldBlock => { @@ -238,11 +241,14 @@ where } // Attempt to lock the terminal. - let mut terminal = match self.terminal.try_lock_unfair() { - // Force block if we are at the buffer size limit. - None if unprocessed >= READ_BUFFER_SIZE => self.terminal.lock_unfair(), - None => continue, + let terminal = match &mut terminal { Some(terminal) => terminal, + None => terminal.insert(match self.terminal.try_lock_unfair() { + // Force block if we are at the buffer size limit. + None if unprocessed >= READ_BUFFER_SIZE => self.terminal.lock_unfair(), + None => continue, + Some(terminal) => terminal, + }), }; // Write a copy of the bytes to the ref test file. @@ -252,7 +258,7 @@ where // Parse the incoming bytes. for byte in &buf[..unprocessed] { - state.parser.advance(&mut *terminal, *byte); + state.parser.advance(&mut **terminal, *byte); } processed += unprocessed; @@ -425,3 +431,32 @@ where }) } } + +trait OptionInsert { + type T; + fn insert(&mut self, value: Self::T) -> &mut Self::T; +} + +// TODO: Remove when MSRV is >= 1.53.0. +// +/// Trait implementation to support Rust version < 1.53.0. +/// +/// This is taken [from STD], further license information can be found in the [rust-lang/rust +/// repository]. +/// +/// +/// [from STD]: https://github.com/rust-lang/rust/blob/6e0b554619a3bb7e75b3334e97f191af20ef5d76/library/core/src/option.rs#L829-L858 +/// [rust-lang/rust repository]: https://github.com/rust-lang/rust/blob/master/LICENSE-MIT +impl<T> OptionInsert for Option<T> { + type T = T; + + fn insert(&mut self, value: T) -> &mut T { + *self = Some(value); + + match self { + Some(v) => v, + // SAFETY: the code above just filled the option + None => unsafe { std::hint::unreachable_unchecked() }, + } + } +} |