Skip to content

StreamReader sync/async optimizations: ArrayPool, IndexOfAny, ValueStringBuilder - #62552

Closed
Trapov wants to merge 26 commits into
dotnet:mainfrom
Trapov:optimizations/7.0.0/stream-reader
Closed

StreamReader sync/async optimizations: ArrayPool, IndexOfAny, ValueStringBuilder#62552
Trapov wants to merge 26 commits into
dotnet:mainfrom
Trapov:optimizations/7.0.0/stream-reader

Conversation

@Trapov

Copy link
Copy Markdown

No description provided.

@ghostghost added area-System.IO community-contribution Indicates that the PR has been added by a community member labels Dec 8, 2021
@ghost

ghost commented Dec 8, 2021

Copy link
Copy Markdown

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

Issue Details

null

Author:Trapov
Assignees:-
Labels:

area-System.IO

Milestone:-

@TrapovTrapov changed the title Store string-builder as a field and clear when reuse.Store string-builder as a field and clear when reuse + IndexOfAnyDec 8, 2021
Comment threadsrc/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs Outdated
@Trapov

Copy link
Copy Markdown
Author

First commit:

MethodJobToolchainLineLengthRangeMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Allocated
ReadLineAsyncJob-LRHBFX/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]576.81 us29.131 us32.379 us562.49 us540.34 us643.70 us1.000.00187.50002.23211,155 KB
ReadLineAsyncJob-WPRXLK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]579.85 us23.834 us27.447 us568.93 us536.74 us637.39 us1.010.07187.5000-1,155 KB
ReadLineAsyncJob-LRHBFX/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]31.16 us1.892 us1.943 us31.12 us28.09 us34.21 us1.000.0010.46080.132465 KB
ReadLineAsyncJob-WPRXLK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]27.64 us3.124 us3.598 us27.46 us23.35 us34.90 us0.900.167.81250.188348 KB
ReadLineAsyncJob-LRHBFX/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]338.23 us3.676 us3.439 us339.46 us328.85 us341.25 us1.000.00125.00001.3298771 KB
ReadLineAsyncJob-WPRXLK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]347.04 us1.816 us1.610 us347.21 us344.91 us350.68 us1.030.01125.00001.3889771 KB
ReadLineAsyncJob-LRHBFX/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]168.74 us2.675 us2.502 us167.66 us165.08 us172.47 us1.000.0055.63190.6868344 KB
ReadLineAsyncJob-WPRXLK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]207.40 us0.979 us0.868 us207.53 us205.60 us208.89 us1.230.0255.6507-341 KB
ReadLineAsyncJob-LRHBFX/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]65.34 us6.810 us7.842 us62.75 us57.27 us83.04 us1.000.0017.8241-110 KB
ReadLineAsyncJob-WPRXLK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]81.23 us6.146 us7.077 us83.22 us67.65 us92.21 us1.260.2117.2739-107 KB
ReadLineAsyncJob-LRHBFX/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]47.61 us6.259 us7.208 us48.00 us35.45 us62.57 us1.000.009.5588-59 KB
ReadLineAsyncJob-WPRXLK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]41.29 us4.558 us5.066 us41.44 us35.00 us51.81 us0.890.239.00540.134455 KB
ReadLineAsyncJob-LRHBFX/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]36.41 us5.433 us6.257 us32.57 us30.47 us47.04 us1.000.0010.63830.166265 KB
ReadLineAsyncJob-WPRXLK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]28.45 us3.326 us3.830 us27.53 us24.42 us35.71 us0.800.147.49540.115346 KB
ReadLineAsyncJob-LRHBFX/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]41.31 us4.936 us5.684 us41.06 us32.03 us51.89 us1.000.0014.81210.361392 KB
ReadLineAsyncJob-WPRXLK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]31.82 us3.128 us3.603 us31.36 us26.26 us38.29 us0.780.137.57580.199447 KB

@Trapov

Copy link
Copy Markdown
Author

Second commit.

MethodJobToolchainLineLengthRangeMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Allocated
ReadLineAsyncJob-SKXEQW/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]662.746 us113.3171 us125.9516 us635.766 us530.010 us981.626 us1.000.00187.50002.01611,155 KB
ReadLineAsyncJob-UNIDYD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]897.942 us153.5380 us176.8146 us884.897 us627.131 us1,174.790 us1.430.42187.5000-1,155 KB
ReadLineAsyncJob-SKXEQW/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]44.210 us6.8340 us7.8700 us44.208 us32.168 us60.262 us1.000.0010.49620.119365 KB
ReadLineAsyncJob-UNIDYD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]10.893 us1.3715 us1.4085 us10.705 us9.150 us14.385 us0.260.047.87110.208548 KB
ReadLineAsyncJob-SKXEQW/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]378.469 us31.3504 us32.1946 us388.850 us330.829 us426.392 us1.000.00125.00001.3889771 KB
ReadLineAsyncJob-UNIDYD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]460.742 us64.4477 us66.1830 us459.692 us361.494 us646.085 us1.230.20125.0000-771 KB
ReadLineAsyncJob-SKXEQW/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]234.039 us33.1543 us36.8509 us230.729 us181.060 us319.581 us1.000.0055.9896-344 KB
ReadLineAsyncJob-UNIDYD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]295.321 us65.5221 us75.4553 us269.663 us202.976 us437.634 us1.290.2954.9242-341 KB
ReadLineAsyncJob-SKXEQW/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]77.645 us10.5925 us12.1983 us76.216 us61.252 us101.756 us1.000.0017.9005-110 KB
ReadLineAsyncJob-UNIDYD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]55.522 us5.4000 us6.2187 us54.816 us46.218 us69.039 us0.740.1617.26190.1984107 KB
ReadLineAsyncJob-SKXEQW/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]52.007 us8.5124 us9.8029 us52.466 us37.995 us73.383 us1.000.009.6154-59 KB
ReadLineAsyncJob-UNIDYD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]26.025 us3.8753 us4.1465 us25.841 us19.443 us35.776 us0.510.158.94470.113255 KB
ReadLineAsyncJob-SKXEQW/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]32.651 us2.6058 us3.0008 us31.169 us29.556 us39.670 us1.000.0010.56760.151065 KB
ReadLineAsyncJob-UNIDYD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]8.686 us0.4398 us0.4888 us8.517 us8.158 us9.859 us0.270.037.51460.198646 KB
ReadLineAsyncJob-SKXEQW/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]37.268 us2.6887 us2.8769 us37.231 us32.383 us42.540 us1.000.0014.93360.414892 KB
ReadLineAsyncJob-UNIDYD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]10.994 us1.9150 us2.2053 us10.871 us7.850 us14.618 us0.300.067.59020.190547 KB

@Trapov

Copy link
Copy Markdown
Author

Third commit.

MethodJobToolchainLineLengthRangeMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Allocated
ReadLineAsyncJob-BCLYJE/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]610.499 us45.8071 us52.7516 us606.611 us536.488 us728.957 us1.000.00187.50002.15521,155 KB
ReadLineAsyncJob-AIFESD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]609.997 us10.9450 us9.1396 us607.176 us598.037 us629.751 us0.990.09187.50002.40381,155 KB
ReadLineAsyncJob-BCLYJE/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]29.742 us0.2418 us0.2261 us29.774 us29.406 us30.153 us1.000.0010.47550.117765 KB
ReadLineAsyncJob-AIFESD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]8.426 us0.1208 us0.1071 us8.418 us8.277 us8.581 us0.280.007.85870.201548 KB
ReadLineAsyncJob-BCLYJE/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]317.568 us2.0502 us1.8175 us317.490 us314.543 us321.392 us1.000.00125.00001.2755771 KB
ReadLineAsyncJob-AIFESD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]356.798 us4.1285 us3.8618 us355.689 us351.650 us364.344 us1.120.01125.00001.3889771 KB
ReadLineAsyncJob-BCLYJE/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]218.355 us20.7127 us23.0221 us212.493 us184.479 us264.052 us1.000.0055.70650.6793344 KB
ReadLineAsyncJob-AIFESD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]183.303 us14.4207 us16.0286 us175.745 us171.088 us229.335 us0.850.0955.31610.7184341 KB
ReadLineAsyncJob-BCLYJE/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]67.853 us6.6293 us7.6343 us66.260 us58.617 us80.864 us1.000.0018.0000-110 KB
ReadLineAsyncJob-AIFESD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]46.189 us0.7011 us0.5855 us45.973 us45.376 us47.320 us0.700.0717.24140.1959107 KB
ReadLineAsyncJob-BCLYJE/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]35.469 us0.3500 us0.3103 us35.388 us35.122 us36.106 us1.000.009.5937-59 KB
ReadLineAsyncJob-AIFESD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]17.950 us0.1317 us0.1167 us17.942 us17.785 us18.204 us0.510.019.01030.071555 KB
ReadLineAsyncJob-BCLYJE/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]29.064 us0.3262 us0.2891 us28.979 us28.752 us29.734 us1.000.0010.62850.115565 KB
ReadLineAsyncJob-AIFESD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]10.322 us1.8122 us2.0869 us9.830 us8.158 us14.673 us0.380.077.52460.194646 KB
ReadLineAsyncJob-BCLYJE/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]34.621 us2.6252 us2.9179 us33.592 us31.286 us41.322 us1.000.0014.88100.372092 KB
ReadLineAsyncJob-AIFESD/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]9.381 us0.9107 us1.0488 us9.299 us7.818 us11.542 us0.270.047.59160.196347 KB

@Trapov

Copy link
Copy Markdown
Author

@stephentoub@adamsitnik moved your suggestions to here.

@stephentoub

Copy link
Copy Markdown
Member

Thanks. My use of StringBuilder in the other PR comments was mostly for a quick hack to exemplify the wins. I think we should look here at instead using char arrays from ArrayPool.

@Trapov

Trapov commented Dec 9, 2021

Copy link
Copy Markdown
Author

Thanks. My use of StringBuilder in the other PR comments was mostly for a quick hack to exemplify the wins. I think we should look here at instead using char arrays from ArrayPool.

Wouldn't be there a problem when there's only one line and we return and rent new char arrays other and other until we hit EOF?

@Trapov
Trapovforce-pushed the optimizations/7.0.0/stream-reader branch from 8c20efb to fb6ccb3CompareDecember 9, 2021 09:00
@Trapov
Trapovforce-pushed the optimizations/7.0.0/stream-reader branch from fb6ccb3 to e2e318fCompareDecember 9, 2021 09:15
@Trapov

Trapov commented Dec 9, 2021

Copy link
Copy Markdown
Author

Thanks. My use of StringBuilder in the other PR comments was mostly for a quick hack to exemplify the wins. I think we should look here at instead using char arrays from ArrayPool.

Wouldn't be there a problem when there's only one line and we return and rent new char arrays other and other until we hit EOF?
@stephentoub

  1. If we read the full buffer and there's more to consume (not yet new line characters) we would have to reallocate/resize the polled array
  2. If we read the buffer (and before that read the buffer and no symbols were met) and a new line symbols there then we would have to resize/join current buffer + polled array.
  3. We wouldn't need a polled array if it's a first read and we see new-line characters so we would make it in place from the buffer.

The first and the second cases do need reallocating/resizing pooled array.

CheckAndRead() // pos == len and Read()
do{
if (HaveEndLine()){
return lineFromBuffer or (pooledArray + lineFromBuffer) Reallocated/Resized
}
pooledArray = ArrayPool.Rent(sizeOfBuffer) + copyBuffer + pooledArray (Reallocated/Resized)
}
while{Reading()}

@stephentoub

Copy link
Copy Markdown
Member

Wouldn't be there a problem when there's only one line and we return and rent new char arrays other and other until we hit EOF?

Why is that a problem?

@Trapov

Copy link
Copy Markdown
Author

Wouldn't be there a problem when there's only one line and we return and rent new char arrays other and other until we hit EOF?

Why is that a problem?

I meant reallocating and resizing the polled arrays wouldn't the cost be higher?

@stephentoub

Copy link
Copy Markdown
Member

I meant reallocating and resizing the polled arrays wouldn't the cost be higher?

There would be some cost, but it should also be rare. We can afford to rent a larger char[] initially than we can proactively allocate a StringBuilder, and by renting/returning, we save the cost of creating a new StringBuilder for each StreamReader, plus avoid increasing the size of the StreamReader itself. We also avoid holding on to a potentially large object for the lifetime of the StreamReader and instead allow other code in the process to use that same memory, or potentially for it to be reclaimed.

@Trapov

Copy link
Copy Markdown
Author

@stephentoub Added array pools as a draft and they do look better. I've picked 80 as default increase factor, probably gonna change to something different. I assume we could redo passing the arrays and copying them as spans, and change Array.Copy to Buffer.Copy but I'm not sure.

Also gonna run unit-tests locally. Feel like I broke something.

MethodJobToolchainLineLengthRangeMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Allocated
ReadLineAsyncJob-ZXCHUZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]522.034 us7.0370 us6.2381 us520.286 us515.192 us537.143 us1.000.00187.50002.08331,155 KB
ReadLineAsyncJob-QMQFHK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]636.177 us8.1706 us6.3790 us635.035 us624.068 us647.340 us1.220.01187.5000-1,155 KB
ReadLineAsyncJob-ZXCHUZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]29.147 us0.5828 us0.6478 us28.984 us28.503 us30.683 us1.000.0010.51190.114365 KB
ReadLineAsyncJob-QMQFHK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]9.698 us0.1297 us0.1213 us9.690 us9.511 us9.911 us0.330.018.84650.114954 KB
ReadLineAsyncJob-ZXCHUZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]318.809 us4.8207 us4.2735 us318.232 us313.885 us329.554 us1.000.00125.00001.2500771 KB
ReadLineAsyncJob-QMQFHK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]373.266 us6.9424 us6.1542 us373.846 us364.966 us383.455 us1.170.02125.00001.4535771 KB
ReadLineAsyncJob-ZXCHUZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]165.901 us2.0257 us1.7957 us166.238 us163.289 us169.531 us1.000.0055.85110.6649344 KB
ReadLineAsyncJob-QMQFHK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]172.244 us2.0826 us1.7391 us172.141 us169.617 us174.969 us1.040.0155.63190.6868344 KB
ReadLineAsyncJob-ZXCHUZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]58.729 us1.1529 us1.2336 us58.550 us57.323 us61.251 us1.000.0017.92280.2298110 KB
ReadLineAsyncJob-QMQFHK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]46.200 us0.5590 us0.4956 us46.094 us45.393 us47.170 us0.790.0217.72660.1827110 KB
ReadLineAsyncJob-ZXCHUZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]34.953 us0.4604 us0.4307 us34.956 us34.306 us35.947 us1.000.009.6366-59 KB
ReadLineAsyncJob-QMQFHK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]18.279 us0.1876 us0.1567 us18.287 us18.040 us18.631 us0.520.019.31630.073457 KB
ReadLineAsyncJob-ZXCHUZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]29.082 us0.2937 us0.2603 us29.078 us28.675 us29.515 us1.000.0010.63080.116865 KB
ReadLineAsyncJob-QMQFHK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]9.497 us0.1593 us0.1412 us9.512 us9.250 us9.719 us0.330.019.02690.114756 KB
ReadLineAsyncJob-ZXCHUZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]30.532 us0.2215 us0.2072 us30.475 us30.280 us30.997 us1.000.0014.95620.364892 KB
ReadLineAsyncJob-QMQFHK/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]9.897 us0.1248 us0.1167 us9.854 us9.746 us10.130 us0.320.0011.11460.352268 KB

@Trapov

Copy link
Copy Markdown
Author

Can't really run the tests I hope the CI would spot an error if there is one (I hope no errors) :(

#62586 (created an issue)

Anyway the benchmarks are here so feel free to comment. I'm gonna play with the Spans until any other comments/suggestions.

@TrapovTrapov changed the title Store string-builder as a field and clear when reuse + IndexOfAnyStore string-builder as a field and clear when reuse + IndexOfAny + ArrayPoolDec 9, 2021
@Trapov

Trapov commented Dec 9, 2021

Copy link
Copy Markdown
Author

Fixed the tests. And figured out how to run them locally (wrote about it in the issue and closed it).

@Trapov

Copy link
Copy Markdown
Author

Benchmarks after fixing the tests.

MethodJobToolchainLineLengthRangeMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Allocated
ReadLineAsyncJob-PWLHPZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]523.748 us8.9409 us8.3633 us520.891 us513.102 us542.318 us1.000.00187.50002.01611,155 KB
ReadLineAsyncJob-BQBLXH/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 0]655.019 us8.7931 us8.2251 us654.981 us637.813 us665.928 us1.250.02187.5000-1,155 KB
ReadLineAsyncJob-PWLHPZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]31.184 us0.5500 us0.4876 us31.022 us30.707 us32.180 us1.000.0010.54220.125565 KB
ReadLineAsyncJob-BQBLXH/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 0, 1024]9.271 us0.1739 us0.1626 us9.319 us9.045 us9.560 us0.300.016.27960.073939 KB
ReadLineAsyncJob-PWLHPZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]325.870 us6.2568 us6.4253 us324.772 us315.801 us337.069 us1.000.00125.00001.3021771 KB
ReadLineAsyncJob-BQBLXH/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 1]370.305 us3.6738 us3.4365 us371.015 us364.259 us375.299 us1.140.02125.00001.4535771 KB
ReadLineAsyncJob-PWLHPZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]167.550 us1.6253 us1.5203 us167.785 us164.828 us169.526 us1.000.0055.77960.6720344 KB
ReadLineAsyncJob-BQBLXH/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 1, 8]177.799 us3.3752 us3.3149 us176.830 us173.500 us185.600 us1.060.0255.02720.6793341 KB
ReadLineAsyncJob-PWLHPZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]58.646 us0.6930 us0.6144 us58.625 us57.410 us59.579 us1.000.0017.79200.2281110 KB
ReadLineAsyncJob-BQBLXH/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 9, 32]47.613 us0.5092 us0.4252 us47.569 us46.797 us48.296 us0.810.0117.28720.1900106 KB
ReadLineAsyncJob-PWLHPZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]34.964 us0.3600 us0.3368 us34.960 us34.423 us35.655 us1.000.009.5291-59 KB
ReadLineAsyncJob-BQBLXH/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 33, 128]18.300 us0.1990 us0.1861 us18.278 us18.089 us18.651 us0.520.018.83620.071854 KB
ReadLineAsyncJob-PWLHPZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]29.496 us0.4170 us0.3697 us29.412 us29.069 us30.358 us1.000.0010.55350.117365 KB
ReadLineAsyncJob-BQBLXH/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[ 129, 1024]8.553 us0.0618 us0.0578 us8.543 us8.475 us8.644 us0.290.006.28420.102539 KB
ReadLineAsyncJob-PWLHPZ/testhost-main/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]31.037 us0.3864 us0.3614 us31.032 us30.576 us31.664 us1.000.0014.94570.370692 KB
ReadLineAsyncJob-BQBLXH/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerun[1025, 2048]8.214 us0.1540 us0.1440 us8.204 us8.008 us8.440 us0.260.016.17490.098038 KB

@Trapov

Copy link
Copy Markdown
Author

@danmoseley removed readtoend changes.

@Trapov
Trapov requested a review from danmoseleyMay 11, 2022 18:17
Comment threadsrc/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs Outdated
@danmoseley

danmoseley commented May 11, 2022

Copy link
Copy Markdown
Contributor

Can you update the benchmark now -- I don't see ReadLine results. We care about ReadLine and ReadLineAsync benchmarks, I would expect the others to be unchanged (of course we should verify)

Some nice improvements in the ReadLineAsync numbers though. I'm guessing the short line cases are slower because IndexOfAny(..) is slower than a trivial loop when the hit is very early in the buffer.

Something interesting I noticed is that the perf characteristics will be slightly different on Windows vs Linux/Mac (that you have). That's because the perf tests use the platform line ending:
https://github.com/dotnet/performance/blob/9062f791140cea0eaba3f3625c845b17e1a80dd4/src/benchmarks/micro/libraries/System.IO/TextReaderReadLineTests.cs#L45

You might want to locally edit that line to use \r\n and then rerun, to see those numbers too. I wouldn't expect it to be that different, but it will run through a slightly different path. It will mostly affect very short lines of course. Eg., [1,1] will create about 5000 lines in the 16K buffer on Windows, and 8000 lines on Mac.

@stephentoub any concerns about the changes here? The local methods seem ugly, but as discussed, we seem to be missing a reusable type here for this case.

@Trapov

Copy link
Copy Markdown
Author

@danmoseley added NewLine to the params (NRN map to the \n\r\n) and ran the benchmarks with ReadLine+ReadLineAsync

BenchmarkDotNet=v0.13.1.1786-nightly, OS=macOS Monterey 12.3.1 (21E258) [Darwin 21.4.0]
Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK=7.0.100-preview.3.22179.4
[Host] : .NET 7.0.0 (7.0.22.17504), X64 RyuJIT
Job-HKXHTD : .NET 7.0.0 (42.42.42.42424), X64 RyuJIT
Job-RJNYWV : .NET 7.0.0 (42.42.42.42424), X64 RyuJIT
PowerPlanMode=00000000-0000-0000-0000-000000000000 IterationTime=250.0000 ms MaxIterationCount=20 MinIterationCount=15 WarmupCount=1 
MethodJobToolchainNewLineLineLengthRangeMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1AllocatedAlloc Ratio
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 0]88.14 μs0.994 μs0.881 μs87.85 μs87.16 μs89.97 μs0.420.0120.3488-3.27 KB1.00
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 0]208.48 μs2.137 μs1.999 μs207.83 μs205.67 μs211.32 μs1.000.0019.7368-3.27 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 1024]40.40 μs0.574 μs0.509 μs40.28 μs39.74 μs41.52 μs1.950.04389.5202-62.2 KB1.72
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 1024]20.66 μs0.396 μs0.370 μs20.47 μs20.27 μs21.41 μs1.000.00226.3580-36.21 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 1]173.74 μs1.316 μs1.167 μs173.95 μs170.66 μs175.22 μs0.760.011223.314638.6236195.27 KB1.00
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 1]228.94 μs2.970 μs2.480 μs229.20 μs224.52 μs233.62 μs1.000.001223.214338.3929195.27 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 8]128.25 μs1.583 μs1.403 μs128.24 μs126.02 μs130.88 μs1.010.01704.3478-112.4 KB1.03
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 8]127.47 μs1.316 μs1.167 μs127.33 μs125.58 μs129.45 μs1.000.00686.4919-109.57 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 9, 32]53.04 μs0.629 μs0.588 μs52.97 μs52.24 μs54.20 μs1.230.02352.8912-56.42 KB1.07
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 9, 32]43.19 μs0.560 μs0.524 μs42.98 μs42.62 μs44.33 μs1.000.00331.1644-52.59 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 33, 128]37.21 μs0.503 μs0.420 μs37.21 μs36.27 μs37.87 μs1.570.03279.9171-44.7 KB1.12
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 33, 128]23.75 μs0.357 μs0.317 μs23.79 μs23.31 μs24.21 μs1.000.00250.0000-39.94 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 129, 1024]41.58 μs0.566 μs0.502 μs41.49 μs40.74 μs42.43 μs2.030.03396.5000-63.39 KB1.73
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 129, 1024]20.51 μs0.242 μs0.227 μs20.44 μs20.22 μs20.88 μs1.000.00229.1395-36.68 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[1025, 2048]51.25 μs1.038 μs1.154 μs51.06 μs49.49 μs53.12 μs2.430.06522.52443.246890.86 KB2.44
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[1025, 2048]21.13 μs0.454 μs0.505 μs21.03 μs20.41 μs22.12 μs1.000.00230.6863-37.24 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 0, 0]57.56 μs0.426 μs0.398 μs57.67 μs56.94 μs58.13 μs0.530.0120.2206-3.27 KB1.00
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 0, 0]108.11 μs1.553 μs1.376 μs108.07 μs106.08 μs110.73 μs1.000.0020.1199-3.27 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 0, 1024]39.82 μs0.376 μs0.333 μs39.77 μs39.23 μs40.44 μs1.960.03383.2487-61.3 KB1.70
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 0, 1024]20.29 μs0.313 μs0.278 μs20.24 μs19.85 μs20.93 μs1.000.00224.9514-35.98 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 1, 1]127.01 μs1.096 μs0.972 μs127.05 μs124.83 μs128.49 μs0.810.01831.3008-132.69 KB1.01
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 1, 1]156.74 μs0.827 μs0.774 μs156.71 μs154.60 μs157.91 μs1.000.00822.4010-131.28 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 1, 8]110.45 μs1.216 μs1.078 μs110.47 μs108.53 μs112.30 μs1.030.01594.1840-94.88 KB1.03
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 1, 8]107.33 μs0.638 μs0.533 μs107.38 μs106.41 μs108.05 μs1.000.00576.6267-92.05 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 9, 32]51.98 μs0.670 μs0.594 μs51.89 μs50.94 μs53.17 μs1.240.02339.1970-54.08 KB1.07
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 9, 32]42.04 μs0.300 μs0.266 μs41.98 μs41.49 μs42.57 μs1.000.00315.6667-50.4 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 33, 128]37.00 μs0.514 μs0.456 μs37.02 μs36.30 μs37.92 μs1.530.02281.2500-44.88 KB1.14
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 33, 128]24.13 μs0.257 μs0.240 μs24.05 μs23.70 μs24.62 μs1.000.00248.2824-39.43 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 129, 1024]40.00 μs0.399 μs0.373 μs40.05 μs39.20 μs40.43 μs1.960.03381.6794-61.08 KB1.67
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 129, 1024]20.38 μs0.256 μs0.227 μs20.35 μs20.06 μs20.79 μs1.000.00229.1667-36.68 KB1.00
ReadLineJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[1025, 2048]49.27 μs0.412 μs0.365 μs49.40 μs48.57 μs49.69 μs2.310.04516.21093.515690.71 KB2.44
ReadLineJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[1025, 2048]21.31 μs0.352 μs0.312 μs21.29 μs20.74 μs21.85 μs1.000.00230.7181-37.24 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 0]1,030.78 μs10.028 μs8.373 μs1,028.46 μs1,021.56 μs1,051.98 μs0.810.017238.2813-1155.27 KB1.00
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 0]1,276.54 μs16.725 μs15.644 μs1,268.77 μs1,259.75 μs1,304.99 μs1.000.007236.1111-1155.27 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 1024]57.57 μs1.070 μs0.894 μs57.56 μs56.39 μs59.46 μs2.290.04404.6763-64.59 KB1.67
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 1024]25.12 μs0.280 μs0.249 μs25.12 μs24.67 μs25.48 μs1.000.00241.3000-38.6 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 1]682.83 μs12.967 μs12.736 μs683.05 μs666.01 μs712.16 μs0.900.024830.7292-771.27 KB1.00
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 1]761.50 μs6.336 μs5.290 μs761.99 μs751.02 μs770.48 μs1.000.004830.3571-771.27 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 8]322.52 μs2.809 μs2.627 μs323.21 μs318.14 μs326.82 μs0.910.012153.7500-343.8 KB1.01
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 8]353.99 μs3.487 μs2.912 μs353.33 μs349.17 μs360.92 μs1.000.002136.1111-340.97 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 9, 32]108.52 μs1.174 μs1.098 μs108.47 μs107.16 μs110.63 μs1.060.03690.9014-110.28 KB1.04
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 9, 32]101.86 μs2.547 μs2.831 μs100.87 μs98.84 μs107.87 μs1.000.00666.3961-106.45 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 33, 128]61.08 μs0.882 μs0.782 μs61.06 μs60.00 μs62.56 μs1.380.02370.6395-59.19 KB1.09
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 33, 128]44.16 μs0.471 μs0.418 μs44.26 μs43.44 μs44.82 μs1.000.00340.8774-54.42 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 129, 1024]57.89 μs1.768 μs1.965 μs56.87 μs55.98 μs62.29 μs2.310.07408.9286-65.29 KB1.69
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 129, 1024]25.21 μs0.310 μs0.290 μs25.21 μs24.77 μs25.77 μs1.000.00240.7000-38.58 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[1025, 2048]65.63 μs1.031 μs0.914 μs65.31 μs64.20 μs67.15 μs2.770.04476.75627.489791.63 KB2.41
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[1025, 2048]23.72 μs0.250 μs0.234 μs23.66 μs23.39 μs24.13 μs1.000.00235.1235-38.02 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 0, 0]742.71 μs183.783 μs204.275 μs670.49 μs540.30 μs1,246.29 μs0.950.353629.1667-579.27 KB1.00
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 0, 0]804.63 μs84.780 μs97.633 μs809.55 μs688.16 μs978.83 μs1.000.003628.9063-579.27 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 0, 1024]66.15 μs5.430 μs6.253 μs67.25 μs56.06 μs78.91 μs2.370.20399.9110-63.63 KB1.66
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 0, 1024]26.77 μs0.514 μs0.429 μs26.60 μs26.40 μs27.98 μs1.000.00239.0376-38.3 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 1, 1]492.95 μs9.335 μs10.375 μs489.33 μs478.22 μs514.43 μs0.900.023237.9032-516.74 KB1.00
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 1, 1]547.55 μs6.008 μs5.326 μs545.59 μs541.14 μs558.24 μs1.000.003228.4483-515.33 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 1, 8]292.94 μs5.747 μs6.618 μs292.36 μs282.91 μs306.74 μs0.940.041808.9623-288.66 KB1.01
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 1, 8]312.51 μs11.828 μs12.147 μs311.16 μs298.71 μs348.45 μs1.000.001790.8654-285.83 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 9, 32]119.37 μs11.473 μs12.753 μs112.42 μs109.09 μs145.75 μs1.010.23661.2762-105.55 KB1.04
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 9, 32]125.96 μs31.777 μs36.594 μs101.98 μs100.05 μs220.98 μs1.000.00638.0719-101.87 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 33, 128]80.75 μs11.853 μs13.650 μs81.97 μs63.41 μs109.29 μs1.910.32370.1717-59.15 KB1.10
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 33, 128]44.26 μs0.255 μs0.226 μs44.25 μs43.78 μs44.61 μs1.000.00333.3333-53.7 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 129, 1024]57.83 μs0.426 μs0.378 μs57.74 μs57.39 μs58.73 μs2.250.03392.8571-62.98 KB1.63
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[ 129, 1024]25.74 μs0.467 μs0.414 μs25.64 μs25.14 μs26.49 μs1.000.00240.5992-38.58 KB1.00
ReadLineAsyncJob-HKXHTD/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[1025, 2048]66.35 μs0.626 μs0.523 μs66.36 μs65.48 μs67.25 μs2.780.04491.40635.468891.48 KB2.41
ReadLineAsyncJob-RJNYWV/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunRN[1025, 2048]23.90 μs0.364 μs0.304 μs23.85 μs23.41 μs24.62 μs1.000.00235.1190-38.02 KB1.00

@Trapov

Copy link
Copy Markdown
Author

We could fall-back to initial while loop if the line is short. We need to determine which is short tho. Something around 5-16 chars.

@danmoseley

Copy link
Copy Markdown
Contributor

We could fall-back to initial while loop if the line is short. We need to determine which is short tho. Something around 5-16 chars.

How do you know how long the line is without searching in the first place? It’s just an assumption we have to make that files are mostly content not newline characters.

@Trapov

Copy link
Copy Markdown
Author

We could fall-back to initial while loop if the line is short. We need to determine which is short tho. Something around 5-16 chars.

How do you know how long the line is without searching in the first place? It’s just an assumption we have to make that files are mostly content not newline characters.

Sorry, I meant running the search loop for 10 chars and then switching back to index of any

@Trapov

Copy link
Copy Markdown
Author

@danmoseley that's what I meant. My naive solution (didn't push it) but what I don't understand why it's allocating 74 kb like that.

publicoverridestring?ReadLine(){ThrowIfDisposed();CheckAsyncTaskInProgress();if(_charPos==_charLen){if(ReadBuffer()==0){returnnull;}}// fast path(intindexStart,intlength)=(_charPos,_charLen-_charPos);intindexOfNewLine=-1;intfastPathMaxLength=length%9;Span<char>span=_charBuffer.AsSpan(indexStart,fastPathMaxLength);intindex=fastPathMaxLength-1;while(index>-1){char@char=span[index];if(@charis'\r' or '\n'){indexOfNewLine=index;break;}index--;}if(indexOfNewLine!=-1){strings=newstring(_charBuffer,indexStart,indexOfNewLine);charch=_charBuffer[_charPos+indexOfNewLine];_charPos+=indexOfNewLine+1;// if it is two chars for the new-line character then inc the _charPosif(ch=='\r'&&(_charPos<_charLen||ReadBuffer()>0)){if(_charBuffer[_charPos]=='\n'){_charPos++;}}returns;}usingValueStringBuildersb=new(stackallocchar[256]);do{// Note the following common line feed chars:// \n - UNIX/Mac \r\n - Windows(indexStart,length)=(_charPos,_charLen-_charPos);indexOfNewLine=_charBuffer.AsSpan(indexStart,length).IndexOfAny('\r','\n');if(indexOfNewLine>=0){strings;if(sb.Length>0){sb.Append(_charBuffer.AsSpan(indexStart,indexOfNewLine));s=sb.ToString();}else{s=newstring(_charBuffer,indexStart,indexOfNewLine);}charch=_charBuffer[_charPos+indexOfNewLine];_charPos+=indexOfNewLine+1;// if it is two chars for the new-line character then inc the _charPosif(ch=='\r'&&(_charPos<_charLen||ReadBuffer()>0)){if(_charBuffer[_charPos]=='\n'){_charPos++;}}returns;}inttotalRead=_charLen-_charPos;sb.Append(_charBuffer.AsSpan(_charPos,totalRead));}while(ReadBuffer()>0);returnsb.ToString();}
BenchmarkDotNet=v0.13.1.1786-nightly, OS=macOS Monterey 12.3.1 (21E258) [Darwin 21.4.0]
Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK=7.0.100-preview.3.22179.4
[Host] : .NET 7.0.0 (7.0.22.17504), X64 RyuJIT
Job-QWLAYE : .NET 7.0.0 (42.42.42.42424), X64 RyuJIT
Job-PVIZJQ : .NET 7.0.0 (42.42.42.42424), X64 RyuJIT
PowerPlanMode=00000000-0000-0000-0000-000000000000 IterationTime=250.0000 ms MaxIterationCount=20 MinIterationCount=15 WarmupCount=1 
MethodJobToolchainNewLineLineLengthRangeMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1AllocatedAlloc Ratio
ReadLineJob-QWLAYE/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 0]95.46 μs0.791 μs0.701 μs95.26 μs94.64 μs96.88 μs0.990.0120.1982-3.27 KB0.04
ReadLineJob-PVIZJQ/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 0]96.53 μs0.817 μs0.764 μs96.49 μs95.33 μs97.69 μs1.000.00466.4634-74.52 KB1.00
ReadLineJob-QWLAYE/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 1024]41.34 μs0.633 μs0.592 μs41.20 μs40.14 μs42.26 μs2.040.03389.4857-62.2 KB1.72
ReadLineJob-PVIZJQ/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 0, 1024]20.29 μs0.259 μs0.229 μs20.28 μs19.87 μs20.59 μs1.000.00226.3446-36.21 KB1.00
ReadLineJob-QWLAYE/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 1]173.59 μs0.861 μs0.672 μs173.61 μs171.97 μs174.57 μs1.430.011223.110538.5174195.27 KB1.78
ReadLineJob-PVIZJQ/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 1]121.56 μs1.225 μs1.086 μs121.45 μs119.98 μs123.56 μs1.000.00687.5000-109.77 KB1.00
ReadLineJob-QWLAYE/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 8]127.14 μs1.310 μs1.022 μs127.11 μs125.24 μs129.05 μs0.890.01704.2026-112.4 KB1.08
ReadLineJob-PVIZJQ/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 1, 8]142.68 μs1.664 μs1.556 μs141.88 μs141.10 μs146.03 μs1.000.00649.5536-103.76 KB1.00
ReadLineJob-QWLAYE/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 9, 32]52.95 μs0.476 μs0.422 μs52.96 μs52.08 μs53.57 μs0.960.02352.9040-56.42 KB1.07
ReadLineJob-PVIZJQ/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 9, 32]55.26 μs0.663 μs0.620 μs55.15 μs54.46 μs56.29 μs1.000.00331.1404-52.59 KB1.00
ReadLineJob-QWLAYE/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 33, 128]37.09 μs0.412 μs0.385 μs37.07 μs36.51 μs37.93 μs1.350.03279.9233-44.7 KB1.12
ReadLineJob-PVIZJQ/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 33, 128]27.41 μs0.533 μs0.499 μs27.33 μs26.54 μs28.58 μs1.000.00250.0000-39.94 KB1.00
ReadLineJob-QWLAYE/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 129, 1024]41.62 μs0.685 μs0.640 μs41.56 μs40.53 μs42.85 μs2.020.04396.4793-63.39 KB1.73
ReadLineJob-PVIZJQ/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[ 129, 1024]20.58 μs0.199 μs0.176 μs20.62 μs20.23 μs20.88 μs1.000.00229.1398-36.68 KB1.00
ReadLineJob-QWLAYE/artifacts-main/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[1025, 2048]50.90 μs0.850 μs0.710 μs51.18 μs49.68 μs51.57 μs2.470.04522.33543.330790.86 KB2.44
ReadLineJob-PVIZJQ/artifacts/bin/testhost/net7.0-OSX-Release-x64/shared/Microsoft.NETCore.App/7.0.0/corerunN[1025, 2048]20.64 μs0.240 μs0.212 μs20.65 μs20.23 μs21.02 μs1.000.00230.7441-37.24 KB1.00

@danmoseley

Copy link
Copy Markdown
Contributor

I don't think you can have a faster path here without making shaky assumptions. I think just IndexOfAny is good.

@Trapov

Trapov commented May 13, 2022

Copy link
Copy Markdown
Author

@danmoseley Do we need something else in this PR or we still waiting on something? (I don't know what to change)

@Trapov

Copy link
Copy Markdown
Author

@danmoseley@adamsitnik any update on the PR?

@danmoseley

Copy link
Copy Markdown
Contributor

oops, overlooked this one. @stephentoub do you have any remaining concerns about the approach (I do think we need to stop returning to pool on array)

@stephentoub

Copy link
Copy Markdown
Member

@stephentoub do you have any remaining concerns about the approach

This is going to conflict with #69888. @GrabYourPitchforks' change is fixing some functional issues in addition to perf optimizations. I know this PR has been open longer, but I'd like to land @GrabYourPitchforks' change first and then revisit this.

@Trapov

Copy link
Copy Markdown
Author

I need to look into #69888 to merge it correctly then, I guess. Tag me, please, when it's going to be merged?

@Trapov

Copy link
Copy Markdown
Author

Any updates? @danmoseley

@danmoseley

Copy link
Copy Markdown
Contributor

@Trapov unfortunately #69888 was paused for a while as @GrabYourPitchforks was working on something else. That's been picked up again, although I see there's test failures. So unfortunately, this remains waiting..

@Trapov

Copy link
Copy Markdown
Author

No problem, just tag me please when it's going to be merged. @danmoseley

@stephentoub

Copy link
Copy Markdown
Member

@Trapov, thanks for your patience and for working on this. #69888 is about to be merged, but at this point I think it also covers most or all of what you were trying to accomplish in this PR. If there's anything additional to be done, once that's merged you can rebase and filter this down to just the incremental portions. Otherwise, we can probably close it. Again, thank you.

@Trapov

Trapov commented Nov 7, 2022

Copy link
Copy Markdown
Author

@stephentoub it covers mostly everything as you said. so probably better to close this PR.

@stephentoub

Copy link
Copy Markdown
Member

it covers mostly everything as you said. so probably better to close this PR.

Ok. Thanks very much, @Trapov.

@ghostghost locked as resolved and limited conversation to collaborators Dec 8, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.IOcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@Trapov@stephentoub@danmoseley@davidfowl@gfoidl@adamsitnik