Skip to content

perf(vector/search): visited bitmap zero-init dominates at high max_doc_id / low ef_search #647

Description

@mosuka

Round-3 perf push sub-issue (tracked under umbrella #536).

[M] Visited bitmap zero-init dominates at high max_doc_id / low ef_search

  • Where: laurus/src/vector/index/hnsw/searcher.rs:438
    BitVec::from_elem(graph.max_doc_id() as usize + 1, false).

  • Current behavior: 10 M-vector segment → 1.25 MB bitmap zeroed once per query. For
    ef_search = 64 × ~5 neighbours visited, fewer than 1000 positions are touched but every
    byte of the 1.25 MB is written at query start.

  • Why it might be a bottleneck / risk: Memory write cost O(N), independent of search
    depth. At 10 M × 1000 QPS this is ~1.2 GB/s of pure zero writes.

  • Reference precedent: hnswlib VisitedListPool; FAISS VisitedTable — both use
    generational counters.

  • Data structure (current): BitVec (1 bit / node, N/8 bytes).

  • Data structure (proposed):

    // 4 bytes / node, reset = bump u32 counter (O(1)):
    visited:     Box<[u32]>,             // allocated once at reader load
    visited_gen: u32,                    // bumped per query
    // is_visited(id) = visited[id] == gen   // 1 load, 1 cmp
    // mark(id)      = visited[id] = gen     // 1 store
    // reset()       = gen += 1; if wrap     // 1 add (real re-zero only on wraparound)
    

    4× memory vs bitmap, but reset is O(1). u16 variant cuts to 2× and re-zeros every 65 K
    queries (cheap amortised).

  • Suggested direction: Switch to generational visited array, allocated once per reader
    (sized from max_doc_id). Live in SearchContext so threads do not contend.

  • Risk / scope: Small. Confined to HnswSearcher + HnswIndexReader.


ID: VS-04 — see ~/.claude/tasks/laurus/20260523_perf_round3_audit/task_list.md for the full Round-3 issue list.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions