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

Switch JsonReaderHelper.IndexOfQuoteOrAnyControlOrBackSlash to use IndexOfAnyValues #82789

Merged
merged 3 commits into from
Mar 8, 2023

Conversation

stephentoub
Copy link
Member

No description provided.

@stephentoub stephentoub added NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) area-System.Text.Json labels Feb 28, 2023
@stephentoub stephentoub added this to the 8.0.0 milestone Feb 28, 2023
@ghost ghost assigned stephentoub Feb 28, 2023
@stephentoub
Copy link
Member Author

/benchmark list

@ghost
Copy link

ghost commented Feb 28, 2023

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

Issue Details

null

Author: stephentoub
Assignees: -
Labels:

NO-MERGE, area-System.Text.Json

Milestone: 8.0.0

@pr-benchmarks
Copy link

pr-benchmarks bot commented Feb 28, 2023

Crank Pull Request Bot

/benchmark <benchmark[,...]> <profile[,...]> <component,[...]> <arguments>

Benchmarks:

  • microbenchmarks: .NET Performance micro benchmarks (default filter: "LinqBenchmarks", change by adding "--variable filter=...")
  • plaintext: TechEmpower Plaintext Scenario - ASP.NET Platform implementation
  • json: TechEmpower JSON Scenario - ASP.NET Platform implementation
  • fortunes: TechEmpower Fortunes Scenario - ASP.NET Platform implementation
  • httpclient-kestrel-configured: HttpClient Benchmark (default: HTTP/1.1 GET 8K)

Profiles:

  • aspnet-perf-win: Intel/Windows 12 Cores
  • aspnet-citrine-win: Intel/Windows 28 Cores

Components:

  • runtime
  • libs

Arguments: any additional arguments to pass through to crank, e.g. --variable name=value

@stephentoub
Copy link
Member Author

/benchmark microbenchmarks aspnet-perf-win libs --variable filter="System.Text.Json.Tests*"

@pr-benchmarks
Copy link

pr-benchmarks bot commented Feb 28, 2023

Benchmark started for microbenchmarks on aspnet-perf-win with libs and arguments --variable filter="System.Text.Json.Tests*". Logs: link

Copy link
Member

@MihaZupan MihaZupan left a comment

Choose a reason for hiding this comment

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

For this set of values, we have fast implementations for x86 and ARM64 right now.

Do you know what the performance numbers look like on WASM? I would imagine this will regress @radekdoulik's improvements from #81758.

@stephentoub
Copy link
Member Author

Do you know what the performance numbers look like on WASM? I would imagine this will regress @radekdoulik's improvements from #81758.

I don't know. But if this regresses wasm, presumably many of the other 50+ places we have that use IndexOfAnyValues are also degraded on wasm. What would it take to make this work well on wasm?

@stephentoub
Copy link
Member Author

Also, if a) this does regress wasm, and b) we for whatever reason can't extend this implementation in IndexOfAnyValues to optimize wasm in addition to x86/arm, I'd still want to make this change to System.Text.Json, and instead augment IndexOfAnyValues to have a specialized implementation for this pattern, effectively moving the implementation from json into corelib. If we're going to carry it around, we might as well get the benefits from it with anyone else who happens to need something similar.

@MihaZupan
Copy link
Member

What would it take to make this work well on wasm?

Assuming the browser ends up translating the WASM instructions into something reasonable, it shouldn't be all that difficult to extend IndexOfAnyAsciiSearcher for PackedSimd.
The main places that would need to change are how we combine two Vector128<ushort> into a Vector128<byte> and the core lookup logic. All the rest is just shared boilerplate.

It seems like a worthwhile investment given the many places that would benefit through IndexOfAnyValues.

@stephentoub
Copy link
Member Author

The WASM issue aside (which we need to address), here are the crank results from running the benchmarks. I don't see anything that stands out as being problematic from switching to use IndexOfAnyValues:

benchmark mean (base) mean (pr) ratio
Perf_Base64.WriteByteArrayAsBase64_HeavyEscaping(NumberOfBytes: 100) 42.81 ns 42.68 ns 1.00
Perf_Base64.WriteByteArrayAsBase64_HeavyEscaping(NumberOfBytes: 1000) 120.6 ns 128.0 ns 1.06
Perf_Base64.WriteByteArrayAsBase64_NoEscaping(NumberOfBytes: 100) 43.32 ns 43.56 ns 1.01
Perf_Base64.WriteByteArrayAsBase64_NoEscaping(NumberOfBytes: 1000) 124.7 ns 126.7 ns 1.02
Perf_Basic.WriteBasicUtf16(Formatted: False, SkipValidation: False, DataSize: 10) 490.4 ns 490.9 ns 1.00
Perf_Basic.WriteBasicUtf16(Formatted: False, SkipValidation: False, DataSize: 100000) 1.3 ms 1.3 ms 1.00
Perf_Basic.WriteBasicUtf16(Formatted: False, SkipValidation: True, DataSize: 10) 464.9 ns 456.3 ns 0.98
Perf_Basic.WriteBasicUtf16(Formatted: False, SkipValidation: True, DataSize: 100000) 1.2 ms 1.2 ms 1.00
Perf_Basic.WriteBasicUtf16(Formatted: True, SkipValidation: False, DataSize: 10) 632.3 ns 629.2 ns 1.00
Perf_Basic.WriteBasicUtf16(Formatted: True, SkipValidation: False, DataSize: 100000) 1.6 ms 1.6 ms 0.99
Perf_Basic.WriteBasicUtf16(Formatted: True, SkipValidation: True, DataSize: 10) 597.6 ns 587.3 ns 0.98
Perf_Basic.WriteBasicUtf16(Formatted: True, SkipValidation: True, DataSize: 100000) 1.5 ms 1.5 ms 1.00
Perf_Basic.WriteBasicUtf8(Formatted: False, SkipValidation: False, DataSize: 10) 435.7 ns 424.1 ns 0.97
Perf_Basic.WriteBasicUtf8(Formatted: False, SkipValidation: False, DataSize: 100000) 1.3 ms 1.3 ms 1.00
Perf_Basic.WriteBasicUtf8(Formatted: False, SkipValidation: True, DataSize: 10) 406.2 ns 386.6 ns 0.95
Perf_Basic.WriteBasicUtf8(Formatted: False, SkipValidation: True, DataSize: 100000) 1.2 ms 1.2 ms 1.00
Perf_Basic.WriteBasicUtf8(Formatted: True, SkipValidation: False, DataSize: 10) 560.6 ns 552.7 ns 0.99
Perf_Basic.WriteBasicUtf8(Formatted: True, SkipValidation: False, DataSize: 100000) 1.6 ms 1.6 ms 1.03
Perf_Basic.WriteBasicUtf8(Formatted: True, SkipValidation: True, DataSize: 10) 535.9 ns 530.6 ns 0.99
Perf_Basic.WriteBasicUtf8(Formatted: True, SkipValidation: True, DataSize: 100000) 1.5 ms 1.5 ms 1.01
Perf_Booleans.WriteBooleans(Formatted: False, SkipValidation: False) 1.2 ms 1.1 ms 0.98
Perf_Booleans.WriteBooleans(Formatted: False, SkipValidation: True) 1.1 ms 1.1 ms 1.07
Perf_Booleans.WriteBooleans(Formatted: True, SkipValidation: False) 1.4 ms 1.4 ms 1.00
Perf_Booleans.WriteBooleans(Formatted: True, SkipValidation: True) 1.4 ms 1.3 ms 0.95
Perf_Ctor.Ctor(Formatted: False, SkipValidation: False) 10.03 ns 10.19 ns 1.02
Perf_Ctor.Ctor(Formatted: False, SkipValidation: True) 9.405 ns 9.454 ns 1.01
Perf_Ctor.Ctor(Formatted: True, SkipValidation: False) 9.200 ns 9.663 ns 1.05
Perf_Ctor.Ctor(Formatted: True, SkipValidation: True) 10.03 ns 11.99 ns 1.20
Perf_DateTimes.WriteDateTimes(Formatted: False, SkipValidation: False) 2.5 ms 2.5 ms 1.00
Perf_DateTimes.WriteDateTimes(Formatted: False, SkipValidation: True) 2.5 ms 2.5 ms 1.00
Perf_DateTimes.WriteDateTimes(Formatted: True, SkipValidation: False) 2.9 ms 2.9 ms 1.01
Perf_DateTimes.WriteDateTimes(Formatted: True, SkipValidation: True) 2.7 ms 2.8 ms 1.03
Perf_Deep.WriteDeepUtf16(Formatted: False, SkipValidation: False) 3.1 ms 3.1 ms 1.00
Perf_Deep.WriteDeepUtf16(Formatted: False, SkipValidation: True) 3.0 ms 3.0 ms 1.00
Perf_Deep.WriteDeepUtf16(Formatted: True, SkipValidation: False) 18.7 ms 18.7 ms 1.00
Perf_Deep.WriteDeepUtf16(Formatted: True, SkipValidation: True) 18.9 ms 19.0 ms 1.00
Perf_Deep.WriteDeepUtf8(Formatted: False, SkipValidation: False) 3.1 ms 3.2 ms 1.04
Perf_Deep.WriteDeepUtf8(Formatted: False, SkipValidation: True) 2.9 ms 3.0 ms 1.01
Perf_Deep.WriteDeepUtf8(Formatted: True, SkipValidation: False) 18.7 ms 18.8 ms 1.00
Perf_Deep.WriteDeepUtf8(Formatted: True, SkipValidation: True) 18.8 ms 18.8 ms 1.00
Perf_Depth.ReadSpanEmptyLoop(Depth: 1) 50.94 ns 50.47 ns 0.99
Perf_Depth.ReadSpanEmptyLoop(Depth: 512) 13.8 μs 13.1 μs 0.95
Perf_Depth.ReadSpanEmptyLoop(Depth: 64) 1.6 μs 1.6 μs 0.99
Perf_Depth.ReadSpanEmptyLoop(Depth: 65) 1.6 μs 1.6 μs 0.99
Perf_Doubles.WriteDoubles(Formatted: False, SkipValidation: False) 14.4 ms 14.4 ms 1.00
Perf_Doubles.WriteDoubles(Formatted: False, SkipValidation: True) 14.3 ms 14.4 ms 1.01
Perf_Doubles.WriteDoubles(Formatted: True, SkipValidation: False) 15.2 ms 15.1 ms 1.00
Perf_Doubles.WriteDoubles(Formatted: True, SkipValidation: True) 15.0 ms 15.1 ms 1.01
Perf_Get.GetBoolean 70.66 ns 71.84 ns 1.02
Perf_Get.GetByte 383.2 ns 385.2 ns 1.01
Perf_Get.GetDateTime 2.8 μs 2.8 μs 1.00
Perf_Get.GetDateTimeOffset 3.7 μs 3.7 μs 1.00
Perf_Get.GetDecimal 2.8 μs 2.9 μs 1.02
Perf_Get.GetDouble 2.8 μs 2.8 μs 1.00
Perf_Get.GetGuid 2.8 μs 2.7 μs 0.95
Perf_Get.GetInt16 420.0 ns 419.2 ns 1.00
Perf_Get.GetInt32 440.6 ns 440.6 ns 1.00
Perf_Get.GetInt64 462.7 ns 463.6 ns 1.00
Perf_Get.GetSByte 419.0 ns 409.7 ns 0.98
Perf_Get.GetSingle 2.8 μs 2.9 μs 1.00
Perf_Get.GetString 2.0 μs 2.0 μs 0.99
Perf_Get.GetUInt16 377.5 ns 380.4 ns 1.01
Perf_Get.GetUInt32 379.3 ns 377.5 ns 1.00
Perf_Get.GetUInt64 375.7 ns 375.7 ns 1.00
Perf_Guids.WriteGuids(Formatted: False, SkipValidation: False) 1.3 ms 1.3 ms 1.01
Perf_Guids.WriteGuids(Formatted: False, SkipValidation: True) 1.3 ms 1.2 ms 1.00
Perf_Guids.WriteGuids(Formatted: True, SkipValidation: False) 1.5 ms 1.5 ms 1.00
Perf_Guids.WriteGuids(Formatted: True, SkipValidation: True) 1.5 ms 1.5 ms 1.00
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: BroadTree) 7.3 μs 7.3 μs 1.00
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: DeepTree) 7.3 μs 7.3 μs 1.00
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: HelloWorld) 103.8 ns 105.4 ns 1.02
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: Json400B) 601.5 ns 605.7 ns 1.01
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: Json40KB) 44.9 μs 45.7 μs 1.02
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: Json4KB) 4.5 μs 4.6 μs 1.01
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: LotsOfNumbers) 2.0 μs 2.0 μs 1.00
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: LotsOfStrings) 1.2 μs 1.1 μs 0.96
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: BroadTree) 4.4 μs 4.3 μs 0.97
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: DeepTree) 2.1 μs 2.1 μs 0.98
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: HelloWorld) 95.45 ns 92.78 ns 0.97
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: Json400B) 442.4 ns 442.7 ns 1.00
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: Json40KB) 29.3 μs 28.6 μs 0.98
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: Json4KB) 3.0 μs 2.9 μs 0.99
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: LotsOfNumbers) 1.5 μs 1.5 μs 1.00
Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: LotsOfStrings) 791.9 ns 785.9 ns 0.99
Perf_Reader.ReadReturnBytes(IsDataCompact: False, TestCase: BroadTree) 7.6 μs 7.7 μs 1.01
Perf_Reader.ReadReturnBytes(IsDataCompact: False, TestCase: DeepTree) 7.1 μs 7.5 μs 1.06
Perf_Reader.ReadReturnBytes(IsDataCompact: False, TestCase: HelloWorld) 62.63 ns 58.81 ns 0.94
Perf_Reader.ReadReturnBytes(IsDataCompact: False, TestCase: Json400B) 577.6 ns 600.7 ns 1.04
Perf_Reader.ReadReturnBytes(IsDataCompact: False, TestCase: Json40KB) 49.6 μs 50.1 μs 1.01
Perf_Reader.ReadReturnBytes(IsDataCompact: False, TestCase: Json4KB) 4.8 μs 4.9 μs 1.01
Perf_Reader.ReadReturnBytes(IsDataCompact: False, TestCase: LotsOfNumbers) 1.9 μs 2.0 μs 1.01
Perf_Reader.ReadReturnBytes(IsDataCompact: False, TestCase: LotsOfStrings) 1.4 μs 1.4 μs 0.96
Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase: BroadTree) 4.8 μs 4.6 μs 0.95
Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase: DeepTree) 2.3 μs 2.2 μs 0.97
Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase: HelloWorld) 59.75 ns 56.34 ns 0.94
Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase: Json400B) 438.2 ns 436.4 ns 1.00
Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase: Json40KB) 34.7 μs 33.4 μs 0.96
Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase: Json4KB) 3.4 μs 3.3 μs 0.96
Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase: LotsOfNumbers) 1.5 μs 1.5 μs 0.96
Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase: LotsOfStrings) 907.2 ns 906.9 ns 1.00
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: BroadTree) 6.9 μs 6.9 μs 0.99
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: DeepTree) 7.2 μs 7.1 μs 0.98
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: HelloWorld) 57.95 ns 58.18 ns 1.00
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: Json400B) 523.7 ns 533.2 ns 1.02
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: Json40KB) 44.3 μs 43.2 μs 0.98
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: Json4KB) 4.3 μs 4.3 μs 0.99
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: LotsOfNumbers) 1.7 μs 1.7 μs 1.01
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: False, TestCase: LotsOfStrings) 1.1 μs 1.2 μs 1.06
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: BroadTree) 4.1 μs 3.9 μs 0.96
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: DeepTree) 2.0 μs 1.9 μs 0.95
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: HelloWorld) 55.84 ns 56.23 ns 1.01
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: Json400B) 371.9 ns 366.6 ns 0.99
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: Json40KB) 28.2 μs 27.2 μs 0.96
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: Json4KB) 2.8 μs 2.7 μs 0.97
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: LotsOfNumbers) 1.3 μs 1.2 μs 0.97
Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact: True, TestCase: LotsOfStrings) 734.4 ns 727.7 ns 0.99
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestCase: BroadTree) 6.9 μs 7.1 μs 1.03
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestCase: DeepTree) 7.1 μs 7.0 μs 1.00
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestCase: HelloWorld) 53.65 ns 53.97 ns 1.01
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestCase: Json400B) 513.1 ns 516.8 ns 1.01
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestCase: Json40KB) 43.7 μs 43.2 μs 0.99
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestCase: Json4KB) 4.3 μs 4.3 μs 0.99
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestCase: LotsOfNumbers) 1.7 μs 1.7 μs 1.00
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestCase: LotsOfStrings) 1.2 μs 1.1 μs 0.96
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCase: BroadTree) 4.0 μs 3.9 μs 0.97
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCase: DeepTree) 2.0 μs 1.9 μs 0.96
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCase: HelloWorld) 50.36 ns 49.77 ns 0.99
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCase: Json400B) 363.6 ns 368.4 ns 1.01
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCase: Json40KB) 28.2 μs 27.4 μs 0.97
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCase: Json4KB) 2.9 μs 2.7 μs 0.96
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCase: LotsOfNumbers) 1.3 μs 1.2 μs 0.99
Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCase: LotsOfStrings) 730.2 ns 740.5 ns 1.01
Perf_Segment.ReadMultiSegmentSequence(segmentSize: 4096, TestCase: Json400KB) 456.0 μs 461.2 μs 1.01
Perf_Segment.ReadMultiSegmentSequence(segmentSize: 4096, TestCase: Json40KB) 45.3 μs 45.8 μs 1.01
Perf_Segment.ReadMultiSegmentSequence(segmentSize: 4096, TestCase: Json4KB) 4.6 μs 4.6 μs 1.01
Perf_Segment.ReadMultiSegmentSequence(segmentSize: 8192, TestCase: Json400KB) 454.6 μs 458.7 μs 1.01
Perf_Segment.ReadMultiSegmentSequence(segmentSize: 8192, TestCase: Json40KB) 45.6 μs 45.6 μs 1.00
Perf_Segment.ReadMultiSegmentSequence(segmentSize: 8192, TestCase: Json4KB) 4.3 μs 4.4 μs 1.01
Perf_Segment.ReadMultiSegmentSequenceUsingSpan(segmentSize: 4096, TestCase: Json400KB) 443.9 μs 442.8 μs 1.00
Perf_Segment.ReadMultiSegmentSequenceUsingSpan(segmentSize: 4096, TestCase: Json40KB) 44.5 μs 44.9 μs 1.01
Perf_Segment.ReadMultiSegmentSequenceUsingSpan(segmentSize: 4096, TestCase: Json4KB) 4.5 μs 4.5 μs 0.99
Perf_Segment.ReadMultiSegmentSequenceUsingSpan(segmentSize: 8192, TestCase: Json400KB) 441.8 μs 438.4 μs 0.99
Perf_Segment.ReadMultiSegmentSequenceUsingSpan(segmentSize: 8192, TestCase: Json40KB) 44.2 μs 43.8 μs 0.99
Perf_Segment.ReadMultiSegmentSequenceUsingSpan(segmentSize: 8192, TestCase: Json4KB) 4.4 μs 4.4 μs 0.99
Perf_Segment.ReadSingleSegmentSequence(TestCase: Json400KB) 435.7 μs 437.7 μs 1.00
Perf_Segment.ReadSingleSegmentSequence(TestCase: Json40KB) 43.5 μs 43.3 μs 0.99
Perf_Segment.ReadSingleSegmentSequence(TestCase: Json4KB) 4.3 μs 4.3 μs 1.00
Perf_Segment.ReadSingleSegmentSequenceByN(numberOfBytes: 4096, TestCase: Json400KB) 442.2 μs 440.2 μs 1.00
Perf_Segment.ReadSingleSegmentSequenceByN(numberOfBytes: 4096, TestCase: Json40KB) 44.0 μs 43.9 μs 1.00
Perf_Segment.ReadSingleSegmentSequenceByN(numberOfBytes: 4096, TestCase: Json4KB) 4.4 μs 4.3 μs 0.97
Perf_Segment.ReadSingleSegmentSequenceByN(numberOfBytes: 8192, TestCase: Json400KB) 438.4 μs 434.9 μs 0.99
Perf_Segment.ReadSingleSegmentSequenceByN(numberOfBytes: 8192, TestCase: Json40KB) 43.9 μs 43.3 μs 0.99
Perf_Segment.ReadSingleSegmentSequenceByN(numberOfBytes: 8192, TestCase: Json4KB) 4.4 μs 4.3 μs 0.98
Perf_Strings.WriteStringsUtf16(Formatted: False, SkipValidation: False, Escaped: AllEscaped) 58.1 ms 55.1 ms 0.95
Perf_Strings.WriteStringsUtf16(Formatted: False, SkipValidation: False, Escaped: NoneEscaped) 5.0 ms 5.0 ms 1.01
Perf_Strings.WriteStringsUtf16(Formatted: False, SkipValidation: False, Escaped: OneEscaped) 8.5 ms 8.6 ms 1.01
Perf_Strings.WriteStringsUtf16(Formatted: False, SkipValidation: True, Escaped: AllEscaped) 57.4 ms 54.8 ms 0.95
Perf_Strings.WriteStringsUtf16(Formatted: False, SkipValidation: True, Escaped: NoneEscaped) 4.9 ms 4.9 ms 1.00
Perf_Strings.WriteStringsUtf16(Formatted: False, SkipValidation: True, Escaped: OneEscaped) 8.4 ms 8.4 ms 1.00
Perf_Strings.WriteStringsUtf16(Formatted: True, SkipValidation: False, Escaped: AllEscaped) 57.2 ms 55.4 ms 0.97
Perf_Strings.WriteStringsUtf16(Formatted: True, SkipValidation: False, Escaped: NoneEscaped) 5.3 ms 5.3 ms 1.01
Perf_Strings.WriteStringsUtf16(Formatted: True, SkipValidation: False, Escaped: OneEscaped) 8.9 ms 9.0 ms 1.01
Perf_Strings.WriteStringsUtf16(Formatted: True, SkipValidation: True, Escaped: AllEscaped) 57.4 ms 55.0 ms 0.96
Perf_Strings.WriteStringsUtf16(Formatted: True, SkipValidation: True, Escaped: NoneEscaped) 5.3 ms 5.2 ms 0.98
Perf_Strings.WriteStringsUtf16(Formatted: True, SkipValidation: True, Escaped: OneEscaped) 8.9 ms 8.7 ms 0.98
Perf_Strings.WriteStringsUtf8(Formatted: False, SkipValidation: False, Escaped: AllEscaped) 52.1 ms 48.8 ms 0.94
Perf_Strings.WriteStringsUtf8(Formatted: False, SkipValidation: False, Escaped: NoneEscaped) 3.4 ms 3.4 ms 1.01
Perf_Strings.WriteStringsUtf8(Formatted: False, SkipValidation: False, Escaped: OneEscaped) 6.0 ms 6.1 ms 1.02
Perf_Strings.WriteStringsUtf8(Formatted: False, SkipValidation: True, Escaped: AllEscaped) 52.0 ms 51.5 ms 0.99
Perf_Strings.WriteStringsUtf8(Formatted: False, SkipValidation: True, Escaped: NoneEscaped) 3.4 ms 3.3 ms 0.95
Perf_Strings.WriteStringsUtf8(Formatted: False, SkipValidation: True, Escaped: OneEscaped) 5.9 ms 6.0 ms 1.02
Perf_Strings.WriteStringsUtf8(Formatted: True, SkipValidation: False, Escaped: AllEscaped) 53.2 ms 47.9 ms 0.90
Perf_Strings.WriteStringsUtf8(Formatted: True, SkipValidation: False, Escaped: NoneEscaped) 3.6 ms 3.7 ms 1.01
Perf_Strings.WriteStringsUtf8(Formatted: True, SkipValidation: False, Escaped: OneEscaped) 6.4 ms 6.4 ms 1.00
Perf_Strings.WriteStringsUtf8(Formatted: True, SkipValidation: True, Escaped: AllEscaped) 52.8 ms 48.2 ms 0.91
Perf_Strings.WriteStringsUtf8(Formatted: True, SkipValidation: True, Escaped: NoneEscaped) 3.6 ms 3.6 ms 1.00
Perf_Strings.WriteStringsUtf8(Formatted: True, SkipValidation: True, Escaped: OneEscaped) 6.3 ms 6.3 ms 1.00
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Allow, SegmentSize: 0, TestCase: LongMultiLine) 506.3 ns 506.3 ns 1.00
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Allow, SegmentSize: 0, TestCase: LongSingleLine) 119.1 ns 113.5 ns 0.95
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Allow, SegmentSize: 0, TestCase: ShortMultiLine) 63.22 ns 60.93 ns 0.96
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Allow, SegmentSize: 0, TestCase: ShortSingleLine) 64.12 ns 59.91 ns 0.93
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Allow, SegmentSize: 100, TestCase: LongMultiLine) 6.9 μs 6.8 μs 0.99
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Allow, SegmentSize: 100, TestCase: LongSingleLine) 418.6 ns 392.4 ns 0.94
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Allow, SegmentSize: 100, TestCase: ShortMultiLine) 68.08 ns 66.04 ns 0.97
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Allow, SegmentSize: 100, TestCase: ShortSingleLine) 66.66 ns 64.24 ns 0.96
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Skip, SegmentSize: 0, TestCase: LongMultiLine) 509.7 ns 504.8 ns 0.99
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Skip, SegmentSize: 0, TestCase: LongSingleLine) 107.4 ns 107.5 ns 1.00
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Skip, SegmentSize: 0, TestCase: ShortMultiLine) 62.32 ns 60.07 ns 0.96
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Skip, SegmentSize: 0, TestCase: ShortSingleLine) 62.47 ns 59.16 ns 0.95
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Skip, SegmentSize: 100, TestCase: LongMultiLine) 6.6 μs 6.6 μs 1.00
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Skip, SegmentSize: 100, TestCase: LongSingleLine) 381.1 ns 369.8 ns 0.97
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Skip, SegmentSize: 100, TestCase: ShortMultiLine) 68.36 ns 66.18 ns 0.97
Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing(CommentHandling: Skip, SegmentSize: 100, TestCase: ShortSingleLine) 66.32 ns 65.74 ns 0.99

@MihaZupan
Copy link
Member

MihaZupan commented Mar 2, 2023

(Obviously untested) this is about what it would take to make IndexOfAnyAsciiSearcher work for WASM: MihaZupan@b488533

The only missing thing is exposing the wasm_u8x16_narrow_i16x8 and wasm_i8x16_narrow_i16x8 intrinsics from PackedSimd (akin to Sse2.PackUnsignedSaturate and Sse2.PackSignedSaturate).
@radekdoulik what would it take to do that?

This is all assuming the behavior for these intrinsics (swizzle, narrow) is as described in https://emscripten.org/docs/porting/simd.html, https://github.com/WebAssembly/simd/blob/main/proposals/simd/SIMD.md.

Copy link
Member

@MihaZupan MihaZupan left a comment

Choose a reason for hiding this comment

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

I agree with #82789 (comment)
Even if we can't do #82789 (comment) for whatever reason, we can still move the "less than or 2 special" implementation into IndexOfAnyValues directly.

@MihaZupan
Copy link
Member

Running benchmarks again after #82866 with --threshold 2%, I'm seeing

summary:
better: 84, geomean: 1.053
worse: 18, geomean: 1.053
total diff: 102
All the numbers
Slower diff/base Base Median (ns) Diff Median (ns) Modality
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromString(Mode: 1.09 103.26 112.11
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromString(Mode: 1.08 107.92 116.64
System.Text.Json.Tests.Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing( 1.07 507.18 540.91 several?
System.Text.Json.Tests.Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing( 1.07 77.72 82.87
System.Text.Json.Tests.Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing( 1.06 463.52 493.22
System.Text.Json.Tests.Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact 1.06 75.33 79.81
System.Text.Json.Tests.Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing( 1.06 9440.05 9987.55
System.Text.Json.Tests.Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing( 1.06 76.74 81.15
System.Text.Json.Tests.Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestC 1.06 8490.02 8969.65
System.Text.Json.Tests.Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing( 1.05 83.81 88.07
System.Text.Json.Tests.Perf_Segment.ReadMultiSegmentSequence(segmentSize: 4096, 1.05 5602.16 5877.79
System.Text.Json.Tests.Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing( 1.05 78.27 81.84
System.Text.Json.Tests.Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: False, TestC 1.04 664.19 691.79
System.Text.Json.Tests.Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing( 1.04 9447.75 9818.12
System.Text.Json.Tests.Utf8JsonReaderCommentsTests.Utf8JsonReaderCommentParsing( 1.04 463.58 479.91 several?
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromReader( 1.03 570.71 590.59
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromStream( 1.03 667.94 690.90
System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String, 1.03 58565.47 60252.22
Faster base/diff Base Median (ns) Diff Median (ns) Modality
System.Text.Json.Tests.Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCa 1.19 68.48 57.47 several?
System.Text.Json.Reader.Tests.Perf_Base64.ReadBase64EncodedByteArray_NoEscaping( 1.14 75.79 66.20
System.Text.Json.Tests.Perf_Depth.ReadSpanEmptyLoop(Depth: 1) 1.11 65.04 58.69
System.Text.Json.Tests.Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: 1.11 122.57 110.70
System.Text.Json.Tests.Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase 1.10 76.79 69.77
System.Text.Json.Tests.Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: 1.10 588.96 535.57
System.Text.Json.Tests.Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: 1.08 3967.52 3681.74
System.Text.Json.Tests.Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase 1.08 1387.77 1289.44
System.Text.Json.Tests.Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact 1.08 39582.93 36794.19
System.Text.Json.Tests.Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCa 1.07 38871.00 36299.16
System.Text.Json.Tests.Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact 1.07 5628.85 5258.17
System.Text.Json.Serialization.Tests.ReadJson<Nullable>.Deserial 1.07 320.13 299.13
System.Text.Json.Tests.Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase 1.07 619.60 579.69
System.Text.Json.Tests.Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase 1.07 4777.58 4471.78 several?
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromUtf8Byte 1.07 17054.33 15975.66
System.Text.Json.Tests.Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCa 1.07 3853.77 3610.12
System.Text.Json.Tests.Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCa 1.07 1707.31 1599.53
System.Text.Json.Tests.Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: 1.07 40398.56 37851.58 several?
System.Text.Json.Serialization.Tests.ReadJson<Nullable>.Deserial 1.07 158.84 149.09
System.Text.Json.Tests.Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCa 1.07 931.30 874.21
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromString( 1.06 547.94 515.01
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromStream 1.06 1008.63 949.27
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromUtf8By 1.06 683.32 645.32
System.Text.Json.Tests.Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: 1.06 5746.07 5429.93
System.Text.Json.Tests.Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact 1.06 536.54 507.07 several?
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromRea 1.06 521.96 493.61
System.Text.Json.Serialization.Tests.ReadJson.Deseria 1.06 1427.32 1350.60
System.Text.Json.Serialization.Tests.ReadJson<Nullable>.Deserial 1.06 160.76 152.34
System.Text.Json.Tests.Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact 1.06 976.94 925.85
System.Text.Json.Serialization.Tests.ReadJson<Nullable>.Deserial 1.05 102.23 96.92
System.Text.Json.Serialization.Tests.ReadJson<Nullable>.Deserial 1.05 102.18 96.96
System.Text.Json.Tests.Perf_Segment.ReadMultiSegmentSequenceUsingSpan(segmentSiz 1.05 5684.11 5396.81
System.Text.Json.Reader.Tests.Perf_Base64.ReadBase64EncodedByteArray_NoEscaping( 1.05 273.42 259.76
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromStr 1.05 20830.67 19795.21
System.Text.Json.Serialization.Tests.ReadJson<Nullable>.Deserial 1.05 211.63 201.20
System.Text.Json.Serialization.Tests.ReadJson.Deseri 1.05 229.64 218.43
System.Text.Json.Tests.Perf_Depth.ReadSpanEmptyLoop(Depth: 65) 1.05 2149.56 2047.04
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromStream(Mo 1.05 1203.34 1146.31
System.Text.Json.Tests.Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact 1.05 5755.10 5489.33
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromStream 1.05 1018.71 971.91
System.Text.Json.Serialization.Tests.ReadJson.Deseria 1.05 999.29 953.84
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromRea 1.05 25728.76 24565.91
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromStream(Mode: 1.05 243.68 232.68
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromReader 1.05 1022.66 976.68
System.Text.Json.Tests.Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCa 1.05 5448.68 5205.13
System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String, 1.05 64763.66 61884.68
System.Text.Json.Tests.Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact 1.05 73.46 70.23
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromReader(Mo 1.05 1367.17 1308.07
System.Text.Json.Tests.Perf_Reader.ReadSingleSpanSequenceEmptyLoop(IsDataCompact 1.05 2630.46 2516.86
System.Text.Json.Serialization.Tests.ReadJson.Deseria 1.05 1412.28 1351.45
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromString(M 1.04 28189.12 26977.70
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromUtf8Byt 1.04 28194.15 27005.96
System.Text.Json.Serialization.Tests.ReadJson.Deseria 1.04 986.98 945.98
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromReade 1.04 849.57 814.29
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromReader(M 1.04 31901.62 30578.33
System.Text.Json.Tests.Perf_Reader.ReadSpanEmptyLoop(IsDataCompact: True, TestCa 1.04 512.00 490.98
System.Text.Json.Tests.Perf_Segment.ReadMultiSegmentSequence(segmentSize: 8192, 1.04 5630.78 5407.50
System.Text.Json.Tests.Perf_Segment.ReadSingleSegmentSequenceByN(numberOfBytes: 1.04 5648.38 5433.81
System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String, 1.04 61797.58 59476.28
System.Text.Json.Serialization.Tests.ReadJson.Deseri 1.04 421.80 406.05
System.Text.Json.Tests.Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: 1.04 930.03 895.76
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromReade 1.04 869.43 837.73
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromReader(Mo 1.04 1342.66 1293.87
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromStrin 1.04 584.98 563.76
System.Text.Json.Tests.Perf_Reader.ReadReturnBytes(IsDataCompact: True, TestCase 1.04 3190.52 3075.14
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromUtf8Byte 1.04 27842.92 26836.45
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromUtf8Bytes 1.03 881.26 851.71
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromUtf8B 1.03 516.72 499.49
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromRea 1.03 25602.80 24758.53
System.Text.Json.Tests.Perf_Depth.ReadSpanEmptyLoop(Depth: 512) 1.03 17227.06 16666.40
System.Text.Json.Serialization.Tests.ReadMissingAndCaseInsensitive.Bas 1.03 956.08 926.06
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromString 1.03 727.98 705.60
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromUtf 1.03 301.64 292.54
System.Text.Json.Tests.Perf_Reader.ReadMultiSpanSequenceEmptyLoop(IsDataCompact: 1.03 1486.43 1441.63
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromString(Mo 1.03 930.39 902.79
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromUtf8Byte 1.03 16797.70 16301.53
System.Text.Json.Serialization.Tests.ReadJson.Deseria 1.03 1230.65 1196.16
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromUtf 1.03 18786.01 18272.52
System.Text.Json.Serialization.Tests.ReadJson.Deseria 1.03 891.55 867.97
System.Text.Json.Serialization.Tests.ReadJson.Deseri 1.03 283.22 275.88
System.Text.Json.Serialization.Tests.ReadJson.Deseriali 1.03 218854.30 213183.02
System.Text.Json.Serialization.Tests.ReadJson<Nullable>.Deserial 1.03 208.25 202.86
System.Text.Json.Serialization.Tests.ReadJson.DeserializeFromReader(M 1.03 31272.55 30474.45
System.Text.Json.Serialization.Tests.ReadJson<ImmutableSortedDictionary<String, 1.02 59415.05 57990.88

@stephentoub
Copy link
Member Author

@radekdoulik, could we implement the necessary wasm primitives here to make this work?

@radekdoulik
Copy link
Member

@radekdoulik, could we implement the necessary wasm primitives here to make this work?

Yes. I will try to add it quickly.

@stephentoub
Copy link
Member Author

@radekdoulik, could we implement the necessary wasm primitives here to make this work?

Yes. I will try to add it quickly.

Excellent, thanks. That should help not only simplify and improve this case, but the other dozens of places IndexOfAnyValues is used and would then end up picking this ASCII-optimized searcher.

radekdoulik added a commit to radekdoulik/runtime that referenced this pull request Mar 7, 2023
Add them as internal as the approved API contains wrong methods for
these. dotnet#53730 (comment)

This will allow faster implementation of IndexOfAnyValues for wasm.
dotnet#82789 (comment)
radekdoulik added a commit that referenced this pull request Mar 7, 2023
* [wasm] Add narrow methods to PackedSimd

Add them as internal as the approved API contains wrong methods for
these. #53730 (comment)

This will allow faster implementation of IndexOfAnyValues for wasm.
#82789 (comment)

* Fix build
Copy link
Member

@radekdoulik radekdoulik left a comment

Choose a reason for hiding this comment

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

LGTM

@stephentoub stephentoub removed the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Mar 8, 2023
@stephentoub stephentoub merged commit ada0379 into dotnet:main Mar 8, 2023
@stephentoub stephentoub deleted the jsonindexofany branch March 8, 2023 14:12
@ghost ghost locked as resolved and limited conversation to collaborators Apr 7, 2023
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.

3 participants