From 96ccc5c23c185f484368e42611fa8b601461369a Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 27 Jan 2021 14:40:31 -0800 Subject: [PATCH 1/2] Add BinaryWriter perf tests --- .../System.IO/BinaryWriterExtendedTests.cs | 41 +++++++++++ .../libraries/System.IO/BinaryWriterTests.cs | 72 +++++++++++++++++++ .../libraries/System.IO/NullWriteStream.cs | 62 ++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 src/benchmarks/micro/libraries/System.IO/BinaryWriterExtendedTests.cs create mode 100644 src/benchmarks/micro/libraries/System.IO/BinaryWriterTests.cs create mode 100644 src/benchmarks/micro/libraries/System.IO/NullWriteStream.cs diff --git a/src/benchmarks/micro/libraries/System.IO/BinaryWriterExtendedTests.cs b/src/benchmarks/micro/libraries/System.IO/BinaryWriterExtendedTests.cs new file mode 100644 index 00000000000..5be8d969473 --- /dev/null +++ b/src/benchmarks/micro/libraries/System.IO/BinaryWriterExtendedTests.cs @@ -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)] + 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); + } + } +} diff --git a/src/benchmarks/micro/libraries/System.IO/BinaryWriterTests.cs b/src/benchmarks/micro/libraries/System.IO/BinaryWriterTests.cs new file mode 100644 index 00000000000..485330225d3 --- /dev/null +++ b/src/benchmarks/micro/libraries/System.IO/BinaryWriterTests.cs @@ -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); + } + } +} diff --git a/src/benchmarks/micro/libraries/System.IO/NullWriteStream.cs b/src/benchmarks/micro/libraries/System.IO/NullWriteStream.cs new file mode 100644 index 00000000000..e58fcf0672b --- /dev/null +++ b/src/benchmarks/micro/libraries/System.IO/NullWriteStream.cs @@ -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 +{ + /// + /// A that acts as a null sink for data. Overrides members that + /// does not. Used for benchmarking wrappers around Stream + /// without benchmarking the implementation of the inner Stream itself. + /// + 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(); + } + + 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+ + public override void Write(ReadOnlySpan buffer) { } + + public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + return ValueTask.CompletedTask; + } +#endif + } +} From 091380cc9dc4e663e1f337a6e909eeb22a1c3fcb Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Thu, 28 Jan 2021 14:02:22 -0800 Subject: [PATCH 2/2] PR feedback --- .../System.IO/BinaryWriterExtendedTests.cs | 2 +- .../libraries/System.IO/NullWriteStream.cs | 25 ++++--------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/benchmarks/micro/libraries/System.IO/BinaryWriterExtendedTests.cs b/src/benchmarks/micro/libraries/System.IO/BinaryWriterExtendedTests.cs index 5be8d969473..7a6c7d82dd5 100644 --- a/src/benchmarks/micro/libraries/System.IO/BinaryWriterExtendedTests.cs +++ b/src/benchmarks/micro/libraries/System.IO/BinaryWriterExtendedTests.cs @@ -14,7 +14,7 @@ public class BinaryWriterExtendedTests private char[] _inputAsChars; private BinaryWriter _bw; - [Params(4, 16, 512, 10_000, 100_000, 500_000, 2_000_000)] + [Params(32, 8_000, 2_000_000)] public int StringLengthInChars; [GlobalSetup] diff --git a/src/benchmarks/micro/libraries/System.IO/NullWriteStream.cs b/src/benchmarks/micro/libraries/System.IO/NullWriteStream.cs index e58fcf0672b..b0fe2238ecc 100644 --- a/src/benchmarks/micro/libraries/System.IO/NullWriteStream.cs +++ b/src/benchmarks/micro/libraries/System.IO/NullWriteStream.cs @@ -26,37 +26,22 @@ internal sealed class NullWriteStream : Stream public override void Flush() { } - public override int Read(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } + 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 long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) => throw new NotSupportedException(); 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 Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => Task.CompletedTask; public override void WriteByte(byte value) { } #if NETCOREAPP2_1_OR_GREATER // these virtual methods only exist in .NET Core 2.1+ public override void Write(ReadOnlySpan buffer) { } - public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) => ValueTask.CompletedTask; #endif } }