forked from 1b-agent/opencadstudio-upstream
perf: parse wire names across cores when building the handle index
With the block geometry cached, the per-edit upload is 135 ms of which only 92 ms was accounted for by the regular and block halves. The rest is the handle index: a `String::parse` per wire over the whole 198 k resident set, rebuilt from scratch on every edit. The arena has an incremental path for this (`patch_handle_index`), but the shared path never reaches it -- the same gate that keeps the arena away from this drawing. Short of that, the parses are independent, so run them across cores and keep only the map insertion serial. `par_iter().enumerate()` collects in index order, so the slot lists keep the emission order they depend on. Adds a `wire-handle-index` PERF line, since this was the unaccounted third of the upload. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
13afc1479f
commit
7bf095e02b
1 file changed
+25
-5
@@ -2402,12 +2402,32 @@ impl Pipeline {
|
|||||||
// Index handle → wire slots once, here, so the per-hover selection
|
// Index handle → wire slots once, here, so the per-hover selection
|
||||||
// overlay can gather just the highlighted wires instead of scanning +
|
// overlay can gather just the highlighted wires instead of scanning +
|
||||||
// string-parsing the whole set every time the hovered entity changes.
|
// string-parsing the whole set every time the hovered entity changes.
|
||||||
|
//
|
||||||
|
// Parsing 198 k names is the bulk of this and each one is independent,
|
||||||
|
// so it runs across cores; only the map insertion stays serial, and
|
||||||
|
// that is cheap once the parse is done. Emission order is preserved --
|
||||||
|
// `par_iter().enumerate()` collects in index order -- which the slot
|
||||||
|
// lists rely on.
|
||||||
|
let t_index = crate::perf::enabled().then(iced::time::Instant::now);
|
||||||
|
let parsed: Vec<(u64, u32)> = {
|
||||||
|
use crate::par::prelude::*;
|
||||||
|
wires
|
||||||
|
.par_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(idx, w)| w.name.parse::<u64>().ok().map(|h| (h, idx as u32)))
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
let mut index: rustc_hash::FxHashMap<u64, Vec<u32>> = rustc_hash::FxHashMap::default();
|
let mut index: rustc_hash::FxHashMap<u64, Vec<u32>> = rustc_hash::FxHashMap::default();
|
||||||
index.reserve(wires.len());
|
index.reserve(parsed.len());
|
||||||
for (idx, w) in wires.iter().enumerate() {
|
for (handle, idx) in parsed {
|
||||||
if let Ok(h) = w.name.parse::<u64>() {
|
index.entry(handle).or_default().push(idx);
|
||||||
index.entry(h).or_default().push(idx as u32);
|
}
|
||||||
}
|
if let Some(started) = t_index {
|
||||||
|
crate::perf_record!(
|
||||||
|
"[perf] wire-handle-index {:.1}ms wires={}",
|
||||||
|
started.elapsed().as_secs_f64() * 1000.0,
|
||||||
|
wires.len(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
std::sync::Arc::new(batches),
|
std::sync::Arc::new(batches),
|
||||||
|
|||||||
Reference in new issue
Block a user