Skip to content

Investigate ~7% perf regression after mojo 1.0.0b1 upgrade #153

Description

@msaelices

Background

Upgrading from mojo 0.26.2 to mojo 1.0.0b1 (#152) introduced a measurable performance regression on the bench_engine.mojo suite, despite all source-level adaptations being either mechanical (fn -> def, len -> byte_length) or documented as zero-overhead (UnsafePointer -> Optional[UnsafePointer] via the None-niche layout).

Measured numbers

Full stable bench_engine comparison, same hardware, back-to-back in one session:

  • Geomean: 1.07x slower across 80 benches (W/L/within +/-5%: 20/38/22)
  • 28 benches >10% slower, 10 benches 5-10% slower
  • 20 benches faster (some by 20-50%)

Persistent regressions (confirmed across re-runs with --filter):

benchmark baseline (0.26.2) new (1.0.0b1) ratio
optimize_extreme_quantifiers 59-71 ns 95-120 ns 1.60-1.69x
toll_free_simple 8.38 us 12.06 us 1.44x
nanpa_findall 5.15 us 7.04 us 1.37x
complex_number 6.72 us 8.95 us 1.33x
dfa_paren_phone 4.07 us 5.37 us 1.32x
sub_whitespace 11.91 us 15.09 us 1.27x
dfa_digits_only 109.97 us 137.51 us 1.25x
flexible_phone 54.32 us 67.36 us 1.24x
optimize_phone_quantifiers 26.12 us 31.97 us 1.22x
dual_quantifiers 17.6-24.4 us 26.8-29.1 us 1.20-1.52x
mixed_range_quantifiers 3.56-4.56 us 5.40-5.85 us 1.28-1.52x

Notable wins (mojo 1.0.0b1 made these faster):

benchmark baseline new ratio
range_lowercase 277 ns 183 ns 0.66x (1.5x faster)
match_all_digits 3.83 us 2.89 us 0.76x
sub_group_phone_fmt 19.95 us 15.40 us 0.77x
range_alphanumeric 557 ns 432 ns 0.78x
flexible_datetime 16.29 us 13.10 us 0.80x
predefined_word 17.49 us 14.07 us 0.80x
simple_phone 27.92 us 22.91 us 0.82x

Single-run noise observed

A --filter=quantifiers re-run flipped several big regressions: ultra_dense_quantifiers went from 1.60x slower to 1.19x faster; optimize_multiple_quantifiers from 1.47x slower to 1.13x faster; grouped_quantifiers from 1.21x slower to 1.25x faster. So the headline 7% geomean is partly inflated by single-run noise. A 3x-median full pass would be the next step before fully trusting the numbers.

Hypothesis

The regression pattern doesn't correlate with files touched by the migration (e.g. range_lowercase is among the biggest wins despite SIMD char-class code being relatively unchanged; optimize_extreme_quantifiers is a hard regression but routes through DFA whose pointer storage just moved to Optional). That points to compiler-level codegen shifts in 1.0.0b1 rather than this PR's adaptations as the dominant cause.

Suggested investigation

  1. Run a 3x-median full bench pass on both toolchains to filter single-run noise. The persistent ~25-70% regressions should narrow down to a smaller, more reliable set.
  2. For each persistent regression, identify the dispatch path (DFA vs lazy DFA vs OnePass vs backtracking NFA). Pattern: most look NFA-routed (*_phone, *_quantifiers, flexible_phone).
  3. Compare LLVM IR / asm output for one or two representative hot loops between 0.26.2 and 1.0.0b1.
  4. Confirm by reverting the Optional[UnsafePointer] migration locally on top of 1.0.0b1 and re-benching - if the perf doesn't recover, it's purely compiler.
  5. If the regression is in a small set of compiler-sensitive hot loops, try targeted rewrites (e.g. manual hoist + alias annotations) before falling back to filing upstream.

Workaround for users

Anyone on the perf-critical path can stay on mojo-regex 0.13.0 + mojo 0.26.x until this is resolved.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions