diff --git a/Tests/MQTTnet.Benchmarks/ChannelAdapterBenchmark.cs b/Tests/MQTTnet.Benchmarks/ChannelAdapterBenchmark.cs new file mode 100644 index 00000000..5f66e6bc --- /dev/null +++ b/Tests/MQTTnet.Benchmarks/ChannelAdapterBenchmark.cs @@ -0,0 +1,107 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Exporters; +using BenchmarkDotNet.Attributes.Jobs; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Validators; +using MQTTnet.Adapter; +using MQTTnet.Core.Internal; +using MQTTnet.Diagnostics; +using MQTTnet.Internal; +using MQTTnet.Packets; +using MQTTnet.Serializer; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace MQTTnet.Benchmarks +{ + public class AllowNonOptimized : ManualConfig + { + public AllowNonOptimized() + { + Add(JitOptimizationsValidator.DontFailOnError); // ALLOW NON-OPTIMIZED DLLS + Add(DefaultConfig.Instance.GetLoggers().ToArray()); // manual config has no loggers by default + Add(DefaultConfig.Instance.GetExporters().ToArray()); // manual config has no exporters by default + Add(DefaultConfig.Instance.GetColumnProviders().ToArray()); // manual config has no columns by default + Add(Job.InProcess); + } + } + + [MemoryDiagnoser] + public class ChannelAdapterBenchmark + { + private MqttChannelAdapter _channelAdapter; + private int _iterations; + private MemoryStream _stream; + private MqttPublishPacket _packet; + + [GlobalSetup] + public void Setup() + { + var message = new MqttApplicationMessageBuilder() + .WithTopic("A") + .Build(); + + _packet = message.ToPublishPacket(); + var serializer = new MqttPacketSerializer(); + var serializedPacket = Join(serializer.Serialize(_packet)); + + _iterations = 10000; + + _stream = new MemoryStream(_iterations * serializedPacket.Length); + + for (var i = 0; i < _iterations; i++) + { + _stream.Write(serializedPacket, 0, serializedPacket.Length); + } + + _stream.Position = 0; + + var channel = new TestMqttChannel(_stream); + + _channelAdapter = new MqttChannelAdapter(channel, serializer, new MqttNetLogger().CreateChildLogger(nameof(MqttChannelAdapter))); + } + + [Benchmark] + public void Receive_10000_Messages() + { + _stream.Position = 0; + + for (var i = 0; i < 10000; i++) + { + _channelAdapter.ReceivePacketAsync(TimeSpan.Zero, CancellationToken.None).GetAwaiter().GetResult(); + } + + _stream.Position = 0; + } + + [Benchmark] + public void Send_10000_Messages() + { + _stream.Position = 0; + + for (var i = 0; i < 10000; i++) + { + _channelAdapter.SendPacketsAsync(TimeSpan.FromSeconds(15), new[] { _packet }, CancellationToken.None).GetAwaiter().GetResult(); + } + + _stream.Position = 0; + } + + private static byte[] Join(params ArraySegment[] chunks) + { + var buffer = new MemoryStream(); + foreach (var chunk in chunks) + { + buffer.Write(chunk.Array, chunk.Offset, chunk.Count); + } + + return buffer.ToArray(); + } + } +} diff --git a/Tests/MQTTnet.Benchmarks/MqttTcpChannelBenchmark.cs b/Tests/MQTTnet.Benchmarks/MqttTcpChannelBenchmark.cs new file mode 100644 index 00000000..6709ff79 --- /dev/null +++ b/Tests/MQTTnet.Benchmarks/MqttTcpChannelBenchmark.cs @@ -0,0 +1,52 @@ +using BenchmarkDotNet.Attributes; +using MQTTnet.Adapter; +using MQTTnet.Channel; +using MQTTnet.Client; +using MQTTnet.Diagnostics; +using MQTTnet.Implementations; +using MQTTnet.Server; +using System.Threading; + +namespace MQTTnet.Benchmarks +{ + [MemoryDiagnoser] + public class MqttTcpChannelBenchmark + { + private IMqttServer _mqttServer; + private IMqttChannel _clientChannel; + private IMqttChannel _serverChannel; + + [GlobalSetup] + public void Setup() + { + var factory = new MqttFactory(); + var tcpServer = new MqttTcpServerAdapter(new MqttNetLogger().CreateChildLogger()); + tcpServer.ClientAccepted += (sender, args) => _serverChannel = (IMqttChannel)args.Client.GetType().GetField("_channel", System.Reflection.BindingFlags.NonPublic| System.Reflection.BindingFlags.Instance).GetValue(args.Client); + + _mqttServer = factory.CreateMqttServer(new[] { tcpServer }, new MqttNetLogger()); + + var serverOptions = new MqttServerOptionsBuilder().Build(); + _mqttServer.StartAsync(serverOptions).GetAwaiter().GetResult(); + + var clientOptions = new MqttClientOptionsBuilder() + .WithTcpServer("localhost").Build(); + + _clientChannel = new MqttTcpChannel((MqttClientTcpOptions)clientOptions.ChannelOptions); + + _clientChannel.ConnectAsync(CancellationToken.None).GetAwaiter().GetResult(); + } + + [Benchmark] + public void Send_10000_Chunks() + { + var size = 5; + var iterations = 10000; + for (var i = 0; i < iterations; i++) + { + _serverChannel.WriteAsync(new byte[size], 0, size, CancellationToken.None).GetAwaiter().GetResult(); + _clientChannel.ReadAsync(new byte[size], 0, size, CancellationToken.None).GetAwaiter().GetResult(); + } + + } + } +} diff --git a/Tests/MQTTnet.Benchmarks/Program.cs b/Tests/MQTTnet.Benchmarks/Program.cs index a65de421..e643e97b 100644 --- a/Tests/MQTTnet.Benchmarks/Program.cs +++ b/Tests/MQTTnet.Benchmarks/Program.cs @@ -13,6 +13,8 @@ namespace MQTTnet.Benchmarks Console.WriteLine("2 = SerializerBenchmark"); Console.WriteLine("3 = LoggerBenchmark"); Console.WriteLine("4 = TopicFilterComparerBenchmark"); + Console.WriteLine("5 = ChannelAdapterBenchmark"); + Console.WriteLine("6 = MqttTcpChannelBenchmark"); var pressedKey = Console.ReadKey(true); switch (pressedKey.KeyChar) @@ -29,6 +31,12 @@ namespace MQTTnet.Benchmarks case '4': BenchmarkRunner.Run(); break; + case '5': + BenchmarkRunner.Run(); + break; + case '6': + BenchmarkRunner.Run(); + break; } Console.ReadLine();