diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-24 11:39:36 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-07-30 15:18:55 -0300 |
| commit | cb05c363045bf0e7af5858f6d7bc26f026fa9d70 (patch) | |
| tree | c3e89426ff044ffe339dd3a77e7f3b7115cba636 /vrsite/bench_test.go | |
| download | notevi-cb05c363045bf0e7af5858f6d7bc26f026fa9d70.tar.gz notevi-cb05c363045bf0e7af5858f6d7bc26f026fa9d70.zip | |
Diffstat (limited to 'vrsite/bench_test.go')
| -rw-r--r-- | vrsite/bench_test.go | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/vrsite/bench_test.go b/vrsite/bench_test.go new file mode 100644 index 0000000..8950b8f --- /dev/null +++ b/vrsite/bench_test.go @@ -0,0 +1,129 @@ +package main + +import ( + "bytes" + "fmt" + "io" + "testing" +) + +// A realistic Rust chunk (~1.2KB): doc comments, generics, lifetimes, attrs, +// strings with escapes, macros — the constructs the highlighter works hardest +// on. Repetition parses fine; tree-sitter is not a compiler. +var rustChunk = []byte(`//! Module documentation with some text. +use std::{collections::HashMap, sync::Arc}; + +/// A cached entry with generics and lifetimes. +#[derive(Debug, Clone, PartialEq)] +pub struct CacheEntry<'a, T: Clone + Send> { + pub key: &'a str, + pub value: Arc<T>, + hits: u64, + tags: HashMap<String, Vec<u8>>, +} + +pub enum LookupResult<T> { + Hit(Arc<T>), + Miss { reason: &'static str, code: i32 }, + Tombstone, +} + +impl<'a, T: Clone + Send> CacheEntry<'a, T> { + pub fn new(key: &'a str, value: T) -> Self { + let tags = HashMap::new(); + Self { key, value: Arc::new(value), hits: 0, tags } + } + + /// Record a hit and return the running total. + pub fn touch(&mut self) -> u64 { + self.hits = self.hits.saturating_add(1); + if self.hits % 100 == 0 { + println!("entry {} hit {} times \"escaped\"", self.key, self.hits); + } + self.hits + } + + pub fn lookup(&self, keys: &[&str]) -> LookupResult<T> { + match keys.iter().position(|k| *k == self.key) { + Some(_) => LookupResult::Hit(self.value.clone()), + None => LookupResult::Miss { reason: "absent <key>", code: -1 }, + } + } +} + +const MAX_ENTRIES: usize = 4096; +static GREETING: &str = "hello \"quoted\" <world> & friends"; +`) + +func synthRust(size int) []byte { + var b bytes.Buffer + for b.Len() < size { + b.Write(rustChunk) + } + return b.Bytes() +} + +var sizes = []int{128 << 10, 1 << 20, 4 << 20} + +func benchHL(b *testing.B) *highlighter { + b.Helper() + return newHighlighter(loadTheme("", "", "dark"), loadTheme("", "", "light")) +} + +// tree-sitter parse + query + paint only +func BenchmarkClassify(b *testing.B) { + hl := benchHL(b) + for _, size := range sizes { + src := synthRust(size) + b.Run(fmt.Sprintf("%dKB", size>>10), func(b *testing.B) { + b.SetBytes(int64(len(src))) + b.ReportAllocs() + for i := 0; i < b.N; i++ { + hl.classify("bench.rs", src) + } + }) + } +} + +// classify + full per-line HTML emit +func BenchmarkRender(b *testing.B) { + hl := benchHL(b) + for _, size := range sizes { + src := synthRust(size) + b.Run(fmt.Sprintf("%dKB", size>>10), func(b *testing.B) { + b.SetBytes(int64(len(src))) + b.ReportAllocs() + for i := 0; i < b.N; i++ { + f := &File{Path: "bench.rs", NoteAt: map[int]int{}} + f.render(src, hl) + } + }) + } +} + +// template execution for an already-rendered file page +func BenchmarkExecute(b *testing.B) { + hl := benchHL(b) + tpl := newTemplates() + site := &Site{ + Title: "bench", Files: map[string]*File{}, + Theme: loadTheme("", "", "dark"), Light: loadTheme("", "", "light"), + Agents: []*Agent{{Name: "bench", Short: "bench", Bit: 1}}, + } + for _, size := range sizes { + src := synthRust(size) + f := &File{Path: "bench.rs", NoteAt: map[int]int{}, Traced: true, Change: "zzzzzzzz"} + f.cover(1, bytes.Count(src, []byte("\n"))/2, 1) + f.render(src, hl) + p := &page{Site: site, Kind: "file", Title: "bench", Root: "", Current: f.Path, File: f} + b.Run(fmt.Sprintf("%dKB", size>>10), func(b *testing.B) { + b.SetBytes(int64(len(src))) + b.ReportAllocs() + for i := 0; i < b.N; i++ { + if err := tpl.Execute(io.Discard, p); err != nil { + b.Fatal(err) + } + } + }) + } +} |
