Share the field-name length probe across SBE's BSON helpers

XMLWordPrintableJSON

    • Type: Improvement
    • Resolution: Fixed
    • Priority: Major - P3
    • 9.1.0-rc0
    • Affects Version/s: None
    • Component/s: None
    • None
    • Query Execution
    • Fully Compatible
    • QE 2026-08-31
    • 200
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      Scope

      SBE only. This covers mongo::sbe::bson in src/mongo/db/exec/sbe/values/bson.h. It does not touch BSONElement/BSONObj, the classic execution engine, or any other BSON parsing path.

      Context

      While investigating BF-45431 (MatchAndGroupLookupUnwind regressed ~3% vs 8.3), profiling the shape on top_twenty_shapes_locust / perf-3-node-replSet.arm.aws.2024-05 showed roughly 7% of cycles in libc strlen, some share of it reached through SBE's BSON field-name helpers. Field-name handling in the SBE scan stage accounted for a large fraction of ScanStageBaseImpl::getNext() and sbe::bson::getField().

      Problem

      The three helpers that need a field name's length did it three different ways:* getField() probed the first nine bytes with unrolled byte comparisons, falling back to strlen() only for longer names.

      • fieldNameAndLength() called strlen() unconditionally, despite being on the same per-element path -- the multi-field scan in placeFieldsFromRecordInAccessors() calls it for every field of every document.
      • getValue() also called strlen() unconditionally.

      Change

      Extract the probe as fieldNameLength() and use it from all three. Field names of eight bytes or fewer, which dominate, no longer pay for a call; longer names behave exactly as before.

      Measurements

      sbe_get_field_bm was used to evaluate alternatives. A SWAR (SIMD Within A Register) word-at-a-time scan replacing the unrolled probe entirely was tried and rejected: it regressed short names by up to 116%, because the measured benefit is the removed call (a constant ~1.4ns per element, independent of name length) rather than faster scanning. Retaining the unrolled probe and using SWAR only beyond eight bytes measured -5% geomean, but was dropped in favour of the simpler shared-probe change.

      Validation

      PMS comparison 6a7cadcda97f1cbbd681b7bb -- 5 patches vs 5 at the merge base, perf-required.

      Follow-ups (not in scope here)

      • No unit coverage exists for fieldNameLength(); the edges worth testing are empty names, lengths 7/8/9, and names ending within eight bytes of the document end.
      • SWAR for names of nine or more bytes, if the microbenchmark case is judged worth the complexity.
      • The remaining cost in that loop is the walk's dependency chain (type byte -> kAdvanceTable -> next element), which a field-shape hint would attack.

            Assignee:
            Catalin Sumanaru
            Reporter:
            Catalin Sumanaru
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: