Skip to content

Performance: excessive memory allocations (970 brk calls per suggestion) #93

@noahgift

Description

@noahgift

Performance Issue

Renacer tracing reveals excessive memory allocations during suggestion.

Evidence

$ renacer -c -- aprender-shell suggest "cargo "
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 73.18    0.008002           8       970           brk    # ❌ 970 allocations!
  2.26    0.000247          11        22           mmap
 13.98    0.001529         169         9           read
...

970 brk syscalls for a single suggestion is excessive. Each brk is a heap expansion.

Impact

  • ~8ms spent just on memory allocation
  • Total syscall overhead: ~11ms per suggestion
  • In the widget (called on every keystroke), this adds up

Analysis

The brk calls suggest:

  1. Many small allocations during model traversal
  2. Possible lack of pre-allocation for results
  3. String allocations for each n-gram lookup

Suggested Fixes

1. Pre-allocate result buffers

fn suggest(&self, prefix: &str, count: usize) -> Vec<Suggestion> {
    let mut results = Vec::with_capacity(count);  // Pre-allocate
    // ...
}

2. Use arena allocator for hot path

use bumpalo::Bump;

fn suggest(&self, prefix: &str) -> Vec<Suggestion> {
    let arena = Bump::new();
    // Allocate intermediate strings in arena
    // Only clone final results to heap
}

3. Cache model in memory-mapped file

Instead of deserializing on each call, use mmap:

let model = unsafe { memmap2::Mmap::map(&file)? };

4. Lazy model loading with static lifetime

static MODEL: OnceLock<Model> = OnceLock::new();

fn get_model() -> &'static Model {
    MODEL.get_or_init(|| Model::load_default().unwrap())
}

Benchmarks Needed

  • Baseline: current allocation count
  • Target: <100 allocations per suggestion
  • Measure with renacer -c --stats-extended

Related

  • Discovered via renacer integration testing
  • Affects real-time suggestion latency

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions