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
- 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.
- 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).
- Compare LLVM IR / asm output for one or two representative hot loops between 0.26.2 and 1.0.0b1.
- 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.
- 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.
Background
Upgrading from mojo 0.26.2 to mojo 1.0.0b1 (#152) introduced a measurable performance regression on the
bench_engine.mojosuite, 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_enginecomparison, same hardware, back-to-back in one session:Persistent regressions (confirmed across re-runs with
--filter):Notable wins (mojo 1.0.0b1 made these faster):
Single-run noise observed
A
--filter=quantifiersre-run flipped several big regressions:ultra_dense_quantifierswent from 1.60x slower to 1.19x faster;optimize_multiple_quantifiersfrom 1.47x slower to 1.13x faster;grouped_quantifiersfrom 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_lowercaseis among the biggest wins despite SIMD char-class code being relatively unchanged;optimize_extreme_quantifiersis a hard regression but routes through DFA whose pointer storage just moved toOptional). That points to compiler-level codegen shifts in 1.0.0b1 rather than this PR's adaptations as the dominant cause.Suggested investigation
*_phone,*_quantifiers,flexible_phone).Optional[UnsafePointer]migration locally on top of 1.0.0b1 and re-benching - if the perf doesn't recover, it's purely compiler.Workaround for users
Anyone on the perf-critical path can stay on
mojo-regex0.13.0 + mojo 0.26.x until this is resolved.