diff --git a/Benchmarking/Benchmark/Benchmark.csproj b/Benchmarking/Benchmark/Benchmark.csproj index ec53112..56eb5f7 100644 --- a/Benchmarking/Benchmark/Benchmark.csproj +++ b/Benchmarking/Benchmark/Benchmark.csproj @@ -7,7 +7,7 @@ - + diff --git a/Benchmarking/Benchmark/Program.cs b/Benchmarking/Benchmark/Program.cs index 16a0924..fe51c0a 100644 --- a/Benchmarking/Benchmark/Program.cs +++ b/Benchmarking/Benchmark/Program.cs @@ -11,8 +11,11 @@ namespace Benchmark { static void Main(string[] args) { - BenchmarkRunner.Run(); - BenchmarkRunner.Run(); + if (args.Length == 0 || args[0] == "grpc") + BenchmarkRunner.Run(); + + if (args.Length == 0 || args[0] == "capnp") + BenchmarkRunner.Run(); } } } diff --git a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj index ebbd9c6..317f6be 100644 --- a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj +++ b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs index ca05312..8205ee4 100644 --- a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs @@ -17,7 +17,7 @@ namespace Capnp.Rpc /// Buffer size (bytes). You should choose it according to the maximum expected raw capnp frame size public static void AddBuffering(this ISupportsMidlayers obj, int bufferSize) { - obj.InjectMidlayer(s => new Util.BufferedNetworkStreamAdapter(s, bufferSize)); + obj.InjectMidlayer(s => new Util.WriteBufferedStream(new Util.BufferedNetworkStreamAdapter(s, bufferSize), bufferSize)); } /// @@ -27,7 +27,7 @@ namespace Capnp.Rpc /// or public static void AddBuffering(this ISupportsMidlayers obj) { - obj.InjectMidlayer(s => new Util.BufferedNetworkStreamAdapter(s)); + obj.InjectMidlayer(s => new Util.WriteBufferedStream(new Util.BufferedNetworkStreamAdapter(s))); } } } diff --git a/Capnp.Net.Runtime/Util/WriteBufferedStream.cs b/Capnp.Net.Runtime/Util/WriteBufferedStream.cs new file mode 100644 index 0000000..6e91c9d --- /dev/null +++ b/Capnp.Net.Runtime/Util/WriteBufferedStream.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; + +namespace Capnp.Util +{ + internal class WriteBufferedStream : Stream + { + // A buffer size of 1024 bytes seems to be a good comprise, giving good performance + // in TCP/IP-over-localhost scenarios for small to medium (200kiB) frame sizes. + const int DefaultBufferSize = 1024; + + readonly Stream _readStream; + readonly BufferedStream _writeStream; + readonly int _bufferSize; + readonly object _reentrancyBlocker = new object(); + + public WriteBufferedStream(Stream stream, int bufferSize) + { + _readStream = stream; + _writeStream = new BufferedStream(stream, bufferSize); + _bufferSize = bufferSize; + } + + public WriteBufferedStream(Stream stream) : this(stream, DefaultBufferSize) + { + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => 0; + + public override long Position + { + get => 0; + set => throw new NotSupportedException(); + } + + public override void Flush() + { + _writeStream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _readStream.Read(buffer, offset, count); + } + + 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) + { + if (buffer.Length > _bufferSize) // avoid moiré-like timing effects + _writeStream.Flush(); + + _writeStream.Write(buffer, offset, count); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + lock (_reentrancyBlocker) + { + try + { + _readStream.Dispose(); + } + catch + { + } + try + { + _writeStream.Dispose(); + } + catch + { + } + } + } + + base.Dispose(disposing); + } + } +}