Skip to content

Rope.Equals uses slow IEnumerable<char> iterator for StringRope, adding unnecessary overhead to large string switch compilation #83663

@davidmikh

Description

@davidmikh

Summary

Rope.Equals compares two ropes character-by-character using IEnumerable<char> iterators, which allocates a CharEnumerator and uses virtual dispatch per character. For StringRope (the common case wrapping a plain string), this is significantly slower than using string == directly.

This is on the hot path in DecisionDagBuilder.CheckConsistentDecision, which is called O(n²) times when building the decision DAG for large string switch statements. At 10,000 switch cases, Rope.Equals accounts for ~5.8% of total CPU time.

Benchmark

Using SwitchStatementBenchmarks.BindFile (compiles a C# file with an N-case string switch and emits IL) where Before represents the current implementation and After represents an implementation that just uses string == directly for StringRope:

SwitchCount Before After Speedup Alloc Before Alloc After Alloc Δ
100 62 ms 49 ms -21% 2.7 MB 2.5 MB -9%
1,000 972 ms 628 ms -35% 115 MB 90 MB -22%
5,000 12.6 s 9.9 s -22% 2,488 MB 1,975 MB -21%
10,000 44.7 s 38.8 s -13% 10,261 MB 7,765 MB -24%

Fix

Override Equals and GetHashCode in StringRope to use direct string operations instead of the IEnumerable<char> base implementation.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions