[1 of 2] Optimize TUI startup terminal probes (#23175)

## Why

Codex TUI startup still feels slower than 0.117.0 after the app-server
move in 0.118.0. A visible chunk of launch-to-input latency comes from
serial terminal startup probes: cursor position, keyboard enhancement
support, and default foreground/background color queries can each wait
on terminal responses before the first usable frame.

Refs #16335.

## What

This PR batches the terminal startup probes into one bounded probe. It
also reuses the probed cursor position and default colors during TUI
setup, fast-paths the primary-device-attributes fallback as keyboard
enhancement unsupported, and keeps lightweight startup timing logs for
future tuning.

The startup telemetry is intentionally left in production: it records
phase timings for terminal probes and initial-frame scheduling so future
startup regressions can be diagnosed from normal logs rather than
re-adding one-off debug instrumentation.

## Benchmark

In the local pty startup benchmark, the pre-optimization `main` baseline
was about 250.5ms median from launch to accepted chat input. This
probe-only branch measured about 152ms median, for an approximate
savings of 95-100ms.

## Stack

1. [#23175: [1 of 2] Optimize TUI startup terminal
probes](https://github.com/openai/codex/pull/23175) — this PR
2. [#23176: [2 of 2] Start fresh TUI thread in
background](https://github.com/openai/codex/pull/23176) — layered on
this PR

## Verification

- `cargo test -p codex-tui`
This commit is contained in:
Eric Traut authored and GitHub committed 2026-05-18 09:04:02 -07:00
1 parent e734cb5713
commit adca1b643f
5 files changed
+254 -73

No files matched your search

+61 -23
View File
@@ -63,6 +63,11 @@ pub(crate) const TARGET_FRAME_INTERVAL: Duration = frame_rate_limiter::MIN_FRAME
/// A type alias for the terminal type used in this application
pub type Terminal = CustomTerminal<CrosstermBackend<Stdout>>;
pub(crate) struct InitializedTerminal {
pub(crate) terminal: Terminal,
pub(crate) enhanced_keys_supported: bool,
}
pub(crate) fn running_in_vscode_terminal() -> bool {
keyboard_modes::running_in_vscode_terminal()
}
@@ -334,7 +339,7 @@ fn flush_terminal_input_buffer() {
pub(crate) fn flush_terminal_input_buffer() {}
/// Initialize the terminal (inline viewport; history stays in normal scrollback)
pub fn init() -> Result<Terminal> {
pub(crate) fn init() -> Result<InitializedTerminal> {
if !stdin().is_terminal() {
return Err(std::io::Error::other("stdin is not a terminal"));
}
@@ -351,20 +356,57 @@ pub fn init() -> Result<Terminal> {
let backend = CrosstermBackend::new(stdout());
#[cfg(unix)]
let cursor_pos =
match crate::terminal_probe::cursor_position(crate::terminal_probe::DEFAULT_TIMEOUT) {
Ok(Some(pos)) => pos,
Ok(None) => {
tracing::warn!("initial cursor position probe timed out; defaulting to origin");
Position { x: 0, y: 0 }
let startup_probe = {
use crate::terminal_probe::StartupKeyboardEnhancementProbe;
let started_at = std::time::Instant::now();
let keyboard_probe = if keyboard_modes::keyboard_enhancement_disabled() {
StartupKeyboardEnhancementProbe::Skip
} else {
StartupKeyboardEnhancementProbe::Query
};
match crate::terminal_probe::startup(crate::terminal_probe::DEFAULT_TIMEOUT, keyboard_probe)
{
Ok(probe) => {
tracing::info!(
duration_ms = %started_at.elapsed().as_millis(),
cursor_position = probe.cursor_position.is_some(),
default_colors = probe.default_colors.is_some(),
keyboard_enhancement_supported = ?probe.keyboard_enhancement_supported,
"terminal startup probes completed"
);
probe
}
Err(err) => {
tracing::warn!(
"failed to read initial cursor position; defaulting to origin: {err}"
duration_ms = %started_at.elapsed().as_millis(),
"terminal startup probes failed: {err}"
);
Position { x: 0, y: 0 }
crate::terminal_probe::StartupProbe {
cursor_position: None,
default_colors: None,
keyboard_enhancement_supported: None,
}
}
};
}
};
#[cfg(unix)]
crate::terminal_palette::set_default_colors_from_startup_probe(startup_probe.default_colors);
#[cfg(unix)]
let cursor_pos = match startup_probe.cursor_position {
Some(pos) => pos,
None => {
tracing::warn!("initial cursor position probe timed out; defaulting to origin");
Position { x: 0, y: 0 }
}
};
#[cfg(unix)]
let enhanced_keys_supported = startup_probe
.keyboard_enhancement_supported
.unwrap_or(/*default*/ false);
#[cfg(not(unix))]
let mut backend = CrosstermBackend::new(stdout());
@@ -372,8 +414,15 @@ pub fn init() -> Result<Terminal> {
#[cfg(not(unix))]
let cursor_pos = cursor_position_with_crossterm(&mut backend);
#[cfg(not(unix))]
let enhanced_keys_supported =
!keyboard_modes::keyboard_enhancement_disabled() && detect_keyboard_enhancement_supported();
let tui = CustomTerminal::with_options_and_cursor_position(backend, cursor_pos)?;
Ok(tui)
Ok(InitializedTerminal {
terminal: tui,
enhanced_keys_supported,
})
}
#[cfg(not(unix))]
@@ -384,13 +433,6 @@ fn cursor_position_with_crossterm(backend: &mut CrosstermBackend<Stdout>) -> Pos
})
}
#[cfg(unix)]
fn detect_keyboard_enhancement_supported() -> bool {
crate::terminal_probe::keyboard_enhancement_supported(crate::terminal_probe::DEFAULT_TIMEOUT)
.unwrap_or(/*default*/ None)
.unwrap_or(/*default*/ false)
}
#[cfg(not(unix))]
fn detect_keyboard_enhancement_supported() -> bool {
// Non-Unix startup keeps the existing crossterm path because the bounded probe implementation
@@ -461,14 +503,10 @@ where
}
impl Tui {
pub fn new(terminal: Terminal) -> Self {
pub fn new(terminal: Terminal, enhanced_keys_supported: bool) -> Self {
let (draw_tx, _) = broadcast::channel(1);
let frame_requester = FrameRequester::new(draw_tx.clone());
// Detect keyboard enhancement support before any EventStream is created so the
// crossterm poller can acquire its lock without contention.
let enhanced_keys_supported = !keyboard_modes::keyboard_enhancement_disabled()
&& detect_keyboard_enhancement_supported();
// Cache this to avoid contention with the event reader.
supports_color::on_cached(supports_color::Stream::Stdout);
let _ = crate::terminal_palette::default_colors();