Files
Marcos Paulo 1806455cd9
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
perf: persistent index cache and a calendar scan cache
Index: .notescraft/cache/index-v1.bin keeps per-note link info, search doc, knowledge passages and lint votes keyed by (mtime, length), re-checked by stat at import; changed notes re-read; corrupt, truncated, oversized or old caches ignored and replaced. The knowledge vocabulary is trusted only by file hash (the old note-count check made a second open slower than a cold one). mdn-docs (14.7k notes, release): second open 1.4 s instead of 15.7-21 s cold.

Calendar: a per-session cache of what each note's scan gave the agenda (parsed events, all dated tasks) validated by length and mtime; window switches only filter in memory (mdn-docs 695 ms -> 2.7 ms), the cold pass runs in 8 ms slices across frames while the old grid stays visible, the week review reuses loaded items.

Built by Claude Sonnet; verified from a clean checkout of the staged files: 1901 tests in engine, index, knowledge and ui-egui lib plus calendar_view pass, clippy -D warnings on the four crates, xtask layers, tree and i18n clean.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 21:10:39 -03:00

60 lines
2.9 KiB
Rust

//! Open-time measurement on a real vault (run on demand, release build):
//! `cargo test --release -p notescraft-engine --test perf_open_cache -- --ignored --nocapture`.
//!
//! Skipped when `~/Documents/vaults/mdn-docs` is missing. Prints per-stage totals of what
//! `Session::index_note` does, then the whole open (cold, then from the index cache).
use std::path::PathBuf;
use std::time::{Duration, Instant};
use notescraft_engine::Session;
fn timed<T>(label: &str, work: impl FnOnce() -> T) -> T {
let start = Instant::now();
let out = work();
println!("{label:<34} {:>10.2?}", start.elapsed());
out
}
fn open_all(root: &std::path::Path) -> Session {
let mut session = Session::open_lazy(root).expect("lazy");
while !session.index_step(Duration::MAX).finished {}
session
}
#[test]
#[ignore = "measurement, run on demand in a release build"]
fn cold_and_cached_open_of_a_real_vault() {
let Some(home) = std::env::var_os("HOME") else { return };
let root = PathBuf::from(home).join("Documents/vaults/mdn-docs");
if !root.is_dir() {
return;
}
let listing = notescraft_vault::Vault::open_read_only(&root).and_then(|v| v.list()).expect("list");
let paths: Vec<String> = listing.into_iter().filter(|e| !e.is_dir && e.path.to_ascii_lowercase().ends_with(".md")).map(|e| e.path).collect();
println!("--- {} notes", paths.len());
let texts = timed("read every note", || paths.iter().filter_map(|p| std::fs::read_to_string(root.join(p)).ok()).collect::<Vec<_>>());
let mut links = notescraft_index::Index::new();
timed("link index: update_note", || paths.iter().zip(&texts).for_each(|(p, t)| drop(links.update_note(p, t))));
let mut search = notescraft_index::search::SearchIndex::new();
timed("search index: update", || paths.iter().zip(&texts).for_each(|(p, t)| drop(search.update(p, t))));
let mut passages = notescraft_knowledge::Index::default();
timed("knowledge passages: update", || paths.iter().zip(&texts).for_each(|(p, t)| drop(passages.update(p, t))));
let mut vocab = notescraft_knowledge::Vocab::default();
timed("knowledge vocabulary: update", || paths.iter().zip(&texts).for_each(|(p, t)| drop(vocab.update(p, t))));
drop((links, search, passages, vocab, texts));
let _ = std::fs::remove_dir_all(root.join(".notescraft/cache"));
let _ = std::fs::remove_file(root.join(".notescraft/knowledge-vocab.json"));
let lazy = timed("open_lazy (names only)", || Session::open_lazy(&root).expect("lazy"));
drop(lazy);
let cold = timed("cold open + index everything", || open_all(&root));
drop(cold);
let size = std::fs::metadata(root.join(".notescraft/cache/index-v1.bin")).map_or(0, |meta| meta.len());
println!("cache file: {} MiB", size / (1024 * 1024));
let lazy = timed("open_lazy with a cache", || Session::open_lazy(&root).expect("lazy"));
drop(lazy);
let cached = timed("cached open + index everything", || open_all(&root));
drop(cached);
}