Date: November 17-18, 2025
System: Intel Xeon E5-2699 v3 @ 2.30GHz (36 cores), 252 GB RAM
CPU Affinity: Pinned to core 0 using taskset -c 0
CPU Governor: performance (verified)
Attempted benchmarks:
state_operations_benchmarks.rs ❌
insert() and merge() methods now require query_length: usize parametertransition_benchmarks.rs ❌
transition_state() signature changedbenchmarks.rs (main) ❌
PathMapDictionary (pathmap-backend feature not enabled)comprehensive_profiling.rs ❌
pathmap-backend featuresubstitution_set_microbench.rs ✅
rand featureNO WORKING GENERALIZED AUTOMATON BENCHMARKS: None of the existing benchmarks test the generalized automaton's core operations (state transitions, successor generation, acceptance).
API Drift: Many benchmarks haven't been updated since the Phase 3/4 changes (phonetic operations, formal verification).
Feature Dependencies: Multiple benchmarks require features not enabled by default (pathmap-backend, rand, serialization).
Limited Phonetic Coverage: Only substitution micro-benchmarks exist; no end-to-end phonetic operation benchmarks.
substitution_set_microbench.rs (partial results):
substitution_set/insertion/char/50 969.89 ns (51.55 Melem/s)
substitution_set/insertion/char/100 1.8056 µs (55.38 Melem/s)
substitution_set/insertion/char/500 9.7436 µs (51.32 Melem/s)
substitution_set/presets/byte/phonetic_basic 317.32 ns
substitution_set/presets/byte/keyboard_qwerty 592.33 ns
Interpretation: Substitution lookups are very fast (~300-600 ns), suggesting they are NOT the primary bottleneck. The real performance issues are likely in:
Based on static code analysis of /src/transducer/generalized/:
Vec<GeneralizedPosition> for each callword_slice.chars().collect() - allocates Veccan_apply() checkssuccessors() for each positioneprintln! statements in debug buildsFor a single accepts() call with word length W, input length I, distance D:
Time Complexity:
O(I × state_size × (ops + subsumption_cost))
Where:
- I: input length (typical: 5-15 chars)
- state_size: positions in state (typical: 5-20, worst: 50+)
- ops: operations checked (standard: 4, phonetic: ~25)
- subsumption_cost: O(state_size) per successor
Worst case: O(I × state_size²)
Space Complexity: O(state_size × sizeof(GeneralizedPosition))
Vec allocations:
successors(): 1 per position per characterword_chars: Vec<char>: 1 per successor callString::from() / to_string(): Multiple per operation checkSmallVec usage:
State uses SmallVec<[GeneralizedPosition; 8]>Based on code analysis, we hypothesize:
Hypothesis: successors_i_type() and successors_m_type() account for 60-80% of CPU time in accepts().
Rationale: These are the largest, most complex methods called for every position at every input character.
Test: Flamegraph analysis should show these methods as top hotspots.
Hypothesis: Allocating Vec<char> repeatedly for word_slice.chars().collect() contributes significant overhead.
Rationale: Called multiple times per state transition (once per operation type check).
Test: Count allocations; cache the Vec and measure improvement.
Expected improvement: 10-15% reduction in allocation count, 5-10% runtime improvement.
Hypothesis: add_position() subsumption checks create quadratic behavior when states have 20+ positions.
Rationale: For N positions, adding M successors requires N×M subsumption checks.
Test: Benchmark with controlled state sizes (1, 5, 10, 20, 50 positions).
Expected: Superlinear time growth with state size.
Hypothesis: Converting characters to strings (to_string(), String::from()) in operation checks adds measurable overhead.
Rationale: Called for every operation check, requires heap allocation for owned String.
Test: Replace with byte slice operations, measure allocation reduction.
Expected improvement: 5-10% reduction in allocations, 3-5% runtime improvement.
Hypothesis: Enabling full phonetic operation set (consonant_digraphs + confusions + clusters) causes 2-3x slowdown vs standard operations only.
Rationale:
Test: Benchmark same inputs with standard-only vs full phonetic.
Expected: 2-3x runtime increase with phonetic operations.
Hypothesis: Split operations (with word_pos calculation and character extraction) add 20-30% overhead compared to standard operations.
Rationale: Additional logic for empty subword handling, word position calculation (Phase 4 fixes).
Test: Benchmark inputs with splits vs inputs with substitutions.
Expected: Split-heavy inputs 20-30% slower.
To test these hypotheses, we need:
Key Finding: Existing benchmark suite is broken and insufficient. We must create comprehensive new benchmarks to properly measure generalized automaton and phonetic operation performance.
Hypothesis Priority:
Ready to proceed with Phase 1.2: Creating new benchmark files.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |