Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
150 changes: 150 additions & 0 deletions src/benchmarks/micro/libraries/System.IO/MemoryStreamChunkedTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// 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;
using BenchmarkDotNet.Attributes;
using MicroBenchmarks;

namespace System.IO.Tests
{
/// <summary>
/// Chunked / buffered operations. Fixed 64KB stream, chunk size controls call count.
/// Read/Write variants loop over the stream in ChunkSize increments.
/// CopyTo / CopyToAsync pass ChunkSize as the bufferSize parameter.
/// </summary>
[BenchmarkCategory(Categories.Libraries)]
public class MemoryStreamChunkedTests
{
private const int StreamSize = 65536;

private MemoryStream _stream;
private byte[] _buffer;

[Params(
1, // 65536 calls, per-call overhead dominates
4096)] // 16 calls, default StreamReader/BufferedStream buffer size
public int ChunkSize { get; set; }

[GlobalSetup]
public void Setup()
{
byte[] backing = new byte[StreamSize];
new Random(42).NextBytes(backing);
_buffer = new byte[ChunkSize];
_stream = new MemoryStream(backing, writable: true);
}

[GlobalCleanup]
public void Cleanup()
{
_stream.Dispose();
}

[Benchmark]
[MemoryRandomization]
public int ReadByteArray()
{
MemoryStream s = _stream;
s.Position = 0;
int count = 0;
int n;
while ((n = s.Read(_buffer, 0, _buffer.Length)) > 0)
count += n;
return count;
}

[Benchmark]
[MemoryRandomization]
public int ReadSpan()
{
MemoryStream s = _stream;
s.Position = 0;
int count = 0;
int n;
while ((n = s.Read(_buffer.AsSpan())) > 0)
count += n;
return count;
}

[Benchmark]
[BenchmarkCategory(Categories.NoWASM)]
[MemoryRandomization]
public async Task<int> ReadAsyncMemory()
{
MemoryStream s = _stream;
s.Position = 0;
int count = 0;
int n;
while ((n = await s.ReadAsync(_buffer, CancellationToken.None)) > 0)
count += n;
return count;
}

[Benchmark]
[MemoryRandomization]
public void WriteByteArray()
{
MemoryStream s = _stream;
s.Position = 0;
int remaining = StreamSize;
while (remaining > 0)
{
int chunk = Math.Min(_buffer.Length, remaining);
s.Write(_buffer, 0, chunk);
remaining -= chunk;
}
}

[Benchmark]
[MemoryRandomization]
public void WriteSpan()
{
MemoryStream s = _stream;
s.Position = 0;
int remaining = StreamSize;
while (remaining > 0)
{
int chunk = Math.Min(_buffer.Length, remaining);
s.Write(_buffer.AsSpan(0, chunk));
remaining -= chunk;
}
}

[Benchmark]
[BenchmarkCategory(Categories.NoWASM)]
[MemoryRandomization]
public async Task WriteAsyncMemory()
{
MemoryStream s = _stream;
s.Position = 0;
int remaining = StreamSize;
while (remaining > 0)
{
int chunk = Math.Min(_buffer.Length, remaining);
await s.WriteAsync(_buffer.AsMemory(0, chunk), CancellationToken.None);
remaining -= chunk;
}
}

[Benchmark]
[MemoryRandomization]
public void CopyToWithBufferSize()
{
MemoryStream s = _stream;
s.Position = 0;
s.CopyTo(Stream.Null, ChunkSize);
}

[Benchmark]
[BenchmarkCategory(Categories.NoWASM)]
[MemoryRandomization]
public async Task CopyToAsyncWithBufferSize()
{
MemoryStream s = _stream;
s.Position = 0;
await s.CopyToAsync(Stream.Null, ChunkSize);
}
}
}
81 changes: 81 additions & 0 deletions src/benchmarks/micro/libraries/System.IO/MemoryStreamTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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.Tasks;
using BenchmarkDotNet.Attributes;
using MicroBenchmarks;

namespace System.IO.Tests
{
/// <summary>
/// Operations that do not receive a user buffer. Backing size controls iteration count.
/// ReadByte / WriteByte exercise per-byte overhead; CopyTo / CopyToAsync use the
/// default buffer size overload.
/// </summary>
[BenchmarkCategory(Categories.Libraries)]
public class MemoryStreamTests
{
private MemoryStream _stream;

[Params(
1024, // small stream
65536)] // large stream
public int Size { get; set; }

[GlobalSetup]
public void Setup()
{
byte[] backing = new byte[Size];
new Random(42).NextBytes(backing);
_stream = new MemoryStream(backing, writable: true);
}

[GlobalCleanup]
public void Cleanup()
{
_stream.Dispose();
}

[Benchmark]
[MemoryRandomization]
public int ReadByte()
{
MemoryStream s = _stream;
s.Position = 0;
int count = 0;
while (s.ReadByte() != -1)
count++;
return count;
}

[Benchmark]
[MemoryRandomization]
public void WriteByte()
{
MemoryStream s = _stream;
s.Position = 0;
for (int i = 0; i < Size; i++)
s.WriteByte((byte)i);
}

[Benchmark]
[MemoryRandomization]
public void CopyTo()
{
MemoryStream s = _stream;
s.Position = 0;
s.CopyTo(Stream.Null);
}

[Benchmark]
[BenchmarkCategory(Categories.NoWASM)]
[MemoryRandomization]
public async Task CopyToAsync()
{
MemoryStream s = _stream;
s.Position = 0;
await s.CopyToAsync(Stream.Null);
}
}
}