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

Add BinaryWriter perf tests #1639

Merged
merged 2 commits into from
Jan 29, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using BenchmarkDotNet.Attributes;
using MicroBenchmarks;

namespace System.IO.Tests
{
[BenchmarkCategory(Categories.Libraries)]
public class BinaryWriterExtendedTests
{
private string _input;
private char[] _inputAsChars;
private BinaryWriter _bw;

[Params(4, 16, 512, 10_000, 100_000, 500_000, 2_000_000)]
Copy link
Member

Choose a reason for hiding this comment

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

can we reduce the number of test cases to the number of different code paths? https://github.com/dotnet/performance/blob/master/docs/microbenchmark-design-guidelines.md#Code-Paths

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, there should be 3 different code paths. How about 32 chars, 8k chars, and 2M chars?

Copy link
Member

Choose a reason for hiding this comment

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

How about 32 chars, 8k chars, and 2M chars?

👍

public int StringLengthInChars;

[GlobalSetup]
public void Setup()
{
_bw = new BinaryWriter(new NullWriteStream());

_input = new string('x', StringLengthInChars);
_inputAsChars = _input.ToCharArray();
}

[Benchmark]
public void WriteAsciiCharArray()
{
_bw.Write(_inputAsChars);
}

[Benchmark]
public void WriteAsciiString()
{
_bw.Write(_input);
}
}
}
72 changes: 72 additions & 0 deletions src/benchmarks/micro/libraries/System.IO/BinaryWriterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using BenchmarkDotNet.Attributes;
using MicroBenchmarks;

namespace System.IO.Tests
{
[BenchmarkCategory(Categories.Libraries)]
public class BinaryWriterTests
{
private BinaryWriter _bw;

[GlobalSetup]
public void Setup()
{
_bw = new BinaryWriter(new NullWriteStream());
}

[Benchmark]
public BinaryWriter DefaultCtor() => new BinaryWriter(Stream.Null);

[Benchmark]
public void WriteBool()
{
_bw.Write(true);
}

[Benchmark]
public void WriteAsciiChar()
{
_bw.Write('a');
}

[Benchmark]
public void WriteNonAsciiChar()
{
_bw.Write('\u00E0');
}

[Benchmark]
public void WriteUInt16()
{
_bw.Write((ushort)0xabcd);
}

[Benchmark]
public void WriteUInt32()
{
_bw.Write((uint)0xdeadbeef);
}

[Benchmark]
public void WriteUInt64()
{
_bw.Write((ulong)0xdeadbeef_aabbccdd);
}

[Benchmark]
public void WriteSingle()
{
_bw.Write((float)Math.PI);
}

[Benchmark]
public void WriteDouble()
{
_bw.Write((double)Math.PI);
}
}
}
62 changes: 62 additions & 0 deletions src/benchmarks/micro/libraries/System.IO/NullWriteStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Threading;
using System.Threading.Tasks;

namespace System.IO.Tests
{
/// <summary>
/// A <see cref="Stream"/> that acts as a null sink for data. Overrides members that
/// <see cref="Stream.Null"/> does not. Used for benchmarking wrappers around Stream
Copy link
Member

@adamsitnik adamsitnik Jan 28, 2021

Choose a reason for hiding this comment

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

thank you for adding a clear explanation why Stream.Null is not enough 👍

/// without benchmarking the implementation of the inner Stream itself.
/// </summary>
internal sealed class NullWriteStream : Stream
{
public override bool CanRead => false;

public override bool CanSeek => false;

public override bool CanWrite => true;

public override long Length => throw new NotSupportedException();

public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }

public override void Flush() { }

public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}

public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}

public override void SetLength(long value)
{
throw new NotSupportedException();
}
GrabYourPitchforks marked this conversation as resolved.
Show resolved Hide resolved

public override void Write(byte[] buffer, int offset, int count) { }

public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

public override void WriteByte(byte value) { }

#if NETCOREAPP2_1_OR_GREATER // these virtual methods only exist in .NET Core 2.1+
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 something new to me. Are you sure that it works outside of dotnet/runtime? cc @ViktorHofer

Copy link
Member Author

Choose a reason for hiding this comment

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

@terrajobst Aren't these defines part of the latest compilers? In theory they should work in any project type in any repo, even non-MSFT code.

public override void Write(ReadOnlySpan<byte> buffer) { }

public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
return ValueTask.CompletedTask;
}
#endif
}
}