Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

CoreFx #22409 StreamWriter Span based API and tests #23915

Closed
wants to merge 5 commits into from

Conversation

WinCPP
Copy link

@WinCPP WinCPP commented Sep 9, 2017

This PR is for the Span based API for StreamWriter. Please note that this PR is dependent on PR #23786 for successful compilation.

@stephentoub @danmosemsft kindly review.

Fixes #22409.

Thanks,
Mandar

@@ -555,6 +571,11 @@ public override void WriteLine(string value)
}
}

public override void WriteLine(ReadOnlySpan<char> source)
{
WriteLine(new string(source.ToArray()));
Copy link
Member

Choose a reason for hiding this comment

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

This is very inefficient, allocating both a char[] and a string. At the very least a better implementation would be:

Write(source);
WriteLine();

but even better would be like the one that takes a string, except using the ReadOnlySpan<char> as the source, and unless there's a measurable perf regression we can't overcome, both this and the string-based overload should just delegate to the same private ReadOnlySpan<char>-based helper that has that logic. This one would then also do a check to make sure it's a concrete StreamWriter, and if it's not, just delegate to the base, e.g.

if (GetType() == typeof(StreamWriter))
{
    WriteLineCore(source);
}
else
{
    base.WriteLine(source);
}

Copy link
Author

Choose a reason for hiding this comment

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

Thanks @stephentoub . Actually I had changed WriteLine(string) to use ReadOnlySpan and then make existing string based overload delegate to it... But after we discussed about TextReader/Writer to use rented array, I thought that is something to be done across the board!

Copy link
Member

Choose a reason for hiding this comment

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

I thought that is something to be done across the board!

TextReader/Writer are abstract base classes: these methods needed to delegate there to the existing virtuals in order for them to get the correct behavior from existing overrides. But StreamReader/Writer are derived classes with their own implementations; as long as the instance is a concrete StreamReader/Writer and not something derived from it, we want them to have the most efficient implementations possible (and for the case where it's a derived type and thus where we still need to call an existing virtual method that may have been overridden), we just delegate to the base methods on TextReader/Writer that already do the appropriate delegation.

{
ArrayPool<char>.Shared.Return(buffer);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Similarly, this is inefficient. The implementation should look like that in Write(string), and ideally if there's no measurable perf regression from doing so, they should share an implementation in a helper, with this doing a type check and delegating to the base if it's not a concrete StreamWriter. The base already does this ArrayPool interaction.

Copy link
Author

Choose a reason for hiding this comment

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

Yup got it! thanks! I'm reverting the whole stuff, reinstate the previous WriteLine overload and do perf measurement for the String overload using the two ways - original and delegation to ReadOnlySpan based overload...

Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

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

Thank you for working on this. The implementations will need to be done differently before this can be merged.

@WinCPP
Copy link
Author

WinCPP commented Sep 10, 2017

@stephentoub I have pushed a newer implementation as per review comments. It is resulting into performance degradation for existing tests that work with entire char buffer of short length and, partial buffer of long or short length, though the string based overload appears to be performing better.

Please note that this doesn't have perf test for ReadOnlySpan specific implementations yet. Please see the below stats. I think the Write* tests would be the most relevant in this case.

Looks like I will have to work on improving the performance. Appreciate your inputs.

Original:
Test Name                                                                 | Metric   | Iterations | AVERAGE | STDEV.S |     MIN |     MAX
:------------------------------------------------------------------------- |:-------- |:----------:| -------:| -------:| -------:| -------:
 System.IO.Tests.Perf_Path.ChangeExtension                                 | Duration |     80     | 125.606 |   7.018 | 121.737 | 167.592
 System.IO.Tests.Perf_Path.Combine                                         | Duration |    100     |  77.092 |   5.920 |  74.908 | 113.829
 System.IO.Tests.Perf_Path.GetDirectoryName                                | Duration |     86     | 116.372 |   5.151 | 113.200 | 141.817
 System.IO.Tests.Perf_Path.GetExtension                                    | Duration |    100     |  75.498 |   4.477 |  72.960 |  95.368
 System.IO.Tests.Perf_Path.GetFileName                                     | Duration |    100     |  73.009 |   3.297 |  71.966 |  95.280
 System.IO.Tests.Perf_Path.GetFileNameWithoutExtension                     | Duration |     92     | 109.038 |   5.138 | 106.035 | 128.758
 System.IO.Tests.Perf_Path.GetFullPathForLegacyLength                      | Duration |     52     | 192.844 |   5.759 | 188.418 | 212.472
 System.IO.Tests.Perf_Path.GetFullPathForReallyLongPath                    | Duration |     44     | 227.775 |  22.479 | 211.128 | 283.944
 System.IO.Tests.Perf_Path.GetFullPathForTypicalLongPath                   | Duration |     51     | 197.226 |   3.991 | 194.924 | 215.009
 System.IO.Tests.Perf_Path.GetPathRoot                                     | Duration |     89     | 113.368 |   6.151 | 111.292 | 157.405
 System.IO.Tests.Perf_Path.GetRandomFileName                               | Duration |     70     | 143.118 |   9.032 | 137.412 | 177.923
 System.IO.Tests.Perf_Path.GetTempPath                                     | Duration |     31     | 329.121 |   7.968 | 322.004 | 355.915
 System.IO.Tests.Perf_Path.HasExtension                                    | Duration |    100     |  79.052 |   5.610 |  77.547 | 118.173
 System.IO.Tests.Perf_Path.IsPathRooted                                    | Duration |    100     |  94.520 |   4.307 |  93.139 | 125.516
 System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 100)        | Duration |     13     | 817.316 |   4.197 | 814.010 | 828.254
 System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 2)          | Duration |     96     | 105.000 |   1.798 | 104.316 | 115.244
 System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 100) | Duration |     13     | 812.313 |  11.383 | 804.757 | 840.191
 System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 2)   | Duration |     86     | 116.625 |   3.842 | 114.531 | 148.845
 System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 100)           | Duration |     13     | 784.501 |  13.234 | 776.421 | 818.972
 System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 2)             | Duration |     95     | 105.703 |   2.680 | 104.638 | 124.649
 System.Tests.Perf_Environment.ExpandEnvironmentVariables                  | Duration |     30     | 342.139 |  11.545 | 335.119 | 386.575
 System.Tests.Perf_Environment.GetEnvironmentVariable                      | Duration |     32     | 314.120 |  25.638 | 299.591 | 438.146
 System.Tests.Perf_Environment.GetEnvironmentVariables                     | Duration |     23     | 441.794 |  14.270 | 430.641 | 480.419
 System.Tests.Perf_Environment.GetFolderPath(folder: System, option: None) | Duration |     68     | 148.679 |  11.890 | 142.121 | 210.963
 System.Tests.Perf_Environment.GetLogicalDrives                            | Duration |    100     |  96.552 |   5.154 |  93.076 | 123.589
 System.Tests.Perf_Random.ctor                                             | Duration |     27     | 375.762 |   4.940 | 372.021 | 388.897
 System.Tests.Perf_Random.Next_int                                         | Duration |    100     |  79.727 |   3.877 |  76.907 |  94.131
 System.Tests.Perf_Random.Next_int_int                                     | Duration |    100     |  81.671 |   2.404 |  80.909 |  94.861
 System.Tests.Perf_Random.NextBytes                                        | Duration |     36     | 284.650 |   7.907 | 279.646 | 320.651
 System.Tests.Perf_Random.NextDouble                                       | Duration |    100     |  54.804 |   1.478 |  54.417 |  63.178

Updated code:
 Test Name                                                                 | Metric   | Iterations | AVERAGE | STDEV.S |     MIN |     MAX
:------------------------------------------------------------------------- |:-------- |:----------:| -------:| -------:| -------:| -------:
 System.IO.Tests.Perf_Path.ChangeExtension                                 | Duration |     63     | 159.384 |   9.150 | 129.554 | 190.317
 System.IO.Tests.Perf_Path.Combine                                         | Duration |    100     |  76.090 |   1.415 |  75.494 |  87.101
 System.IO.Tests.Perf_Path.GetDirectoryName                                | Duration |     76     | 132.466 |  20.440 | 104.463 | 214.747
 System.IO.Tests.Perf_Path.GetExtension                                    | Duration |    100     |  85.609 |  17.042 |  73.752 | 113.451
 System.IO.Tests.Perf_Path.GetFileName                                     | Duration |    100     |  83.516 |   1.619 |  82.492 |  93.713
 System.IO.Tests.Perf_Path.GetFileNameWithoutExtension                     | Duration |     84     | 120.429 |  10.281 | 108.791 | 157.672
 System.IO.Tests.Perf_Path.GetFullPathForLegacyLength                      | Duration |     49     | 205.809 |  20.449 | 190.959 | 267.514
 System.IO.Tests.Perf_Path.GetFullPathForReallyLongPath                    | Duration |     46     | 221.244 |   8.222 | 216.011 | 261.907
 System.IO.Tests.Perf_Path.GetFullPathForTypicalLongPath                   | Duration |     50     | 203.514 |  13.406 | 197.659 | 292.193
 System.IO.Tests.Perf_Path.GetPathRoot                                     | Duration |     88     | 114.668 |   4.970 | 112.742 | 138.047
 System.IO.Tests.Perf_Path.GetRandomFileName                               | Duration |     70     | 142.972 |   4.443 | 138.099 | 156.078
 System.IO.Tests.Perf_Path.GetTempPath                                     | Duration |     30     | 337.125 |   7.103 | 331.271 | 362.863
 System.IO.Tests.Perf_Path.HasExtension                                    | Duration |    100     |  84.931 |   1.931 |  84.113 | 101.269
 System.IO.Tests.Perf_Path.IsPathRooted                                    | Duration |    100     |  99.613 |   0.912 |  99.116 | 108.088
 System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 100)        | Duration |     13     | 806.761 |   3.767 | 802.160 | 814.499
 System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 2)          | Duration |     76     | 132.347 |   1.321 | 128.351 | 136.306
 System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 100) | Duration |     11     | 919.366 |  15.691 | 908.505 | 957.997
 System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 2)   | Duration |     39     | 261.271 |  12.834 | 251.458 | 297.790
 System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 100)           | Duration |     13     | 784.352 |  11.449 | 775.134 | 811.231
 System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 2)             | Duration |     97     | 103.479 |   2.430 | 101.178 | 119.971
 System.Tests.Perf_Environment.ExpandEnvironmentVariables                  | Duration |     28     | 365.699 |  20.240 | 342.212 | 424.230
 System.Tests.Perf_Environment.GetEnvironmentVariable                      | Duration |     33     | 306.924 |   2.998 | 302.878 | 318.850
 System.Tests.Perf_Environment.GetEnvironmentVariables                     | Duration |     22     | 472.029 |   9.493 | 461.578 | 500.891
 System.Tests.Perf_Environment.GetFolderPath(folder: System, option: None) | Duration |     62     | 162.907 |  21.642 | 147.744 | 231.314
 System.Tests.Perf_Environment.GetLogicalDrives                            | Duration |     98     | 102.546 |   3.898 |  99.628 | 117.238
 System.Tests.Perf_Random.ctor                                             | Duration |     27     | 381.606 |   4.651 | 377.079 | 394.761
 System.Tests.Perf_Random.Next_int                                         | Duration |    100     |  82.146 |   1.011 |  81.553 |  87.450
 System.Tests.Perf_Random.Next_int_int                                     | Duration |    100     |  85.160 |   2.124 |  84.091 |  94.683
 System.Tests.Perf_Random.NextBytes                                        | Duration |     36     | 282.844 |   3.062 | 280.863 | 298.054
 System.Tests.Perf_Random.NextDouble                                       | Duration |    100     |  61.667 |   0.997 |  61.306 |  70.329

@WinCPP
Copy link
Author

WinCPP commented Sep 12, 2017

@stephentoub I am not able to understand how to settle down for a particular performance reading. I removed all the changes and reran the perf test for Write* calls with original code and got a bit different numbers today for same set that I ran two days back (under the heading Original).

Original (2 days back)

Test Name Metric Iterations AVERAGE STDEV.S MIN MAX
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 100) Duration 13 817.316 4.197 814.010 828.254
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 2) Duration 96 105.000 1.798 104.316 115.244
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 100) Duration 13 812.313 11.383 804.757 840.191
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 2) Duration 86 116.625 3.842 114.531 148.845
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 100) Duration 13 784.501 13.234 776.421 818.972
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 2) Duration 95 105.703 2.680 104.638 124.649

ReRun (without any changes)

Test Name Metric Iterations AVERAGE STDEV.S MIN MAX
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 100) Duration 13 805.942 2.034 801.808 808.154
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 2) Duration 74 135.393 5.805 131.021 167.140
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 100) Duration 12 902.028 1.705 899.634 904.939
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 2) Duration 84 119.328 2.978 116.715 140.478
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 100) Duration 13 791.115 24.880 781.270 873.499
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 2) Duration 97 103.789 0.665 100.623 104.626

@stephentoub
Copy link
Member

I am not able to understand how to settle down for a particular performance reading. I removed all the changes and reran the perf test for Write* calls with original code and got a bit different numbers today for same set that I ran two days back (under the heading Original).

It could be that the tests aren't particularly stable, meaning there's too much variation and work needs to be done to reign in the results.

It could also be that you had other things happening on your machine the two times you ran them, perturbing the results.

@WinCPP
Copy link
Author

WinCPP commented Oct 5, 2017

Resuming work... rebased from the dotnet/master... Please ignore latest commit... it is just to sync the branch.

@stephentoub
Copy link
Member

Resuming work

Thanks :)

@WinCPP
Copy link
Author

WinCPP commented Oct 5, 2017

Hi @stephentoub I rebased and now when I try to run the perf test, it gives me an error as below. I have posted the same on gitter as well, just in case someone knows or has encountered it. But I did nothing special, just rebased to get in merged code for #22406 and other stuff. I have even tried .\clean.cmd -b -c -p to get all the packages once again. Still no luck... Appreciate your advise! Thanks!

RunTestsForProject:
  D:\WinCPP\corefx\bin/tests/System.Runtime.Extensions.Performance.Tests/netcoreapp-Windows_NT-Release-x64//RunTests.cmd D:\WinCPP\corefx\bin/testhost/netcoreapp-Windows_NT-Releas
  e-x64/
  Using D:\WinCPP\corefx\bin\testhost\netcoreapp-Windows_NT-Release-x64\ as the test runtime folder.
  Executing in D:\WinCPP\corefx\bin\tests\System.Runtime.Extensions.Performance.Tests\netcoreapp-Windows_NT-Release-x64\
  Running tests... Start time:  1:51:52.63
  The application to execute does not exist: 'D:\WinCPP\corefx\bin\tests\System.Runtime.Extensions.Performance.Tests\netcoreapp-Windows_NT-Release-x64\PerfRunner.exe'

  Finished running tests.  End time= 1:51:52.63, Exit code = -2147450751

@stephentoub
Copy link
Member

@WinCPP, this is most likely https://github.com/dotnet/corefx/issues/24153.

@WinCPP
Copy link
Author

WinCPP commented Oct 7, 2017

@stephentoub following is the latest numbers for performance. Looks like performance for all the Write(...) calls has degraded. I am not sure if this looks good... Surprisingly, the performance for Write(ReadOnlySpan) (i.e. the perf test named WriteReadOnlySpan is even worse that any of the other Write overloads which call the same core function. In case of WriteReadOnlySpan, the Write(ReadOnlySpan) just delegates to WriteCore(ReadOnlySpan).... Does that indicate that it would be better not to extract common code into WriteCore(ReadOnlySpan) and instead just have Write(ReadOnlySpan) overload as a verbatim copy of other Write overloads with relevant changes to use a ReadOnlySpan? Appreciate your inputs.

Test Name Metric Iterations AVERAGE STDEV.S MIN MAX
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 100) Duration 13 798.518 0.438 798.073 799.686
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 2) Duration 74 135.132 3.274 131.508 153.247
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 100) Duration 13 799.316 8.691 794.462 818.519
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 2) Duration 85 118.872 2.043 116.351 136.529
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 100) Duration 13 775.294 22.465 768.003 850.024
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 2) Duration 97 103.992 0.162 103.920 105.323

With Core function

Test Name Metric Iterations AVERAGE STDEV.S MIN MAX
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 100) Duration 12 889.565 1.306 888.573 892.380
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 2) Duration 44 227.813 1.062 227.392 234.177
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 100) Duration 12 902.819 0.514 901.980 903.925
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 2) Duration 40 251.832 5.477 249.513 275.596
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 100) Duration 12 889.898 4.094 888.376 902.874
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 2) Duration 44 231.049 0.164 230.711 231.469
System.IO.Tests.Perf_StreamWriter.WriteReadOnlySpan(writeLength: 100) Duration 11 935.819 0.558 935.225 937.121
System.IO.Tests.Perf_StreamWriter.WriteReadOnlySpan(writeLength: 2) Duration 30 336.390 0.119 336.212 336.693

Please note that there are no performance tests for WriteLine in the original project... I will work on getting those numbers but in the meantime thought of checking with you in case we don't want to use the Write*Core common function.

@WinCPP
Copy link
Author

WinCPP commented Oct 7, 2017

@dotnet-bot test Linux arm Release Build please

@WinCPP
Copy link
Author

WinCPP commented Oct 8, 2017

@stephentoub , as mentioned in previous comment here, following is the data for the alternate implementation in which the Write and WriteLine calls do not delegate to ReadOnlySpan based Core functions. Essentially,

  1. Existing Write and WriteLine implementations have been left untouched (i.e. contains a copy of the core code with additional validations of input parameters.)
  2. On similar lines Write and WriteLine overloads have been introduced for ReadOnlySpan by using a copy of the core code.

Observation - performance for existing functions almost remains unaltered. Although, the ReadOnlySpan based implementations appear to be comparatively slower.

Looks like making a copy of core code (as per practice in the file), instead of calling a core code method, appears to be the better approach for adding two new overloads? Appreciate your thoughts.

Notes:

  1. The code for below performance data is on my machine, not yet checked in to this PR. I didn't want to disturb / overwrite the last checked in code for which the perf data is mentioned in previous comment.
  2. I have taken fresh performance data for the original code (without ReadOnlySpan APIs). Please note that it differs from old "original" perf data. Perhaps because I rebased my branch since then... But this one appears to be more stable.
  3. Current source doesn't have code to capture performance data for WriteLine.

Original performance data (without implementing the ReadOnlySpan overloads)

Test Name Metric Iterations AVERAGE STDEV.S MIN MAX
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 100) Duration 13 805.416 0.473 804.487 806.133
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 2) Duration 96 104.417 0.629 103.984 106.340
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 100) Duration 13 805.851 0.568 805.230 806.861
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 2) Duration 90 112.099 0.243 111.841 113.874
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 100) Duration 14 756.623 7.952 753.811 784.218
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 2) Duration 96 104.357 0.500 104.096 108.172
System.IO.Tests.Perf_StreamWriter.WriteLineString(writeLength: 100) Duration 13 811.572 0.720 810.693 813.310
System.IO.Tests.Perf_StreamWriter.WriteLineString(writeLength: 2) Duration 48 210.784 7.815 209.450 263.735

After adding ReadOnlySpan overloads that use copy of the core code.

Test Name Metric Iterations AVERAGE STDEV.S MIN MAX
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 100) Duration 13 801.007 0.288 800.620 801.661
System.IO.Tests.Perf_StreamWriter.WriteCharArray(writeLength: 2) Duration 99 101.512 3.182 100.104 123.747
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 100) Duration 13 807.687 4.286 805.815 821.839
System.IO.Tests.Perf_StreamWriter.WritePartialCharArray(writeLength: 2) Duration 81 124.540 4.116 117.070 129.055
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 100) Duration 14 757.697 8.085 754.250 785.700
System.IO.Tests.Perf_StreamWriter.WriteString(writeLength: 2) Duration 87 115.886 0.413 115.412 118.509
System.IO.Tests.Perf_StreamWriter.WriteReadOnlySpan(writeLength: 100) Duration 11 928.066 2.871 925.612 936.448
System.IO.Tests.Perf_StreamWriter.WriteReadOnlySpan(writeLength: 2) Duration 30 334.497 0.396 333.569 335.511
System.IO.Tests.Perf_StreamWriter.WriteLineString(writeLength: 100) Duration 13 811.566 0.531 810.621 812.311
System.IO.Tests.Perf_StreamWriter.WriteLineString(writeLength: 2) Duration 48 210.127 0.413 209.454 211.228
System.IO.Tests.Perf_StreamWriter.WriteLineReadOnlySpan(writeLength: 100) Duration 11 913.514 10.915 908.675 946.279
System.IO.Tests.Perf_StreamWriter.WriteLineReadOnlySpan(writeLength: 2) Duration 31 328.013 2.569 324.327 332.400

@stephentoub
Copy link
Member

Thanks. I would like us to try to avoid duplicating the code. I will try to look tomorrow.

@WinCPP
Copy link
Author

WinCPP commented Oct 9, 2017

Thank you! To check the implementation that uses duplicated code, please refer here. This is a temp branch in which I have parked the code.

@stephentoub
Copy link
Member

Just FYI, I haven't forgotten about this... just had to switch to some other things, and I'll get back to it soon...

@WinCPP
Copy link
Author

WinCPP commented Oct 11, 2017

Yup I understand! Thank you! In the meantime I am working StreamReader overload implementation #22408, writing test cases and, getting baseline and overload implementation performance data...

@WinCPP
Copy link
Author

WinCPP commented Oct 15, 2017

Hi @stephentoub I was wondering if this will require exposing some new overload such as ReadOnlySpan.CopyTo(srcIndex, destination, destIndex, copyCount) or something which will allow copying from ReadOnlySpan to Span e.g. Line 424 which is as follows,

source.Slice(index, n).CopyTo(new Span<char>(_charBuffer, _charPos, n));

I suspect creating slices of ReadOnlySpan and allocating new inline Span in each iteration is consuming time because there will be validation overload in creating both and then again in the CopyTo method? I am not sure, but thinking aloud.

I believe this is more involved stuff than it appears and might require some deeper knowledge, so would you mind taking taking over this PR and associated issue #22409...? I will move to something simpler.

Thanks!

@stephentoub
Copy link
Member

would you mind taking taking over this issue and associated PR...?

No problem. Thanks for your efforts.

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.

6 participants