diff --git a/src/benchmarks/micro/libraries/System.IO/MemoryStreamChunkedTests.cs b/src/benchmarks/micro/libraries/System.IO/MemoryStreamChunkedTests.cs
new file mode 100644
index 00000000000..46ec5b66949
--- /dev/null
+++ b/src/benchmarks/micro/libraries/System.IO/MemoryStreamChunkedTests.cs
@@ -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
+{
+ ///
+ /// 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.
+ ///
+ [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 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);
+ }
+ }
+}
diff --git a/src/benchmarks/micro/libraries/System.IO/MemoryStreamTests.cs b/src/benchmarks/micro/libraries/System.IO/MemoryStreamTests.cs
new file mode 100644
index 00000000000..24db4f653ee
--- /dev/null
+++ b/src/benchmarks/micro/libraries/System.IO/MemoryStreamTests.cs
@@ -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
+{
+ ///
+ /// 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.
+ ///
+ [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);
+ }
+ }
+}