Skip to content

Conversation

@russcam
Copy link
Contributor

@russcam russcam commented Jun 11, 2018

This PR introduces some performance improvements to 6.x

  • remove string allocations when creating a Stream from a JToken by writing token to stream directly
  • remove the need to read the response into bytes to check the length, by checking the length of the stream directly
  • lazily evaluate whether the internal serializer is being used as the source (document) serializer, to avoid the performance costs associated with SourceConverter
  • Add RecyclableMemoryStreamFactory to pool byte buffers for streams

BenchmarkDotNet results

Comparing 5.6.2, 6.1.0 and 6.x (this branch).

Note that these use InMemoryConnection to return a fixed set of bytes.

Search returning 100 documents

BenchmarkDotNet=v0.10.14.585-nightly, OS=Windows 10.0.16299.371 (1709/FallCreatorsUpdate/Redstone3)
Intel Core i7-2920XM CPU 2.50GHz (Sandy Bridge), 1 CPU, 8 logical and 4 physical cores
Frequency=2433504 Hz, Resolution=410.9301 ns, Timer=TSC
  [Host]     : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2633.0
  Job-KBLBLJ : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit LegacyJIT/clrjit-v4.7.2633.0;compatjit-v4.7.2633.0
  Job-PFMEQG : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0

MinIterationTime=500.0000 ms  Platform=AnyCpu  MinTargetIterationCount=30  
Method Jit Mean Error StdDev Scaled ScaledSD Allocated
Search562 Default 3.638 ms 0.0400 ms 0.0573 ms 0.43 0.01 563.2 KB
Search562Async Default 3.743 ms 0.0478 ms 0.0715 ms 0.44 0.01 563.2 KB
Search610 Default 8.523 ms 0.0786 ms 0.1152 ms 1.00 0.00 3919.24 KB
Search610Async Default 8.667 ms 0.1369 ms 0.2049 ms 1.02 0.03 4280.32 KB
Search610JsonNetSerializer Default 9.221 ms 0.0742 ms 0.1088 ms 1.08 0.02 3919.24 KB
Search610JsonNetSerializerAsync Default 9.494 ms 0.0566 ms 0.0756 ms 1.11 0.02 4280.32 KB
Search6x Default 3.460 ms 0.0445 ms 0.0666 ms 0.41 0.01 531.2 KB
Search6xAsync Default 3.357 ms 0.0493 ms 0.0738 ms 0.39 0.01 531.2 KB
Search6xJsonNetSerializer Default 8.842 ms 0.1011 ms 0.1513 ms 1.04 0.02 3532.49 KB
Search6xJsonNetSerializerAsync Default 8.869 ms 0.0748 ms 0.1120 ms 1.04 0.02 3532.49 KB
Search562 RyuJit 3.506 ms 0.0398 ms 0.0596 ms 0.40 0.01 563.2 KB
Search562Async RyuJit 3.529 ms 0.0661 ms 0.0989 ms 0.41 0.01 563.2 KB
Search610 RyuJit 8.664 ms 0.1381 ms 0.2066 ms 1.00 0.00 3919.24 KB
Search610Async RyuJit 8.356 ms 0.0925 ms 0.1384 ms 0.97 0.03 4280.32 KB
Search610JsonNetSerializer RyuJit 9.188 ms 0.1353 ms 0.1983 ms 1.06 0.03 3919.24 KB
Search610JsonNetSerializerAsync RyuJit 9.296 ms 0.1189 ms 0.1779 ms 1.07 0.03 4280.32 KB
Search6x RyuJit 3.382 ms 0.0627 ms 0.0900 ms 0.39 0.01 531.2 KB
Search6xAsync RyuJit 3.414 ms 0.0679 ms 0.1076 ms 0.39 0.02 531.2 KB
Search6xJsonNetSerializer RyuJit 9.032 ms 0.1200 ms 0.1796 ms 1.04 0.03 3532.49 KB
Search6xJsonNetSerializerAsync RyuJit 9.137 ms 0.1433 ms 0.2100 ms 1.06 0.03 3532.49 KB

Search returning 1000 documents

BenchmarkDotNet=v0.10.14.585-nightly, OS=Windows 10.0.16299.371 (1709/FallCreatorsUpdate/Redstone3)
Intel Core i7-2920XM CPU 2.50GHz (Sandy Bridge), 1 CPU, 8 logical and 4 physical cores
Frequency=2433504 Hz, Resolution=410.9301 ns, Timer=TSC
  [Host]     : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2633.0
  Job-KBLBLJ : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit LegacyJIT/clrjit-v4.7.2633.0;compatjit-v4.7.2633.0
  Job-PFMEQG : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0

MinIterationTime=500.0000 ms  Platform=AnyCpu  MinTargetIterationCount=30  
Method Jit Mean Error StdDev Scaled ScaledSD Gen 0 Gen 1 Allocated
Search562 Default 35.77 ms 0.4422 ms 0.6619 ms 0.42 0.01 - - 3.84 MB
Search562Async Default 35.76 ms 0.6612 ms 0.9897 ms 0.42 0.01 - - 3.84 MB
Search610 Default 85.05 ms 0.9365 ms 1.4017 ms 1.00 0.00 5000.0000 1000.0000 33.16 MB
Search610Async Default 91.19 ms 0.7971 ms 1.1930 ms 1.07 0.02 5000.0000 1000.0000 36.35 MB
Search610JsonNetSerializer Default 95.54 ms 0.7945 ms 1.1395 ms 1.12 0.02 5000.0000 1000.0000 33.16 MB
Search610JsonNetSerializerAsync Default 100.69 ms 0.6511 ms 0.9337 ms 1.18 0.02 5000.0000 1000.0000 36.35 MB
Search6x Default 35.34 ms 0.4391 ms 0.6572 ms 0.42 0.01 - - 3.59 MB
Search6xAsync Default 33.00 ms 0.2429 ms 0.3561 ms 0.39 0.01 - - 3.59 MB
Search6xJsonNetSerializer Default 87.50 ms 0.8645 ms 1.2940 ms 1.03 0.02 5000.0000 1000.0000 30.36 MB
Search6xJsonNetSerializerAsync Default 91.36 ms 1.8024 ms 3.4725 ms 1.07 0.04 5000.0000 1000.0000 30.36 MB
Search562 RyuJit 35.02 ms 0.5554 ms 0.7785 ms 0.43 0.01 - - 3.84 MB
Search562Async RyuJit 34.44 ms 0.6850 ms 1.2176 ms 0.42 0.02 - - 3.84 MB
Search610 RyuJit 81.45 ms 0.3979 ms 0.5956 ms 1.00 0.00 5000.0000 1000.0000 33.16 MB
Search610Async RyuJit 85.03 ms 0.6983 ms 0.9323 ms 1.04 0.01 5000.0000 1000.0000 36.35 MB
Search610JsonNetSerializer RyuJit 91.25 ms 0.5301 ms 0.7770 ms 1.12 0.01 5000.0000 1000.0000 33.16 MB
Search610JsonNetSerializerAsync RyuJit 95.72 ms 0.4528 ms 0.6637 ms 1.18 0.01 5000.0000 1000.0000 36.35 MB
Search6x RyuJit 33.21 ms 0.4803 ms 0.7189 ms 0.41 0.01 - - 3.59 MB
Search6xAsync RyuJit 33.19 ms 0.3661 ms 0.5366 ms 0.41 0.01 - - 3.59 MB
Search6xJsonNetSerializer RyuJit 92.38 ms 0.7229 ms 1.0368 ms 1.13 0.01 5000.0000 1000.0000 30.36 MB
Search6xJsonNetSerializerAsync RyuJit 89.78 ms 1.2280 ms 1.8000 ms 1.10 0.02 5000.0000 1000.0000 30.36 MB

Search returning 10000 documents

BenchmarkDotNet=v0.10.14.585-nightly, OS=Windows 10.0.16299.371 (1709/FallCreatorsUpdate/Redstone3)
Intel Core i7-2920XM CPU 2.50GHz (Sandy Bridge), 1 CPU, 8 logical and 4 physical cores
Frequency=2433504 Hz, Resolution=410.9301 ns, Timer=TSC
  [Host]     : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2633.0
  Job-KBLBLJ : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit LegacyJIT/clrjit-v4.7.2633.0;compatjit-v4.7.2633.0
  Job-PFMEQG : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2633.0

MinIterationTime=500.0000 ms  Platform=AnyCpu  MinTargetIterationCount=30  
Method Jit Mean Error StdDev Median Scaled ScaledSD Gen 0 Gen 1 Gen 2 Allocated
Search562 Default 380.8 ms 3.624 ms 5.425 ms 379.5 ms 0.44 0.01 6000.0000 2000.0000 - 37.61 MB
Search562Async Default 391.9 ms 3.979 ms 5.833 ms 392.5 ms 0.45 0.01 6000.0000 2000.0000 - 37.61 MB
Search610 Default 869.8 ms 14.065 ms 21.052 ms 864.0 ms 1.00 0.00 59000.0000 12000.0000 1000.0000 336.99 MB
Search610Async Default 886.3 ms 12.057 ms 17.673 ms 881.5 ms 1.02 0.03 57000.0000 13000.0000 - 369.79 MB
Search610JsonNetSerializer Default 948.7 ms 18.684 ms 29.089 ms 954.4 ms 1.09 0.04 59000.0000 12000.0000 1000.0000 337.01 MB
Search610JsonNetSerializerAsync Default 1,006.9 ms 20.129 ms 43.759 ms 1,004.5 ms 1.16 0.06 57000.0000 13000.0000 - 369.8 MB
Search6x Default 379.3 ms 7.471 ms 11.632 ms 376.4 ms 0.44 0.02 6000.0000 2000.0000 - 35.1 MB
Search6xAsync Default 358.2 ms 7.160 ms 12.351 ms 360.3 ms 0.41 0.02 6000.0000 2000.0000 - 35.1 MB
Search6xJsonNetSerializer Default 896.9 ms 17.620 ms 27.433 ms 906.7 ms 1.03 0.04 51000.0000 10000.0000 - 306.37 MB
Search6xJsonNetSerializerAsync Default 898.0 ms 17.938 ms 32.801 ms 916.7 ms 1.03 0.04 51000.0000 10000.0000 - 306.36 MB
Search562 RyuJit 387.9 ms 6.964 ms 10.424 ms 390.5 ms 0.46 0.01 6000.0000 2000.0000 - 37.6 MB
Search562Async RyuJit 360.6 ms 1.359 ms 1.814 ms 360.4 ms 0.43 0.01 6000.0000 2000.0000 - 37.61 MB
Search610 RyuJit 844.5 ms 10.982 ms 15.750 ms 842.1 ms 1.00 0.00 57000.0000 13000.0000 - 336.94 MB
Search610Async RyuJit 854.8 ms 16.752 ms 29.340 ms 860.2 ms 1.01 0.04 57000.0000 13000.0000 - 369.8 MB
Search610JsonNetSerializer RyuJit 926.3 ms 16.568 ms 24.798 ms 919.7 ms 1.10 0.04 57000.0000 13000.0000 - 336.95 MB
Search610JsonNetSerializerAsync RyuJit 939.1 ms 6.488 ms 9.510 ms 941.5 ms 1.11 0.02 58000.0000 12000.0000 1000.0000 369.86 MB
Search6x RyuJit 356.9 ms 2.711 ms 3.888 ms 356.5 ms 0.42 0.01 6000.0000 2000.0000 - 35.1 MB
Search6xAsync RyuJit 364.7 ms 6.757 ms 10.113 ms 363.6 ms 0.43 0.01 6000.0000 2000.0000 - 35.1 MB
Search6xJsonNetSerializer RyuJit 884.8 ms 11.681 ms 16.375 ms 880.8 ms 1.05 0.03 51000.0000 10000.0000 - 306.37 MB
Search6xJsonNetSerializerAsync RyuJit 918.3 ms 6.877 ms 9.863 ms 920.3 ms 1.09 0.02 51000.0000 10000.0000 - 306.36 MB

Copy link
Member

@Mpdreamz Mpdreamz left a comment

Choose a reason for hiding this comment

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

So much goodness in here 👍 will rebase against 6.x now

var anyEmpty = combined.Any(q => q == null || !q.IsWritable);
query = anyEmpty ? combined.FirstOrDefault(q => q != null && q.IsWritable) : null;
return anyEmpty;
query = null;
Copy link
Member

Choose a reason for hiding this comment

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

👍

russcam added 13 commits June 11, 2018 12:21
This commit removes the need to copy the response bytes into a MemoryStream to
get the bytes and check the length, by simply checking the length of the stream directly.
This commit removes string allocations when creating a Stream from
a JToken, by writing the token directly to a stream using UTF-8 encoding
…lizer

This commit removes the JToken to Stream handoff within SourceConverter when
the SourceSerializer is InternalSerializer, by passing the JsonReader directly.
…solver

This commit reverts the previous check added in SourceConverter to determine whether it's
the InternalSerializer by fixing a bug in ElasticContractResolver that is intended to perform this
check. The bug is that the check is evaluated too early, before serializers have been assigned
to ConnectionSettings. Now, the check is lazily made.
This commit adds a RecyclableMemoryStreamFactory that can pool underlying byte
buffers for MemoryStreams for better reuse and fewer allocations.

Add Create(byte[]) method on IMemoryStreamFactory to allow creation of a stream with
written bytes.

Include IMemoryStreamFactory on IConnectionConfigurationValues to allow it to be accessed
inside custom JsonConverters.
@Mpdreamz
Copy link
Member

Mpdreamz commented Jun 11, 2018

No more LOH gen 2 when using Nest.JsonNetSerializer ❤️

…gus deadlock that were popping up on my machine
@Mpdreamz Mpdreamz merged commit a5a92b9 into 6.x Jun 11, 2018
Mpdreamz pushed a commit that referenced this pull request Jun 11, 2018
* Remove allocations in QueryBase IfEitherIsEmptyReturnTheOtherOrEmpty

* Remove need to ReadBytesAsync

This commit removes the need to copy the response bytes into a MemoryStream to
get the bytes and check the length, by simply checking the length of the stream directly.

* Honour SkipOnTeamCityAttribute for unit tests

* Use EmptyReadOnly collection

* Fix spelling and add xml documentation

* Don't unneccessarily split string

* Reduce string allocations when creating streams from JToken

This commit removes string allocations when creating a Stream from
a JToken, by writing the token directly to a stream using UTF-8 encoding

* Add link to JSON.Net issue to extension method

* Add benchmarks including JsonNetSerializer

* Avoid JToken to Stream handoff when SourceSerializer is InternalSerializer

This commit removes the JToken to Stream handoff within SourceConverter when
the SourceSerializer is InternalSerializer, by passing the JsonReader directly.

* Replace InternalSerializer check with lazy check in ElasticContractResolver

This commit reverts the previous check added in SourceConverter to determine whether it's
the InternalSerializer by fixing a bug in ElasticContractResolver that is intended to perform this
check. The bug is that the check is evaluated too early, before serializers have been assigned
to ConnectionSettings. Now, the check is lazily made.

* small tidy-up

* Add RecyclableMemoryStreamFactory

This commit adds a RecyclableMemoryStreamFactory that can pool underlying byte
buffers for MemoryStreams for better reuse and fewer allocations.

Add Create(byte[]) method on IMemoryStreamFactory to allow creation of a stream with
written bytes.

Include IMemoryStreamFactory on IConnectionConfigurationValues to allow it to be accessed
inside custom JsonConverters.

* SkipOnTeamCity no longer has a description argument, small fix for Bogus deadlock that were popping up on my machine

Conflicts:
	src/Tests/Framework/TestClient.cs
@Mpdreamz Mpdreamz deleted the feature/6.x-perf branch June 11, 2018 11:57
@Mpdreamz
Copy link
Member

merged and ported to master

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants