dotnet / MQTTnet

MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from http://mqtt.org/.
MIT License
4.46k stars 1.06k forks source link

Performance of UWP TCP client dramatically lower than other platforms #127

Closed tiefschneeteufel closed 6 years ago

tiefschneeteufel commented 6 years ago

I have been experimenting with using MQTTnet with Unity. Win32 and Android clients built using MQTTnet work great and can cope with update rates of the order of hundreds/second. However, once I managed to coax Unity into working with MQTTnet, using both .NET and IL2CPP backends, performance is very poor. Above ~20 messages/second a MqttCommunicationTimedOutException is thrown, and the client disconnects. The MQTTnet.TestApp.UniversalWindows test app is similarly slow although it does somewhat better, sustaining ~40 messages/second for around a minute before timing out. The broker I used for my tests was mosquitto running on a Raspberry Pi.

Why is UWP performance so poor? Is there something that can be done about it? For comparison M2MQTT performs similarly.

chkr1011 commented 6 years ago

Hi, can you please give me some more details. Which version are you using? Nuget? Self compiled? Also sharing some trace.

The performance of .NET in Unity is in general not optimal like discussed in some threads like: https://forum.unity.com/threads/performance-issue-with-difference-between-ms-net-and-unity-mono-issue.313789/

Also there are some considerations about performance of .NET code in Unity described here: https://developer.microsoft.com/en-us/windows/mixed-reality/performance_recommendations_for_unity

The problem is that this library is not optimized to be used in Unity. There are lots of LINQ expressions, Lamdas etc. The guidelines also recommend using structs over classes which is not an option for this project.

If you share some performance diagnostics from the Code running in Unity we may can find some pitfalls which can be optimized.

But the UWP client you mentioned is not running on Windows?

Best regards Christian

tiefschneeteufel commented 6 years ago

Hello Christian,

I don't think this is specifically a Unity issue (although I can go into the gory details later). I checked out the develop branch (latest commit hash 0ee3c8e135261567ac5755aa262c586039e4a3e9) this afternoon, and tried publishing ~600 byte messages to a topic which I subscribed to using the MQTTnet.TestApp.UniversalWindows test app from the Tests directory of the repository. After about a minute at around 40 messages/second it threw a MqttCommunicationTimedOutException.

I got a Unity client working with the IL2CPP backend (whereby IL bytecode is converted to C++) to work with the latest version of the master branch. To use the .NET backend for UWP Unity apps I used the develop branch from today, but had to downgrade the version of Microsoft.NETCore.UniversalWindowsPlatform to 5.0.0 and strip out support for WebSockets. I was then able to use the .NET 4.6 experimental support within Unity (version 2017.2.0p1-MRTP4).

I can provide more tracing and information tomorrow, but if the performance could be improved for a vanilla UWP app like MQTTnet.TestApp.UniversalWindows then that would be a good foundation from which to look at improving the Unity version. Performance for Android and within the Unity editor itself is great.

Thanks,

Joe

chkr1011 commented 6 years ago

How do you send the messages? In a batch probably. The problem is that no "KeepAlive" packet is processed when you send lots of messages in batch because the batch blocks the channel until everything is sent. This may explain the connection timeouts.

And UWP running on Window is also slow without having any relation with Unity? Which server do you use? The one from this project?

Best regards Christian

tiefschneeteufel commented 6 years ago

I am sending the messages using a Node.js script. The messages are not batched, but at a set interval of a certain number milliseconds (e.g. 150, 100, 50, 15, 5...,1). At a certain point they will certainly appear to batched to the subscriber, but my Node.js clients and other C# scripts can certainly handle hundreds of messages/second.

I am using mosquitto as my MQTT broker. It is running on a Raspberry Pi, which is also acting as my WiFi access point, and I am connected over WiFi.

I am trying to write Hololens apps with MQTT, but the experiments I have done most recently have been on the desktop. Perhaps the answer, as you say, is that UWP apps are slow. I would like to be able to handle at least 60 messages/second as the Hololens has a frame rate of 60 fps. For my particular use case I would actually prefer new messages to displace old ones, rather than having a queue growing until a timeout triggers a disconnect.

chkr1011 commented 6 years ago

I don't say that UWP apps are slower in general. Also please keep in mind that the UWP app in this repo is also used for testing. If you send 60 messages per second the UI is refreshing all the time which leads to long delays because it is not optimized for such loads.

tiefschneeteufel commented 6 years ago

Hello Christian,

I just built a test application which puts negligible load on the UI thread. It calculates message statistics once a second and then dispatches this to the UI thread using RunIdleAsync. The standard TCP client barely manages to sustain 40 messages/second, but when I used the MqttClientWebSocketOptions, to connect to my MQTT broker via a WebSocket I get nearly 400 messages/second. This suggests to me that there is something slowing down the handling of messages in the UWP implementation of MQTTTcpChannel. I am attaching the my UWP project MqttUWPPerformanceApp.zip .

BTW, it would be great to have a more graceful failure mode when the message rate exceeds the clients ability to consume them. For example, dropping or sub-sampling "at most once (0)" QoS messages.

chkr1011 commented 6 years ago

Please test again with the latest version. Several issues in socket and stream handling were fixed.

tiefschneeteufel commented 6 years ago

The master branch?

Joe

On Wed 11. Apr 2018 at 22:24, Christian notifications@github.com wrote:

Please test again with the latest version. Several issues in socket and stream handling were fixed.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/chkr1011/MQTTnet/issues/127#issuecomment-380584039, or mute the thread https://github.com/notifications/unsubscribe-auth/AJmHih-drJm3rn2ZzMKC_zzmH8Wnn_WDks5tnmZ6gaJpZM4QvLnJ .

chkr1011 commented 6 years ago

Yes or you use the latest nuget 2.7.4. It is the same version.

chkr1011 commented 6 years ago

@tiefschneeteufel I found an API for the UWP build which avoids generating useless buffers. So the performance should be much better now. Please try with version 2.8.0-alpha3 and let me know if it is faster now.

tiefschneeteufel commented 6 years ago

Okay, that’s good to know. I’m on a different project now, but will try to find the time to look at it.

Joe

On Tue 5. Jun 2018 at 21:43, Christian notifications@github.com wrote:

@tiefschneeteufel https://github.com/tiefschneeteufel I found an API for the UWP build which avoids generating useless buffers. So the performance should be much better now. Please try with version 2.8.0-alpha3 and let me know if it is faster now.

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/chkr1011/MQTTnet/issues/127#issuecomment-394835709, or mute the thread https://github.com/notifications/unsubscribe-auth/AJmHigp1Jdj8OjcG2B2JLaV-r5NwgCv-ks5t5t9SgaJpZM4QvLnJ .

chkr1011 commented 6 years ago

OK then I will close this ticket for now. If you need support please reopen it or create a new one.