Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intrinsicify SpanHelpers.IndexOfAny(char,char) #40589

Conversation

benaadams
Copy link
Member

Updated Intrinsicify SpanHelpers.IndexOfAny(char,char) dotnet/coreclr#22877

Resolves: #12094

{
Debug.Assert(length >= 0);
// If vectors are supported, we first align to Vector.
// If the searchSpan has not been fixed or pinned the GC can relocate it during the
// execution of this method, so the alignment only acts as best endeavour.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thanks for the comment (cf. #11703).

@danmoseley
Copy link
Member

Regex uses IndexOfAny(char, char) and IndexOfAny(char, char, char) so would presumably benefit from this.

@danmoseley
Copy link
Member

Same request for perf numbers please - thanks!

@stephentoub
Copy link
Member

stephentoub commented Aug 12, 2020

Regex uses IndexOfAny(char, char) and IndexOfAny(char, char, char) so would presumably benefit from this.

Ideally we'd test this specifically with regex redux, which spends something like 30% of the time now inside of IndexOfAny(char, char). While it'd be great if it made it faster, I also want to confirm it doesn't make it slower. If memory serves, it was spending a lot of its time in the non-vectorized portion of the method.
#25023

@benaadams
Copy link
Member Author

Ideally we'd test this specifically with regex redux, which ...

@stephentoub is that in the performance repo?

@benaadams benaadams force-pushed the Intrinsicify-SpanHelpers.IndexOfAny(char,char) branch from fcb5c78 to ff3f2cf Compare August 12, 2020 16:37
@benaadams benaadams force-pushed the Intrinsicify-SpanHelpers.IndexOfAny(char,char) branch from ff3f2cf to 92a2679 Compare August 12, 2020 17:41
@benaadams
Copy link
Member Author

benaadams commented Aug 12, 2020

Dealing with the alignment loses most of the benefit, so have updated it to match the approach I took for SequenceCompareTo where if it goes vector it does vector for everything (tried a bunch of variations, aligning with loop, unaligned vector first read => aligned vectors etc), however this worked best

+10%

| Faster                                                  | base/diff | Base Median (ns) | Diff Median (ns) | Modality|
| ------------------------------------------------------- | ---------:| ----------------:| ----------------:| ------- |
| BenchmarksGame.RegexRedux_1.RunBench                    |      1.11 |      45419250.00 |      41004791.67 |         |
| BenchmarksGame.RegexRedux_5.RunBench(options: Compiled) |      1.10 |       8419890.74 |       7639460.29 | bimodal |
| BenchmarksGame.RegexRedux_5.RunBench(options: None)     |      1.02 |      25805255.56 |      25258357.14 |         |

@danmoseley
Copy link
Member

10% is significant on that one. This might be worth getting creative to try to get into this release.

@benaadams was that with IndexOfAny(char, char, char) changes as well? I would expect that to be relevant also: https://github.com/dotnet/performance/blob/master/src/benchmarks/micro/runtime/BenchmarksGame/regex-redux-5.cs#L60-L68

@benaadams
Copy link
Member Author

Just noticed that's with deleting IndexOfAny(char, char, char) to it uses the very slow path... 😅

@benaadams
Copy link
Member Author

Let me put them all in one as they are basically identical methods

@danmoseley
Copy link
Member

All your IndexOf PR's into one? That sounds like a good idea, thanks.

@danmoseley
Copy link
Member

Your perf numbers above demonstrate that the interpreter doesn't use IndexOfAny at all. @stephentoub had this listed in #1349 and it's checked off so maybe he tried it and it didn't give a win somehow.

@stephentoub
Copy link
Member

stephentoub commented Aug 12, 2020

I probably checked it off in error, or having employed IndexOf but not IndexOfAny. There's a TODO in the code for the IndexOfAny (and some other related optimizations):

// TODO https://github.com/dotnet/runtime/issues/1349:
// LeadingCharClasses may contain multiple sets, one for each of the first N characters in the expression,
// but the interpreter currently only uses the first set for the first character. In fact, we currently
// only run the analysis that can produce multiple sets if RegexOptions.Compiled was set.
string set = _code.LeadingCharClasses[0].CharClass;
if (RegexCharClass.IsSingleton(set))

I don't think I ever got around to evaluating the trade-off that would be required here, the overhead of extracting from the char class the 2 or 3 characters that could be used with IndexOfAny and then using IndexOfAny.

@danmoseley
Copy link
Member

OK, I un-checked it for some future day. Presumably the value could only be higher in the interpreter, since the runtime is larger.

@stephentoub
Copy link
Member

Presumably the value could only be higher in the interpreter, since the runtime is larger.

Not necessarily. With the compiler we get to compute the right thing to do once, and there's then no overhead at execution time, since the choice to use IndexOfAny and the arguments to it are all pre-computed. With the interpreter, we either need to redetermine that every time we invoke FindFirstChar, or we need to compute it once and store that data away somewhere, then check whether we have it and use it. It would certainly be beneficial when the things being searched for are few and far between, but if the IndexOfAny is used to search for something that frequently presents itself very quickly, it might be a net loss. Someone would need to do the work and then see whether it's fruitful on a variety of benchmarks.

@benaadams
Copy link
Member Author

Superseded by #40729

@benaadams benaadams closed this Aug 12, 2020
@benaadams benaadams deleted the Intrinsicify-SpanHelpers.IndexOfAny(char,char) branch August 12, 2020 19:27
@karelz karelz added this to the 5.0.0 milestone Aug 18, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 7, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use Intrinsics.X86 for SpanHelpers.IndexOfAny(char,char)
6 participants