diff --git a/Source/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj b/Source/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj index 9cac34d0..899b655f 100644 --- a/Source/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj +++ b/Source/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj @@ -1,6 +1,7 @@ - + + true Exe Full net6.0 diff --git a/Source/MQTTnet.Benchmarks/MemoryCopyBenchmark.cs b/Source/MQTTnet.Benchmarks/MemoryCopyBenchmark.cs new file mode 100644 index 00000000..39fa4f38 --- /dev/null +++ b/Source/MQTTnet.Benchmarks/MemoryCopyBenchmark.cs @@ -0,0 +1,40 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; +using System; + + +namespace MQTTnet.Benchmarks +{ + [SimpleJob(RuntimeMoniker.Net60)] + [RPlotExporter, RankColumn] + [MemoryDiagnoser] + public class MemoryCopyBenchmark + { + const int max_length = 1024 * 8; + private byte[] source; + private byte[] target; + + [Params(64 - 1, 128 - 1, 256 - 1, 512 - 1, 1024 - 1, 2048 - 1, 5096 - 1)] + public int Length { get; set; } + + [GlobalSetup] + public void Setup() + { + source = new byte[max_length]; + target = new byte[max_length]; + } + + [Benchmark(Baseline = true)] + public void Array_Copy() + { + Array.Copy(source, 0, target, 0, Length); + } + + [Benchmark] + public void Memory_Copy() + { + MQTTnet.Internal.Memory.Copy(source, 0, target, 0, Length); + } + + } +} \ No newline at end of file diff --git a/Source/MQTTnet/Formatter/MqttBufferReader.cs b/Source/MQTTnet/Formatter/MqttBufferReader.cs index 3aa820a6..4b3ef3c4 100644 --- a/Source/MQTTnet/Formatter/MqttBufferReader.cs +++ b/Source/MQTTnet/Formatter/MqttBufferReader.cs @@ -36,7 +36,7 @@ namespace MQTTnet.Formatter ValidateReceiveBuffer(length); var result = new byte[length]; - Array.Copy(_buffer, _position, result, 0, length); + Memory.Copy(_buffer, _position, result, 0, length); _position += length; return result; @@ -80,8 +80,7 @@ namespace MQTTnet.Formatter } var buffer = new byte[bufferLength]; - Array.Copy(_buffer, _position, buffer, 0, bufferLength); - + Memory.Copy(_buffer, _position, buffer, 0, bufferLength); _position += bufferLength; return buffer; diff --git a/Source/MQTTnet/Formatter/MqttBufferWriter.cs b/Source/MQTTnet/Formatter/MqttBufferWriter.cs index 7e740630..8e572d22 100644 --- a/Source/MQTTnet/Formatter/MqttBufferWriter.cs +++ b/Source/MQTTnet/Formatter/MqttBufferWriter.cs @@ -6,6 +6,7 @@ using System; using System.Runtime.CompilerServices; using System.Text; using MQTTnet.Exceptions; +using MQTTnet.Internal; using MQTTnet.Protocol; namespace MQTTnet.Formatter @@ -125,7 +126,7 @@ namespace MQTTnet.Formatter EnsureAdditionalCapacity(count); - Array.Copy(buffer, offset, _buffer, _position, count); + Memory.Copy(buffer, offset, _buffer, _position, count); IncreasePosition(count); } @@ -149,7 +150,7 @@ namespace MQTTnet.Formatter _buffer[_position] = (byte)(valueLength >> 8); _buffer[_position + 1] = (byte)valueLength; - Array.Copy(value, 0, _buffer, _position + 2, valueLength); + Memory.Copy(value, 0, _buffer, _position + 2, valueLength); IncreasePosition(valueLength + 2); } } diff --git a/Source/MQTTnet/Formatter/MqttPacketBuffer.cs b/Source/MQTTnet/Formatter/MqttPacketBuffer.cs index 8bdd51c8..7a3afea1 100644 --- a/Source/MQTTnet/Formatter/MqttPacketBuffer.cs +++ b/Source/MQTTnet/Formatter/MqttPacketBuffer.cs @@ -43,8 +43,8 @@ namespace MQTTnet.Formatter } var buffer = new byte[Length]; - Array.Copy(Packet.Array, Packet.Offset, buffer, 0, Packet.Count); - Array.Copy(Payload.Array, Payload.Offset, buffer, Packet.Count, Payload.Count); + Memory.Copy(Packet.Array, Packet.Offset, buffer, 0, Packet.Count); + Memory.Copy(Payload.Array, Payload.Offset, buffer, Packet.Count, Payload.Count); return buffer; } @@ -57,8 +57,8 @@ namespace MQTTnet.Formatter } var buffer = new byte[Length]; - Array.Copy(Packet.Array, Packet.Offset, buffer, 0, Packet.Count); - Array.Copy(Payload.Array, Payload.Offset, buffer, Packet.Count, Payload.Count); + Memory.Copy(Packet.Array, Packet.Offset, buffer, 0, Packet.Count); + Memory.Copy(Payload.Array, Payload.Offset, buffer, Packet.Count, Payload.Count); return new ArraySegment(buffer); } diff --git a/Source/MQTTnet/Internal/Memory.cs b/Source/MQTTnet/Internal/Memory.cs new file mode 100644 index 00000000..0d53f6aa --- /dev/null +++ b/Source/MQTTnet/Internal/Memory.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.CompilerServices; + +namespace MQTTnet.Internal +{ + public static class Memory + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Copy(byte[] source, int sourceIndex, byte[] destination, int destinationIndex, int length) + { +#if NETCOREAPP3_1_OR_GREATER || NETSTANDARD2_1 + source.AsSpan(sourceIndex, length).CopyTo(destination.AsSpan(destinationIndex, length)); +#elif NET461_OR_GREATER || NETSTANDARD1_3_OR_GREATER + unsafe + { + fixed (byte* pSoure = &source[sourceIndex]) + { + fixed (byte* pDestination = &destination[destinationIndex]) + { + System.Buffer.MemoryCopy(pSoure, pDestination, length, length); + } + } + } +#else + Array.Copy(source, sourceIndex, destination, destinationIndex, length); +#endif + } + } +} diff --git a/Source/MQTTnet/MQTTnet.csproj b/Source/MQTTnet/MQTTnet.csproj index c8bf7f0a..6153cce0 100644 --- a/Source/MQTTnet/MQTTnet.csproj +++ b/Source/MQTTnet/MQTTnet.csproj @@ -42,6 +42,7 @@ MIT true 1591 + true