StartsWith Linux perf improvements by adamsitnik · Pull Request #26621 · dotnet/coreclr (original) (raw)

This PR improves the performance of Culture-aware string.StartsWith on Linux.

Unfortunately, ICU does not expose a method that allows for optimal StartsWith using Collator API (there is a StartsWith that allows for comparing UnicodeStrings but without a possibility to specify culture).

I read some docs, articles and studied the code of ICU itself and came up with this proposal.

The longer the source text and the more unlucky case (miss) the bigger the gains.

It should help a lot with https://github.com/dotnet/corefx/issues/40674

public class Perf_StartsWith { public IEnumerable<object[]> StartsWithArguments() { yield return new object[] { "a", "a" }; yield return new object[] { "aaaaaaaaaaa", "a" }; yield return new object[] { "a", "aaaaaaaaaaa" }; yield return new object[] { new string('a', 512), "a" }; yield return new object[] { new string('a', 512), "aaaaaaaaaaa" }; yield return new object[] { new string('a', 512), new string('a', 512) }; yield return new object[] { new string('a', 2048), "a" }; yield return new object[] { new string('a', 2048), "aaaaaaaaaaa" }; yield return new object[] { new string('a', 2048), new string('a', 2048) }; }

[GlobalSetup]
public void Setup() => Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("fr-FR"); // isAsciiEqualityOrdinal=false

[Benchmark]
[ArgumentsSource(nameof(StartsWithArguments))]
public bool StartsWith(string text, string prefix) => text.StartsWith(prefix);

}

Method Toolchain text prefix Mean Ratio
StartsWith /after/corerun a a 2.930 ns 1.04
StartsWith /before/corerun a a 2.807 ns 1.00
StartsWith /after/corerun a aaaaaaaaaaa 325.073 ns 0.05
StartsWith /before/corerun a aaaaaaaaaaa 6,422.332 ns 1.00
StartsWith /after/corerun aaaaaaaaaaa a 362.019 ns 0.06
StartsWith /before/corerun aaaaaaaaaaa a 5,589.542 ns 1.00
StartsWith /after/corerun aaaaa(...)aaaaa [512] a 510.155 ns 0.08
StartsWith /before/corerun aaaaa(...)aaaaa [512] a 6,032.578 ns 1.00
StartsWith /after/corerun aaaaa(...)aaaaa [512] aaaaaaaaaaa 664.491 ns 0.09
StartsWith /before/corerun aaaaa(...)aaaaa [512] aaaaaaaaaaa 7,143.208 ns 1.00
StartsWith /after/corerun aaaaa(...)aaaaa [512] aaaaa(...)aaaaa [512] 2.934 ns 1.03
StartsWith /before/corerun aaaaa(...)aaaaa [512] aaaaa(...)aaaaa [512] 2.844 ns 1.00
StartsWith /after/corerun aaaaa(...)aaaaa [2048] a 551.200 ns 0.08
StartsWith /before/corerun aaaaa(...)aaaaa [2048] a 6,754.139 ns 1.00
StartsWith /after/corerun aaaaa(...)aaaaa [2048] aaaaaaaaaaa 760.843 ns 0.11
StartsWith /before/corerun aaaaa(...)aaaaa [2048] aaaaaaaaaaa 7,071.727 ns 1.00
StartsWith /after/corerun aaaaa(...)aaaaa [2048] aaaaa(...)aaaaa [2048] 2.787 ns 0.96
StartsWith /before/corerun aaaaa(...)aaaaa [2048] aaaaa(...)aaaaa [2048] 2.876 ns 1.00