Skip to content

Commit

Permalink
Alternative to use copy of core code
Browse files Browse the repository at this point in the history
  • Loading branch information
WinCPP committed Oct 9, 2017
1 parent 8278849 commit 45b0c45
Show file tree
Hide file tree
Showing 2 changed files with 223 additions and 30 deletions.
192 changes: 162 additions & 30 deletions src/System.Runtime.Extensions/src/System/IO/StreamWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,52 @@ public override void Write(char[] buffer)
return;
}

if (GetType() == typeof(StreamWriter))
CheckAsyncTaskInProgress();

// Threshold of 4 was chosen after running perf tests
if (buffer.Length <= 4)
{
WriteCore(new ReadOnlySpan<char>(buffer));
for (int i = 0; i < buffer.Length; i++)
{
if (_charPos == _charLen)
{
Flush(false, false);
}

Debug.Assert(_charLen - _charPos > 0, "StreamWriter::Write(char[]) isn't making progress! This is most likely a race in user code.");
_charBuffer[_charPos] = buffer[i];
_charPos++;
}
}
else
{
base.Write(buffer);
int count = buffer.Length;

int index = 0;
while (count > 0)
{
if (_charPos == _charLen)
{
Flush(false, false);
}

int n = _charLen - _charPos;
if (n > count)
{
n = count;
}

Debug.Assert(n > 0, "StreamWriter::Write(char[]) isn't making progress! This is most likely a race in user code.");
Buffer.BlockCopy(buffer, index * sizeof(char), _charBuffer, _charPos * sizeof(char), n * sizeof(char));
_charPos += n;
index += n;
count -= n;
}
}

if (_autoFlush)
{
Flush(true, false);
}
}

Expand All @@ -359,29 +398,56 @@ public override void Write(char[] buffer, int index, int count)
{
throw new ArgumentException(SR.Argument_InvalidOffLen);
}
if (GetType() == typeof(StreamWriter))

CheckAsyncTaskInProgress();

// Threshold of 4 was chosen after running perf tests
if (count <= 4)
{
WriteCore(new ReadOnlySpan<char>(buffer, index, count));
while (count > 0)
{
if (_charPos == _charLen)
{
Flush(false, false);
}

Debug.Assert(_charLen - _charPos > 0, "StreamWriter::Write(char[]) isn't making progress! This is most likely a race in user code.");
_charBuffer[_charPos] = buffer[index];
_charPos++;
index++;
count--;
}
}
else
{
base.Write(buffer, index, count);
}
}
while (count > 0)
{
if (_charPos == _charLen)
{
Flush(false, false);
}

public override void Write(ReadOnlySpan<char> source)
{
if (GetType() == typeof(StreamWriter))
{
WriteCore(source);
int n = _charLen - _charPos;
if (n > count)
{
n = count;
}

Debug.Assert(n > 0, "StreamWriter::Write(char[], int, int) isn't making progress! This is most likely a race condition in user code.");
Buffer.BlockCopy(buffer, index * sizeof(char), _charBuffer, _charPos * sizeof(char), n * sizeof(char));
_charPos += n;
index += n;
count -= n;
}
}
else

if (_autoFlush)
{
base.Write(source);
Flush(true, false);
}
}

private void WriteCore(ReadOnlySpan<char> source)
public override void Write(ReadOnlySpan<char> source)
{
CheckAsyncTaskInProgress();

Expand Down Expand Up @@ -441,13 +507,52 @@ public override void Write(string value)
return;
}

if (GetType() == typeof(StreamWriter))
CheckAsyncTaskInProgress();

int count = value.Length;

// Threshold of 4 was chosen after running perf tests
if (count <= 4)
{
WriteCore(value.AsReadOnlySpan());
for (int i = 0; i < count; i++)
{
if (_charPos == _charLen)
{
Flush(false, false);
}

Debug.Assert(_charLen - _charPos > 0, "StreamWriter::Write(String) isn't making progress! This is most likely a race condition in user code.");
_charBuffer[_charPos] = value[i];
_charPos++;
}
}
else
{
base.Write(value);
int index = 0;
while (count > 0)
{
if (_charPos == _charLen)
{
Flush(false, false);
}

int n = _charLen - _charPos;
if (n > count)
{
n = count;
}

Debug.Assert(n > 0, "StreamWriter::Write(String) isn't making progress! This is most likely a race condition in user code.");
value.CopyTo(index, _charBuffer, _charPos, n);
_charPos += n;
index += n;
count -= n;
}
}

if (_autoFlush)
{
Flush(true, false);
}
}

Expand All @@ -462,26 +567,53 @@ public override void WriteLine(string value)
value = String.Empty;
}

if (GetType() == typeof(StreamWriter))
CheckAsyncTaskInProgress();

int count = value.Length;
int index = 0;
while (count > 0)
{
if (_charPos == _charLen)
{
Flush(false, false);
}

int n = _charLen - _charPos;
if (n > count)
{
n = count;
}

Debug.Assert(n > 0, "StreamWriter::WriteLine(String) isn't making progress! This is most likely a race condition in user code.");
value.CopyTo(index, _charBuffer, _charPos, n);
_charPos += n;
index += n;
count -= n;
}

char[] coreNewLine = CoreNewLine;
for (int i = 0; i < coreNewLine.Length; i++) // Expect 2 iterations, no point calling BlockCopy
{
WriteLineCore(value.AsReadOnlySpan());
if (_charPos == _charLen)
{
Flush(false, false);
}

_charBuffer[_charPos] = coreNewLine[i];
_charPos++;
}
else

if (_autoFlush)
{
base.WriteLine(value);
Flush(true, false);
}
}

public override void WriteLine(ReadOnlySpan<char> source)
{
WriteLineCore(source);
}

private void WriteLineCore(ReadOnlySpan<char> value)
{
CheckAsyncTaskInProgress();

int count = value.Length;
int count = source.Length;
int index = 0;
while (count > 0)
{
Expand All @@ -497,7 +629,7 @@ private void WriteLineCore(ReadOnlySpan<char> value)
}

Debug.Assert(n > 0, "StreamWriter::WriteLine(String) isn't making progress! This is most likely a race condition in user code.");
value.Slice(index, n).CopyTo(new Span<char>(_charBuffer, _charPos, n));
source.Slice(index, n).CopyTo(new Span<char>(_charBuffer, _charPos, n));
_charPos += n;
index += n;
count -= n;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,67 @@ public void WriteString(int writeLength)
}
}

[Benchmark]
[MemberData(nameof(WriteLengthMemberData))]
public void WriteLineString(int writeLength)
{
string value = new string('a', writeLength);
int innerIterations = MemoryStreamSize / writeLength;
int outerIteration = TotalWriteCount / innerIterations;
using (var stream = new MemoryStream(MemoryStreamSize))
{
using (var writer = new StreamWriter(stream, new UTF8Encoding(false, true), DefaultStreamWriterBufferSize, true))
{
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < outerIteration; i++)
{
for (int j = 0; j < innerIterations; j++)
{
writer.WriteLine(value);
}
writer.Flush();
stream.Position = 0;
}
}
}
}
}
}

[Benchmark]
[MemberData(nameof(WriteLengthMemberData))]
public void WriteLineReadOnlySpan(int writeLength)
{
string value = new string('a', writeLength);
ReadOnlySpan<char> span = value.AsReadOnlySpan();
int innerIterations = MemoryStreamSize / writeLength;
int outerIteration = TotalWriteCount / innerIterations;
using (var stream = new MemoryStream(MemoryStreamSize))
{
using (var writer = new StreamWriter(stream, new UTF8Encoding(false, true), DefaultStreamWriterBufferSize, true))
{
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < outerIteration; i++)
{
for (int j = 0; j < innerIterations; j++)
{
writer.WriteLine(span);
}
writer.Flush();
stream.Position = 0;
}
}
}
}
}
}

public static IEnumerable<object[]> WriteLengthMemberData()
{
yield return new object[] { 2 };
Expand Down

0 comments on commit 45b0c45

Please sign in to comment.