perf: prism pairs before the mesh, bodies measured once, and a STEP import that copies less (#714)
A cut or an intersection between prisms (a plate and the tools through it) is now decided in 2D before either operand is meshed. A body's size and volume are measured once, a placement reads its orientation from its matrix, the evaluation cache is bounded to 64 MiB, and STEP import copies fewer shells. Hole plates evaluate 20-30% faster with less memory, and models are unchanged. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
a1cb8d4d36
commit
2bb24d1d2a
13 files changed
+630
-71
No files matched your search
+42
-5
@@ -459,6 +459,8 @@ impl ModelState {
|
||||
pub struct EvalCache {
|
||||
map: std::collections::HashMap<u64, CachedEval>,
|
||||
order: std::collections::VecDeque<u64>,
|
||||
/// What the stored results cost together.
|
||||
bytes: usize,
|
||||
pub hits: usize,
|
||||
}
|
||||
|
||||
@@ -469,11 +471,20 @@ struct CachedEval {
|
||||
boolean_diagnostics: kernel::BooleanDiagnostics,
|
||||
ms: f64,
|
||||
state: Arc<ModelState>,
|
||||
/// What the state costs, worked out once when it was stored (see
|
||||
/// [`ModelState::retained_bytes`]).
|
||||
bytes: usize,
|
||||
}
|
||||
|
||||
/// Results kept (oldest dropped first).
|
||||
const CACHE_ENTRIES: usize = 4096;
|
||||
|
||||
/// Bytes of results kept (oldest dropped first). A cached result is as big as the model it
|
||||
/// holds, so bounding the cache by entry count alone let a long editing session keep every
|
||||
/// superseded state: the entries nothing else refers to any more are exactly the ones a byte
|
||||
/// budget drops.
|
||||
const CACHE_BYTES: usize = 64 << 20;
|
||||
|
||||
impl EvalCache {
|
||||
fn get(&mut self, key: u64) -> Option<CachedEval> {
|
||||
let r = self.map.get(&key).cloned();
|
||||
@@ -483,18 +494,43 @@ impl EvalCache {
|
||||
r
|
||||
}
|
||||
fn put(&mut self, key: u64, e: CachedEval) {
|
||||
if self.map.insert(key, e).is_none() {
|
||||
self.order.push_back(key);
|
||||
let bytes = e.bytes;
|
||||
match self.map.insert(key, e) {
|
||||
Some(old) => self.bytes = self.bytes.saturating_sub(old.bytes),
|
||||
None => self.order.push_back(key),
|
||||
}
|
||||
while self.order.len() > CACHE_ENTRIES {
|
||||
if let Some(k) = self.order.pop_front() {
|
||||
self.map.remove(&k);
|
||||
self.bytes = self.bytes.saturating_add(bytes);
|
||||
// One result is always kept, so a single state larger than the budget cannot empty the
|
||||
// cache and force a full recompute on every undo.
|
||||
while self.order.len() > CACHE_ENTRIES || (self.bytes > CACHE_BYTES && self.order.len() > 1) {
|
||||
if let Some(k) = self.order.pop_front()
|
||||
&& let Some(old) = self.map.remove(&k)
|
||||
{
|
||||
self.bytes = self.bytes.saturating_sub(old.bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SolvedSketch {
|
||||
/// Rough heap footprint (see [`ModelState::retained_bytes`]).
|
||||
pub fn retained_bytes(&self) -> usize {
|
||||
let entities = self.sketch.points.len() + self.sketch.curves.len() + self.sketch.constraints.len() + self.sketch.links.len();
|
||||
let loops: usize = self.profiles.iter().map(|p| p.region.outer.segs.len() + p.region.holes.iter().map(|h| h.segs.len()).sum::<usize>()).sum();
|
||||
entities * 192 + loops * 64 + 512
|
||||
}
|
||||
}
|
||||
|
||||
impl ModelState {
|
||||
/// Rough heap footprint, for the evaluation cache's byte budget. The bodies' B-rep
|
||||
/// topology is what makes a kept timeline snapshot expensive, so it dominates; sketches
|
||||
/// and the rest are counted from their entity counts.
|
||||
pub fn retained_bytes(&self) -> usize {
|
||||
let bodies: usize = self.bodies.iter().map(|b| b.body.retained_bytes()).sum();
|
||||
let sketches: usize = self.sketches.iter().map(|s| s.retained_bytes()).sum();
|
||||
bodies + sketches + self.sheets.len() * 4096 + self.threads.len() * 192 + self.construct.len() * 192
|
||||
}
|
||||
|
||||
pub fn body(&self, name: &str) -> Option<&ModelBody> {
|
||||
self.bodies.iter().find(|b| b.name == name)
|
||||
}
|
||||
@@ -1048,6 +1084,7 @@ impl Model {
|
||||
warning: warning.clone(),
|
||||
boolean_diagnostics: boolean_diagnostics.clone(),
|
||||
ms,
|
||||
bytes: state.retained_bytes(),
|
||||
state: state.clone(),
|
||||
},
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user