1
1
mirror of https://github.com/wez/wezterm.git synced 2024-09-20 11:17:15 +03:00

Reduce size of Action

Action is used to encode parsed terminal output and shuttle it between
the thread that does the parsing and the main gui thread that applies
it to the terminal model.

Take it down from 184 bytes to 40 bytes (on 64-bit systems).  This seems
to boost `time cat bigfile` by reducing the runtime to ~40% of its prior
duration: down from 8s -> 4.5s on an M1 macbook air.

Size reductions achieved by Box'ing relatively less frequently
used enum variants. The kitty image data variant is particularly
large, and the Window variant is also pretty heavy.
This commit is contained in:
Wez Furlong 2022-09-09 21:02:01 -07:00
parent 7a0461989e
commit ef14f78e08
5 changed files with 41 additions and 28 deletions

View File

@ -1865,7 +1865,7 @@ impl TerminalState {
let height = Some(screen.physical_rows as i64); let height = Some(screen.physical_rows as i64);
let width = Some(screen.physical_cols as i64); let width = Some(screen.physical_cols as i64);
let response = Window::ResizeWindowCells { width, height }; let response = Box::new(Window::ResizeWindowCells { width, height });
write!(self.writer, "{}", CSI::Window(response)).ok(); write!(self.writer, "{}", CSI::Window(response)).ok();
self.writer.flush().ok(); self.writer.flush().ok();
} }
@ -1874,19 +1874,19 @@ impl TerminalState {
let screen = self.screen(); let screen = self.screen();
let height = screen.physical_rows; let height = screen.physical_rows;
let width = screen.physical_cols; let width = screen.physical_cols;
let response = Window::ReportCellSizePixelsResponse { let response = Box::new(Window::ReportCellSizePixelsResponse {
width: Some((self.pixel_width / width) as i64), width: Some((self.pixel_width / width) as i64),
height: Some((self.pixel_height / height) as i64), height: Some((self.pixel_height / height) as i64),
}; });
write!(self.writer, "{}", CSI::Window(response)).ok(); write!(self.writer, "{}", CSI::Window(response)).ok();
self.writer.flush().ok(); self.writer.flush().ok();
} }
Window::ReportTextAreaSizePixels => { Window::ReportTextAreaSizePixels => {
let response = Window::ResizeWindowPixels { let response = Box::new(Window::ResizeWindowPixels {
width: Some(self.pixel_width as i64), width: Some(self.pixel_width as i64),
height: Some(self.pixel_height as i64), height: Some(self.pixel_height as i64),
}; });
write!(self.writer, "{}", CSI::Window(response)).ok(); write!(self.writer, "{}", CSI::Window(response)).ok();
self.writer.flush().ok(); self.writer.flush().ok();
} }

View File

@ -234,7 +234,7 @@ impl<'a> Performer<'a> {
Action::XtGetTcap(names) => self.xt_get_tcap(names), Action::XtGetTcap(names) => self.xt_get_tcap(names),
Action::KittyImage(img) => { Action::KittyImage(img) => {
self.flush_print(); self.flush_print();
if let Err(err) = self.kitty_img(img) { if let Err(err) = self.kitty_img(*img) {
log::error!("kitty_img: {:#}", err); log::error!("kitty_img: {:#}", err);
} }
} }
@ -446,7 +446,7 @@ impl<'a> Performer<'a> {
CSI::Mode(mode) => self.state.perform_csi_mode(mode), CSI::Mode(mode) => self.state.perform_csi_mode(mode),
CSI::Device(dev) => self.state.perform_device(*dev), CSI::Device(dev) => self.state.perform_device(*dev),
CSI::Mouse(mouse) => error!("mouse report sent by app? {:?}", mouse), CSI::Mouse(mouse) => error!("mouse report sent by app? {:?}", mouse),
CSI::Window(window) => self.state.perform_csi_window(window), CSI::Window(window) => self.state.perform_csi_window(*window),
CSI::SelectCharacterPath(CharacterPath::ImplementationDefault, _) => { CSI::SelectCharacterPath(CharacterPath::ImplementationDefault, _) => {
self.state.bidi_hint.take(); self.state.bidi_hint.take();
} }

View File

@ -26,7 +26,7 @@ pub enum CSI {
Mouse(MouseReport), Mouse(MouseReport),
Window(Window), Window(Box<Window>),
Keyboard(Keyboard), Keyboard(Keyboard),
@ -39,6 +39,19 @@ pub enum CSI {
Unspecified(Box<Unspecified>), Unspecified(Box<Unspecified>),
} }
#[cfg(all(test, target_pointer_width = "64"))]
#[test]
fn csi_size() {
assert_eq!(std::mem::size_of::<Sgr>(), 24);
assert_eq!(std::mem::size_of::<Cursor>(), 12);
assert_eq!(std::mem::size_of::<Edit>(), 8);
assert_eq!(std::mem::size_of::<Mode>(), 24);
assert_eq!(std::mem::size_of::<MouseReport>(), 8);
assert_eq!(std::mem::size_of::<Window>(), 40);
assert_eq!(std::mem::size_of::<Keyboard>(), 8);
assert_eq!(std::mem::size_of::<CSI>(), 32);
}
bitflags::bitflags! { bitflags::bitflags! {
pub struct KittyKeyboardFlags: u16 { pub struct KittyKeyboardFlags: u16 {
const NONE = 0; const NONE = 0;
@ -1830,7 +1843,7 @@ impl<'a> CSIParser<'a> {
'n' => self.dsr(params), 'n' => self.dsr(params),
'r' => self.decstbm(params), 'r' => self.decstbm(params),
's' => self.decslrm(params), 's' => self.decslrm(params),
't' => self.window(params).map(CSI::Window), 't' => self.window(params).map(|p| CSI::Window(Box::new(p))),
'u' => noparams!(Cursor, RestoreCursor, params), 'u' => noparams!(Cursor, RestoreCursor, params),
'x' => self 'x' => self
.req_terminal_parameters(params) .req_terminal_parameters(params)
@ -1915,14 +1928,14 @@ impl<'a> CSIParser<'a> {
let left = OneBased::from_optional_esc_param(params.get(3))?; let left = OneBased::from_optional_esc_param(params.get(3))?;
let bottom = OneBased::from_optional_esc_param(params.get(4))?; let bottom = OneBased::from_optional_esc_param(params.get(4))?;
let right = OneBased::from_optional_esc_param(params.get(5))?; let right = OneBased::from_optional_esc_param(params.get(5))?;
Ok(CSI::Window(Window::ChecksumRectangularArea { Ok(CSI::Window(Box::new(Window::ChecksumRectangularArea {
request_id, request_id,
page_number, page_number,
top, top,
left, left,
bottom, bottom,
right, right,
})) })))
} }
fn dsr(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> { fn dsr(&mut self, params: &'a [CsiParam]) -> Result<CSI, ()> {
@ -2865,14 +2878,14 @@ mod test {
fn window() { fn window() {
assert_eq!( assert_eq!(
parse('t', &[6], "\x1b[6t"), parse('t', &[6], "\x1b[6t"),
vec![CSI::Window(Window::LowerWindow)] vec![CSI::Window(Box::new(Window::LowerWindow))]
); );
assert_eq!( assert_eq!(
parse('t', &[6, 15, 7], "\x1b[6;15;7t"), parse('t', &[6, 15, 7], "\x1b[6;15;7t"),
vec![CSI::Window(Window::ReportCellSizePixelsResponse { vec![CSI::Window(Box::new(Window::ReportCellSizePixelsResponse {
width: Some(7), width: Some(7),
height: Some(15) height: Some(15)
})] }))]
); );
} }

View File

@ -40,18 +40,18 @@ pub enum Action {
Esc(Esc), Esc(Esc),
Sixel(Box<Sixel>), Sixel(Box<Sixel>),
/// A list of termcap, terminfo names for which the application /// A list of termcap, terminfo names for which the application
/// whats information /// wants information
XtGetTcap(Vec<String>), XtGetTcap(Vec<String>),
KittyImage(KittyImage), KittyImage(Box<KittyImage>),
} }
#[cfg(all(test, target_pointer_width = "64"))] #[cfg(all(test, target_pointer_width = "64"))]
#[test] #[test]
fn action_size() { fn action_size() {
assert_eq!(std::mem::size_of::<Action>(), 184); assert_eq!(std::mem::size_of::<Action>(), 40);
assert_eq!(std::mem::size_of::<DeviceControlMode>(), 16); assert_eq!(std::mem::size_of::<DeviceControlMode>(), 16);
assert_eq!(std::mem::size_of::<ControlCode>(), 1); assert_eq!(std::mem::size_of::<ControlCode>(), 1);
assert_eq!(std::mem::size_of::<CSI>(), 48); assert_eq!(std::mem::size_of::<CSI>(), 32);
assert_eq!(std::mem::size_of::<Esc>(), 4); assert_eq!(std::mem::size_of::<Esc>(), 4);
} }

View File

@ -215,7 +215,7 @@ impl<'a, F: FnMut(Action)> VTActor for Performer<'a, F> {
fn apc_dispatch(&mut self, data: Vec<u8>) { fn apc_dispatch(&mut self, data: Vec<u8>) {
if let Some(img) = super::KittyImage::parse_apc(&data) { if let Some(img) = super::KittyImage::parse_apc(&data) {
(self.callback)(Action::KittyImage(img)) (self.callback)(Action::KittyImage(Box::new(img)))
} else { } else {
log::trace!("Ignoring APC data: {:?}", String::from_utf8_lossy(&data)); log::trace!("Ignoring APC data: {:?}", String::from_utf8_lossy(&data));
} }
@ -787,7 +787,7 @@ mod test {
fn window() { fn window() {
assert_eq!( assert_eq!(
round_trip_parse("\x1b[22;2t"), round_trip_parse("\x1b[22;2t"),
vec![Action::CSI(CSI::Window(Window::PushWindowTitle))] vec![Action::CSI(CSI::Window(Box::new(Window::PushWindowTitle)))]
); );
} }
@ -795,14 +795,14 @@ mod test {
fn checksum_area() { fn checksum_area() {
assert_eq!( assert_eq!(
round_trip_parse("\x1b[1;2;3;4;5;6*y"), round_trip_parse("\x1b[1;2;3;4;5;6*y"),
vec![Action::CSI(CSI::Window(Window::ChecksumRectangularArea { vec![Action::CSI(CSI::Window(Box::new(Window::ChecksumRectangularArea {
request_id: 1, request_id: 1,
page_number: 2, page_number: 2,
top: OneBased::new(3), top: OneBased::new(3),
left: OneBased::new(4), left: OneBased::new(4),
bottom: OneBased::new(5), bottom: OneBased::new(5),
right: OneBased::new(6), right: OneBased::new(6),
}))] })))]
); );
} }
@ -868,7 +868,7 @@ mod test {
assert_eq!( assert_eq!(
round_trip_parse("\x1b_Gf=24,s=10,v=20;aGVsbG8=\x1b\\"), round_trip_parse("\x1b_Gf=24,s=10,v=20;aGVsbG8=\x1b\\"),
vec![ vec![
Action::KittyImage(KittyImage::TransmitData { Action::KittyImage(Box::new(KittyImage::TransmitData {
transmit: KittyImageTransmit { transmit: KittyImageTransmit {
format: Some(KittyImageFormat::Rgb), format: Some(KittyImageFormat::Rgb),
data: KittyImageData::Direct("aGVsbG8=".to_string()), data: KittyImageData::Direct("aGVsbG8=".to_string()),
@ -880,7 +880,7 @@ mod test {
more_data_follows: false, more_data_follows: false,
}, },
verbosity: KittyImageVerbosity::Verbose, verbosity: KittyImageVerbosity::Verbose,
}), })),
Action::Esc(Esc::Code(EscCode::StringTerminator)), Action::Esc(Esc::Code(EscCode::StringTerminator)),
] ]
); );
@ -891,7 +891,7 @@ mod test {
"\x1b_Ga=q,i=1,s=1,v=1;YWJjZA==\x1b\\" "\x1b_Ga=q,i=1,s=1,v=1;YWJjZA==\x1b\\"
), ),
vec![ vec![
Action::KittyImage(KittyImage::Query { Action::KittyImage(Box::new(KittyImage::Query {
transmit: KittyImageTransmit { transmit: KittyImageTransmit {
format: None, format: None,
data: KittyImageData::Direct("YWJjZA==".to_string()), data: KittyImageData::Direct("YWJjZA==".to_string()),
@ -902,7 +902,7 @@ mod test {
compression: KittyImageCompression::None, compression: KittyImageCompression::None,
more_data_follows: false, more_data_follows: false,
}, },
}), })),
Action::Esc(Esc::Code(EscCode::StringTerminator)), Action::Esc(Esc::Code(EscCode::StringTerminator)),
] ]
); );
@ -912,7 +912,7 @@ mod test {
"\x1b_Ga=q,i=2,s=1,t=f,v=1;L3Zhci90bXAvdG1wdGYxd3E4Ym4=\x1b\\" "\x1b_Ga=q,i=2,s=1,t=f,v=1;L3Zhci90bXAvdG1wdGYxd3E4Ym4=\x1b\\"
), ),
vec![ vec![
Action::KittyImage(KittyImage::Query { Action::KittyImage(Box::new(KittyImage::Query {
transmit: KittyImageTransmit { transmit: KittyImageTransmit {
format: None, format: None,
data: KittyImageData::File { data: KittyImageData::File {
@ -927,7 +927,7 @@ mod test {
compression: KittyImageCompression::None, compression: KittyImageCompression::None,
more_data_follows: false, more_data_follows: false,
}, },
}), })),
Action::Esc(Esc::Code(EscCode::StringTerminator)), Action::Esc(Esc::Code(EscCode::StringTerminator)),
] ]
); );