Run UI on a dedicated OS thread
The UI event loop was running on the same tokio runtime as inference, tool execution, and background agents. When the runtime was busy, the UI's select loop couldn't wake up to render — causing visible latency and input lag. Give the UI its own OS thread with a dedicated single-threaded tokio runtime. The mind loop stays on the main runtime. Cross-runtime communication (channels, watch, Notify) works unchanged. Also drops the tokio-scoped dependency, which was only used to scope the two tasks together. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
d3f0b3f3f7
commit
b115cec096
3 changed files with 22 additions and 40 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
|
@ -559,7 +559,6 @@ dependencies = [
|
||||||
"tokenizers",
|
"tokenizers",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tokio-scoped",
|
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tui-markdown",
|
"tui-markdown",
|
||||||
"tui-textarea-2",
|
"tui-textarea-2",
|
||||||
|
|
@ -3160,27 +3159,6 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-scoped"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e4beb8ba13bc53ac53ce1d52b42f02e5d8060f0f42138862869beb769722b256"
|
|
||||||
dependencies = [
|
|
||||||
"tokio",
|
|
||||||
"tokio-stream",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-stream"
|
|
||||||
version = "0.1.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.18"
|
version = "0.7.18"
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ rayon = "1"
|
||||||
|
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tokio-util = { version = "0.7", features = ["compat"] }
|
tokio-util = { version = "0.7", features = ["compat"] }
|
||||||
tokio-scoped = "0.2.0"
|
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
capnp = "0.25"
|
capnp = "0.25"
|
||||||
capnp-rpc = "0.25"
|
capnp-rpc = "0.25"
|
||||||
|
|
|
||||||
|
|
@ -190,25 +190,30 @@ async fn start(cli: crate::user::CliArgs) -> Result<()> {
|
||||||
let (turn_tx, turn_rx) = tokio::sync::mpsc::channel(1);
|
let (turn_tx, turn_rx) = tokio::sync::mpsc::channel(1);
|
||||||
let (mind_tx, mind_rx) = tokio::sync::mpsc::unbounded_channel();
|
let (mind_tx, mind_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
|
||||||
let mind = crate::mind::Mind::new(config, turn_tx).await;
|
let mind = std::sync::Arc::new(crate::mind::Mind::new(config, turn_tx).await);
|
||||||
|
|
||||||
let mut result = Ok(());
|
// UI runs on a dedicated OS thread so CPU-intensive work on the
|
||||||
tokio_scoped::scope(|s| {
|
// main tokio runtime can't starve rendering.
|
||||||
// Mind event loop — init + run
|
let ui_mind = mind.clone();
|
||||||
s.spawn(async {
|
let ui_handle = std::thread::Builder::new()
|
||||||
|
.name("ui".into())
|
||||||
|
.spawn(move || {
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.expect("UI tokio runtime");
|
||||||
|
rt.block_on(run(
|
||||||
|
tui::App::new(String::new(), ui_mind.agent.clone()),
|
||||||
|
&ui_mind, mind_tx,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.expect("spawn UI thread");
|
||||||
|
|
||||||
|
// Mind event loop — runs on the main tokio runtime
|
||||||
mind.init().await;
|
mind.init().await;
|
||||||
mind.run(mind_rx, turn_rx).await;
|
mind.run(mind_rx, turn_rx).await;
|
||||||
});
|
|
||||||
|
|
||||||
// UI event loop
|
ui_handle.join().unwrap_or_else(|_| Err(anyhow::anyhow!("UI thread panicked")))
|
||||||
s.spawn(async {
|
|
||||||
result = run(
|
|
||||||
tui::App::new(String::new(), mind.agent.clone()),
|
|
||||||
&mind, mind_tx,
|
|
||||||
).await;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hotkey_cycle_reasoning(mind: &crate::mind::Mind) {
|
fn hotkey_cycle_reasoning(mind: &crate::mind::Mind) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue