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 |