Skip to content

Vectorize IndexOfAnyExcept for four values - #73696

Merged
adamsitnik merged 4 commits into
dotnet:mainfrom
adamsitnik:vectorizeIndexOfAnyExcept4
Aug 15, 2022
Merged

Vectorize IndexOfAnyExcept for four values#73696
adamsitnik merged 4 commits into
dotnet:mainfrom
adamsitnik:vectorizeIndexOfAnyExcept4

Conversation

@adamsitnik

Copy link
Copy Markdown
Member

I took a look and the usage of IndexOfAnyExcept and the patterns are following:

  • IndexOfAnyExcept(byte) - most frequent
  • IndexOfAnyExcept(int), IndexOfAnyExcept(char) - sporadic
  • IndexOfAnyExcept(" \t\r\n") - few places

Since the first two got vectorized by @stephentoub in #73488 I've vectorized the 4 values case.

Benchmarks:

publicclassIndexOfAnyExcept{privatestring_whiteSpaces,_noWhiteSpaces;[Params(1,4,16,64,256,1024)]publicintLength{get;set;}[GlobalSetup]publicvoidSetup(){_whiteSpaces=newstring(' ',Length);_noWhiteSpaces=newstring('a',Length);}[Benchmark]publicintImmediateMismatch()=>_noWhiteSpaces.AsSpan().IndexOfAnyExcept(" \t\r\n");[Benchmark]publicintNoMismatch()=>_whiteSpaces.AsSpan().IndexOfAnyExcept(" \t\r\n");}
BenchmarkDotNet=v0.13.1.1845-nightly, OS=Windows 11 (10.0.22000.795/21H2)
AMD Ryzen Threadripper PRO 3945WX 12-Cores, 1 CPU, 24 logical and 12 physical cores
.NET SDK=7.0.100-preview.7.22377.5
[Host] : .NET 7.0.0 (7.0.22.37506), X64 RyuJIT AVX2
Job-OQFSEO : .NET 7.0.0 (42.42.42.42424), X64 RyuJIT AVX2
Job-main : .NET 7.0.0 (42.42.42.42424), X64 RyuJIT AVX2
MethodJobLengthMeanRatio
ImmediateMismatchJob-PR17.401 ns1.30
ImmediateMismatchJob-main15.679 ns1.00
NoMismatchJob-PR17.259 ns1.32
NoMismatchJob-main15.483 ns1.00
ImmediateMismatchJob-PR47.597 ns1.34
ImmediateMismatchJob-main45.689 ns1.00
NoMismatchJob-PR410.021 ns0.76
NoMismatchJob-main413.155 ns1.00
ImmediateMismatchJob-PR169.135 ns1.47
ImmediateMismatchJob-main166.226 ns1.00
NoMismatchJob-PR169.973 ns0.24
NoMismatchJob-main1641.561 ns1.00
ImmediateMismatchJob-PR649.123 ns1.47
ImmediateMismatchJob-main646.216 ns1.00
NoMismatchJob-PR6415.135 ns0.09
NoMismatchJob-main64164.828 ns1.00
ImmediateMismatchJob-PR2569.126 ns1.47
ImmediateMismatchJob-main2566.196 ns1.00
NoMismatchJob-PR25631.836 ns0.05
NoMismatchJob-main256642.908 ns1.00
ImmediateMismatchJob-PR10249.128 ns1.48
ImmediateMismatchJob-main10246.153 ns1.00
NoMismatchJob-PR1024104.512 ns0.04
NoMismatchJob-main10242,534.292 ns1.00

It's clearly a tradeoff:

  • for all strings with immediate mismatch, the method has regressed by 2-3ns
  • same goes for very short strings with no mismatch
  • for other cases, when there is no mismatch the longer the string the bigger the gain

@adamsitnikadamsitnik added this to the 7.0.0 milestone Aug 10, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-memory
See info in area-owners.md if you want to be subscribed.

Issue Details

I took a look and the usage of IndexOfAnyExcept and the patterns are following:

  • IndexOfAnyExcept(byte) - most frequent
  • IndexOfAnyExcept(int), IndexOfAnyExcept(char) - sporadic
  • IndexOfAnyExcept(" \t\r\n") - few places

Since the first two got vectorized by @stephentoub in #73488 I've vectorized the 4 values case.

Benchmarks:

publicclassIndexOfAnyExcept{privatestring_whiteSpaces,_noWhiteSpaces;[Params(1,4,16,64,256,1024)]publicintLength{get;set;}[GlobalSetup]publicvoidSetup(){_whiteSpaces=newstring(' ',Length);_noWhiteSpaces=newstring('a',Length);}[Benchmark]publicintImmediateMismatch()=>_noWhiteSpaces.AsSpan().IndexOfAnyExcept(" \t\r\n");[Benchmark]publicintNoMismatch()=>_whiteSpaces.AsSpan().IndexOfAnyExcept(" \t\r\n");}
BenchmarkDotNet=v0.13.1.1845-nightly, OS=Windows 11 (10.0.22000.795/21H2)
AMD Ryzen Threadripper PRO 3945WX 12-Cores, 1 CPU, 24 logical and 12 physical cores
.NET SDK=7.0.100-preview.7.22377.5
[Host] : .NET 7.0.0 (7.0.22.37506), X64 RyuJIT AVX2
Job-OQFSEO : .NET 7.0.0 (42.42.42.42424), X64 RyuJIT AVX2
Job-main : .NET 7.0.0 (42.42.42.42424), X64 RyuJIT AVX2
MethodJobLengthMeanRatio
ImmediateMismatchJob-PR17.401 ns1.30
ImmediateMismatchJob-main15.679 ns1.00
NoMismatchJob-PR17.259 ns1.32
NoMismatchJob-main15.483 ns1.00
ImmediateMismatchJob-PR47.597 ns1.34
ImmediateMismatchJob-main45.689 ns1.00
NoMismatchJob-PR410.021 ns0.76
NoMismatchJob-main413.155 ns1.00
ImmediateMismatchJob-PR169.135 ns1.47
ImmediateMismatchJob-main166.226 ns1.00
NoMismatchJob-PR169.973 ns0.24
NoMismatchJob-main1641.561 ns1.00
ImmediateMismatchJob-PR649.123 ns1.47
ImmediateMismatchJob-main646.216 ns1.00
NoMismatchJob-PR6415.135 ns0.09
NoMismatchJob-main64164.828 ns1.00
ImmediateMismatchJob-PR2569.126 ns1.47
ImmediateMismatchJob-main2566.196 ns1.00
NoMismatchJob-PR25631.836 ns0.05
NoMismatchJob-main256642.908 ns1.00
ImmediateMismatchJob-PR10249.128 ns1.48
ImmediateMismatchJob-main10246.153 ns1.00
NoMismatchJob-PR1024104.512 ns0.04
NoMismatchJob-main10242,534.292 ns1.00

It's clearly a tradeoff:

  • for all strings with immediate mismatch, the method has regressed by 2-3ns
  • same goes for very short strings with no mismatch
  • for other cases, when there is no mismatch the longer the string the bigger the gain
Author:adamsitnik
Assignees:-
Labels:

area-System.Memory, tenet-performance

Milestone:7.0.0

Comment threadsrc/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs Outdated
@danmoseley

Copy link
Copy Markdown
Contributor

Some pretty nice improvements!

@adamsitnik

Copy link
Copy Markdown
MemberAuthor

The CI did not start... I am going to close and re-open the PR

@adamsitnikadamsitnik reopened this Aug 11, 2022
@runfoapprunfoappBot mentioned this pull request Aug 11, 2022
case 3:
return IndexOfAnyExcept(span, values[0], values[1], values[2]);

case 4: // common for searching whitespaces

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: (don't restart CI just for this)

Suggested change
case4:// common for searching whitespaces
case4:// common for searching ASCII whitespaces

}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int ComputeIndex<T>(ref T searchSpace, ref T current, Vector128<T> notEquals) where T : struct, IEquatable<T>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There are many other methods in this type, whereas this "ComputeIndex" is only relevant to LastIndexOfExcept. Consider renaming it accordingly.

@stephentoubstephentoub left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!

@adamsitnik

Copy link
Copy Markdown
MemberAuthor

@stephentoub Since I currently can't merge #73768, I am going to merge this PR now and address your feedback later (renaming ComputeIndex to ComputeFirstIndex). Normally I would do it first, but we have limited time ;)

@adamsitnik
adamsitnik merged commit 49cb4ff into dotnet:mainAug 15, 2022
@ghostghost locked as resolved and limited conversation to collaborators Sep 15, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Memorytenet-performancePerformance related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@adamsitnik@danmoseley@stephentoub