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 JsonReaderHelper.IndexOfOrLessThan #40877

Closed
wants to merge 19 commits into from

Conversation

benaadams
Copy link
Member

@benaadams benaadams commented Aug 15, 2020

  • Update to use newer Sse2, Axv2 intrinsics; and add ARM as per the method it mimics (with changes) from SpanHelpers

  • Also add size optimization/simplification for wasm

x64 performance changes (up to +20% improvement)

better: 30, geomean: 1.113
worse: 1, geomean: 1.066
total diff: 31

| Slower                                                                           | diff/base | Base Median (ns) | Diff Median (ns) | Modality|
| -------------------------------------------------------------------------------- | ---------:| ----------------:| ----------------:| --------:|
| System.Text.Json.Serialization.Tests.ReadJson<SimpleStructWithProperties>.Deseri |      1.07 |           288.23 |           307.28 |         |

| Faster                                                                           | base/diff | Base Median (ns) | Diff Median (ns) | Modality|
| -------------------------------------------------------------------------------- | ---------:| ----------------:| ----------------:| --------:|
| System.Text.Json.Serialization.Tests.ReadJson<Dictionary<String, String>>.Deseri |      1.22 |         22031.18 |         18102.24 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Dictionary<String, String>>.Deseri |      1.20 |         21554.46 |         17944.26 |         |
| System.Text.Json.Serialization.Tests.ReadJson<MyEventsListerViewModel>.Deseriali |      1.20 |        341085.15 |        284277.87 |         |
| System.Text.Json.Serialization.Tests.ReadJson<IndexViewModel>.DeserializeFromUtf |      1.19 |         29706.85 |         24903.98 |         |
| System.Text.Json.Serialization.Tests.ReadJson<MyEventsListerViewModel>.Deseriali |      1.19 |        330481.64 |        277947.73 |         |
| System.Text.Json.Serialization.Tests.ReadJson<MyEventsListerViewModel>.Deseriali |      1.19 |        399397.91 |        336085.63 |         |
| System.Text.Json.Serialization.Tests.ReadJson<IndexViewModel>.DeserializeFromStr |      1.18 |         31986.63 |         27064.34 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Dictionary<String, String>>.Deseri |      1.18 |         23919.94 |         20268.43 |         |
| System.Text.Json.Serialization.Tests.ReadJson<IndexViewModel>.DeserializeFromStr |      1.18 |         31000.14 |         26348.41 |         |
| System.Text.Json.Serialization.Tests.ReadJson<LoginViewModel>.DeserializeFromStr |      1.15 |           522.04 |           454.92 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Hashtable>.DeserializeFromUtf8Byte |      1.12 |         68993.04 |         61636.12 |         |
| System.Text.Json.Serialization.Tests.ReadJson<HashSet<String>>.DeserializeFromUt |      1.10 |         12663.49 |         11477.42 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String,  |      1.10 |         78887.97 |         71927.75 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Hashtable>.DeserializeFromStream   |      1.10 |         69968.66 |         63797.29 |         |
| System.Text.Json.Serialization.Tests.ReadJson<LoginViewModel>.DeserializeFromStr |      1.09 |           763.93 |           698.34 |         |
| System.Text.Json.Serialization.Tests.ReadJson<HashSet<String>>.DeserializeFromSt |      1.09 |         12745.33 |         11734.38 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableDictionary<String, String |      1.09 |         48372.57 |         44572.25 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ArrayList>.DeserializeFromStream   |      1.09 |         51673.60 |         47617.28 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableDictionary<String, String |      1.08 |         51226.78 |         47249.65 |         |
| System.Text.Json.Serialization.Tests.ReadJson<HashSet<String>>.DeserializeFromSt |      1.08 |         13979.59 |         12973.07 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableDictionary<String, String |      1.08 |         48102.61 |         44652.30 |         |
| System.Text.Json.Serialization.Tests.ReadJson<BinaryData>.DeserializeFromStream  |      1.07 |           807.95 |           755.26 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ArrayList>.DeserializeFromString   |      1.07 |         49947.46 |         46735.64 |         |
| System.Text.Json.Serialization.Tests.ReadJson<BinaryData>.DeserializeFromUtf8Byt |      1.07 |           488.59 |           458.07 |         |
| System.Text.Json.Serialization.Tests.ReadJson<LoginViewModel>.DeserializeFromUtf |      1.06 |           426.56 |           400.78 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String,  |      1.06 |         78155.94 |         73498.13 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Hashtable>.DeserializeFromString   |      1.06 |         67906.38 |         63896.07 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ArrayList>.DeserializeFromUtf8Byte |      1.06 |         50083.93 |         47157.52 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String,  |      1.05 |         73213.63 |         69703.93 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Int32>.DeserializeFromUtf8Bytes    |      1.03 |            90.42 |            87.57 |         |

/cc @kunalspathak @jeffhandley for the intrinsics

@benaadams benaadams changed the title Intrinsicify JsonReaderHelper.IndexOfOrLessThan Intrinsicify JsonReaderHelper.IndexOfOrLessThan [NoMerge] Aug 15, 2020
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ref byte AddByteOffset(ref byte start, nuint offset)
Copy link
Member

Choose a reason for hiding this comment

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

For the following methods I see this pattern quite often. Maybe it's time to make these a public api?

Yeah, they're still easy to type helpers, but repeated often enough. Furthermore there could be asserts that the reads are within bounds, etc.

Most similar issue I've found is #36182

@benaadams benaadams marked this pull request as ready for review August 15, 2020 20:30
@benaadams benaadams changed the title Intrinsicify JsonReaderHelper.IndexOfOrLessThan [NoMerge] Intrinsicify JsonReaderHelper.IndexOfOrLessThan Aug 15, 2020
@benaadams
Copy link
Member Author

better: 30, geomean: 1.113
worse: 1, geomean: 1.066
total diff: 31

| Slower                                                                           | diff/base | Base Median (ns) | Diff Median (ns) | Modality|
| -------------------------------------------------------------------------------- | ---------:| ----------------:| ----------------:| --------:|
| System.Text.Json.Serialization.Tests.ReadJson<SimpleStructWithProperties>.Deseri |      1.07 |           288.23 |           307.28 |         |

| Faster                                                                           | base/diff | Base Median (ns) | Diff Median (ns) | Modality|
| -------------------------------------------------------------------------------- | ---------:| ----------------:| ----------------:| --------:|
| System.Text.Json.Serialization.Tests.ReadJson<Dictionary<String, String>>.Deseri |      1.22 |         22031.18 |         18102.24 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Dictionary<String, String>>.Deseri |      1.20 |         21554.46 |         17944.26 |         |
| System.Text.Json.Serialization.Tests.ReadJson<MyEventsListerViewModel>.Deseriali |      1.20 |        341085.15 |        284277.87 |         |
| System.Text.Json.Serialization.Tests.ReadJson<IndexViewModel>.DeserializeFromUtf |      1.19 |         29706.85 |         24903.98 |         |
| System.Text.Json.Serialization.Tests.ReadJson<MyEventsListerViewModel>.Deseriali |      1.19 |        330481.64 |        277947.73 |         |
| System.Text.Json.Serialization.Tests.ReadJson<MyEventsListerViewModel>.Deseriali |      1.19 |        399397.91 |        336085.63 |         |
| System.Text.Json.Serialization.Tests.ReadJson<IndexViewModel>.DeserializeFromStr |      1.18 |         31986.63 |         27064.34 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Dictionary<String, String>>.Deseri |      1.18 |         23919.94 |         20268.43 |         |
| System.Text.Json.Serialization.Tests.ReadJson<IndexViewModel>.DeserializeFromStr |      1.18 |         31000.14 |         26348.41 |         |
| System.Text.Json.Serialization.Tests.ReadJson<LoginViewModel>.DeserializeFromStr |      1.15 |           522.04 |           454.92 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Hashtable>.DeserializeFromUtf8Byte |      1.12 |         68993.04 |         61636.12 |         |
| System.Text.Json.Serialization.Tests.ReadJson<HashSet<String>>.DeserializeFromUt |      1.10 |         12663.49 |         11477.42 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String,  |      1.10 |         78887.97 |         71927.75 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Hashtable>.DeserializeFromStream   |      1.10 |         69968.66 |         63797.29 |         |
| System.Text.Json.Serialization.Tests.ReadJson<LoginViewModel>.DeserializeFromStr |      1.09 |           763.93 |           698.34 |         |
| System.Text.Json.Serialization.Tests.ReadJson<HashSet<String>>.DeserializeFromSt |      1.09 |         12745.33 |         11734.38 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableDictionary<String, String |      1.09 |         48372.57 |         44572.25 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ArrayList>.DeserializeFromStream   |      1.09 |         51673.60 |         47617.28 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableDictionary<String, String |      1.08 |         51226.78 |         47249.65 |         |
| System.Text.Json.Serialization.Tests.ReadJson<HashSet<String>>.DeserializeFromSt |      1.08 |         13979.59 |         12973.07 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableDictionary<String, String |      1.08 |         48102.61 |         44652.30 |         |
| System.Text.Json.Serialization.Tests.ReadJson<BinaryData>.DeserializeFromStream  |      1.07 |           807.95 |           755.26 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ArrayList>.DeserializeFromString   |      1.07 |         49947.46 |         46735.64 |         |
| System.Text.Json.Serialization.Tests.ReadJson<BinaryData>.DeserializeFromUtf8Byt |      1.07 |           488.59 |           458.07 |         |
| System.Text.Json.Serialization.Tests.ReadJson<LoginViewModel>.DeserializeFromUtf |      1.06 |           426.56 |           400.78 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String,  |      1.06 |         78155.94 |         73498.13 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Hashtable>.DeserializeFromString   |      1.06 |         67906.38 |         63896.07 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ArrayList>.DeserializeFromUtf8Byte |      1.06 |         50083.93 |         47157.52 |         |
| System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String,  |      1.05 |         73213.63 |         69703.93 |         |
| System.Text.Json.Serialization.Tests.ReadJson<Int32>.DeserializeFromUtf8Bytes    |      1.03 |            90.42 |            87.57 |         |

@benaadams
Copy link
Member Author

Libraries Test Run release coreclr OSX x64 Debug failed: AcceptV4BoundToAnyV6_Success #40913

// Same as method as above
matches = Avx2.MoveMask(
Avx2.Or(
Avx2.CompareGreaterThan(
Copy link
Member Author

@benaadams benaadams Aug 17, 2020

Choose a reason for hiding this comment

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

Note: Avx2 doesn't have less than so arguments are switched for greater than

Avx2.Or(
Avx2.CompareGreaterThan(
valuesLessThan,
Avx2.Subtract(search, Vector256.Create((byte)0x80)).AsSByte()).AsByte(),
Copy link
Member Author

@benaadams benaadams Aug 17, 2020

Choose a reason for hiding this comment

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

Note: Also CompareGreaterThan is only sbyte (and CompareLessThan on Sse2), so subtract 0x80 before casting and doing the compare to keep the order correct

@benaadams benaadams force-pushed the IndexOfOrLessThan branch 3 times, most recently from 7ffc080 to 3a10197 Compare August 17, 2020 16:41
@benaadams
Copy link
Member Author

benaadams commented Aug 17, 2020

Can't workout the linker test issues :(

dotnet build /t:PublishTrimmed /nr:false /warnaserror -p:configuration=Release
/Users/runner/work/1/s/.dotnet/sdk/5.0.100-preview.8.20362.3/NuGet.targets(128,5): 
Invalid restore input. Invalid target framework 'unsupported'. Input files:
 /Users/runner/work/1/s/src/libraries/System.Text.Json/src/System.Text.Json.csproj.
 [/Users/runner/work/1/s/artifacts/bin/trimmingTests/projects/Microsoft.Extensions.Logging.Console.TrimmingTests/
  AddConsoleFormatterTests/osx-x64/project.csproj] [/Users/runner/work/1/s/src/libraries/Microsoft.Extensions.Logging.Console/tests/TrimmingTests/
  Microsoft.Extensions.Logging.Console.TrimmingTests.proj]

@layomia
Copy link
Contributor

layomia commented Aug 19, 2020

Taking a look now.

@benaadams
Copy link
Member Author

@layomia when I add the browser type $(NetCoreAppCurrent)-Browser to <TargetFrameworks> then the linker tests for TrimmingTests/Microsoft.Extensions.Logging.Console.TrimmingTests.proj which imports System.Text.Json start failing with

Errors
    NuGet.targets(128,5): Invalid restore input. Invalid target framework 'unsupported'. 
    Input files:  
        src/libraries/System.Text.Json/src/System.Text.Json.csproj.          
        trimmingTests/projects/Microsoft.Extensions.Logging.Console.TrimmingTests/AddConsoleFormatterTests/linux-x64/project.csproj               
        src/libraries/Microsoft.Extensions.Logging.Console/tests/TrimmingTests/Microsoft.Extensions.Logging.Console.TrimmingTests.proj

On Windows, Linux and OSX. However doesn't seem to provide much helpful detail in the binlog as to why its becoming "unsupported" :(

@benaadams
Copy link
Member Author

So the unsupported bit is probably NuGet/Home#5413; which is what NuGet outputs for an unknown framework

@benaadams
Copy link
Member Author

Current working idea looking at other build is need to override NuGet.targets with NuGet.RestoreEx.targets somehow

Overriding target "Restore" in project "/__w/1/s/.dotnet/sdk/5.0.100-preview.8.20362.3/NuGet.targets"
 with target "Restore" from project "/__w/1/s/.dotnet/sdk/5.0.100-preview.8.20362.3/NuGet.RestoreEx.targets"

Copy link
Contributor

@layomia layomia left a comment

Choose a reason for hiding this comment

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

I tried out some changes wrt wasm/non-wasm builds, pls see if this helps - layomia@137ac47. We don't run the linker tests specifically on wasm builds afaict so I don't think any linker test changes are needed in this PR.

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TargetFrameworks>$(NetCoreAppCurrent);netstandard2.0;netcoreapp3.0;net461</TargetFrameworks>
<TargetFrameworks>$(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Browser;netstandard2.0;netcoreapp3.0;net461</TargetFrameworks>
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this change needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it will only output an AnyCPU assembly if either the TargetFrameworks doesn't have browser or the Architectures aren't included to have wasm which will mean '$(TargetArchitecture)' == 'wasm' will never be true?

@benaadams
Copy link
Member Author

We don't run the linker tests specifically on wasm builds afaict so I don't think any linker test changes are needed in this PR.

So its looks like NuGet chokes on <TargetFrameworks>net5.0;net5.0-Browser;...; so the arcade build tools normalize that before restore to <TargetFrameworks>net5.0;... so NuGet doesn't fail.

However the linker tests look to shell out to a basic build which uses the standard restore causing them to fail for all frameworks (where this changed .csproj is included)

@benaadams
Copy link
Member Author

🥳

Going to close this PR and open a fresh one as its a bit of a tire fire

@benaadams
Copy link
Member Author

Opened #41097

@benaadams benaadams closed this Aug 20, 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.

5 participants