This repository was archived by the owner on Aug 14, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ea42ed2
Showing
5 changed files
with
346 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
using System.Diagnostics; | ||
using MQTTnet; | ||
using MQTTnet.Client; | ||
using MQTTnet.Formatter; | ||
using MQTTnet.Protocol; | ||
using Nett; | ||
|
||
namespace ThingsOn_MQTT_Bench { | ||
internal class Program { | ||
|
||
// Entry point of the program | ||
private static async Task Main() { | ||
|
||
// Prompt the user to start a new benchmark | ||
Console.Write("Do you want to start a new benchmark? (y/n): "); | ||
var answer = Console.ReadLine(); | ||
|
||
// Run the benchmark if the user answers "y" | ||
if (answer?.ToLower() == "y") { | ||
try { | ||
await RunBenchmark(); | ||
} | ||
catch (Exception ex) { | ||
Console.ForegroundColor = ConsoleColor.Red; | ||
Console.WriteLine($"An error occurred: {ex.Message}"); | ||
Console.ResetColor(); | ||
} | ||
} | ||
|
||
// Main logic of the benchmark | ||
async Task RunBenchmark() { | ||
// Load benchmark settings | ||
var (settings, serverUri, port, cleanSession, userName, password, keepAlivePeriod, connectionTimeOut, | ||
mqttVersion, clientCount, messageCount, messageSize, qos, retain) = LoadSettings(); | ||
|
||
// Create MQTT clients | ||
var factory = new MqttFactory(); | ||
var clients = Enumerable.Range(0, clientCount).Select(_ => factory.CreateMqttClient()).ToList(); | ||
|
||
// Connect to MQTT broker and measure connect time | ||
var stopwatchConnect = Stopwatch.StartNew(); | ||
var connectTasks = clients.Select(c => c.ConnectAsync(CreateMqttClientOptions(serverUri, port, cleanSession, userName, password, keepAlivePeriod, connectionTimeOut, mqttVersion))).ToList(); | ||
await Task.WhenAll(connectTasks); | ||
stopwatchConnect.Stop(); | ||
var elapsedConnect = stopwatchConnect.Elapsed; | ||
|
||
// Generate messages | ||
var messages = Enumerable.Range(1, messageCount) | ||
.Select(i => new MqttApplicationMessageBuilder() | ||
.WithTopic($"test/{i}") | ||
.WithPayload(new byte[messageSize]) | ||
.WithQualityOfServiceLevel((MqttQualityOfServiceLevel) qos) | ||
.WithRetainFlag(retain) | ||
.Build()) | ||
.ToList(); | ||
|
||
// Start benchmark | ||
var stopwatch = Stopwatch.StartNew(); | ||
|
||
// Send messages | ||
var totalMessagesSent = clientCount * messageCount; | ||
var sent = 0; | ||
var progressReport = 0; | ||
var sendTasks = clients.Select(client => Task.Run(async () => { | ||
var results = new List<MqttClientPublishResult>(); | ||
foreach (var message in messages) { | ||
// Publish message and store the result | ||
var result = await client.PublishAsync(message); | ||
results.Add(result); | ||
|
||
// Update progress | ||
sent++; | ||
var newProgressReport = sent * 100 / totalMessagesSent; | ||
if (newProgressReport >= progressReport + 10) { | ||
progressReport = newProgressReport / 10 * 10; | ||
Console.CursorLeft = 0; | ||
Console.Write($"\rProgress: {progressReport}%"); | ||
} | ||
} | ||
|
||
return results; | ||
})).ToList(); | ||
|
||
// Wait for all messages to be sent | ||
var sendResults = await Task.WhenAll(sendTasks); | ||
Console.Write("\rProgress: 100%"); | ||
Console.WriteLine(); | ||
Console.WriteLine(); | ||
|
||
// End benchmark | ||
stopwatch.Stop(); | ||
var elapsed = stopwatch.Elapsed; | ||
var messagesSent = clientCount * messageCount; | ||
var throughput = messagesSent / elapsed.TotalSeconds; | ||
var lossRate = (double) sendResults.SelectMany(r => r).Count(r => r.ReasonCode != MqttClientPublishReasonCode.Success) / messagesSent; | ||
var successRate = 1.0 - lossRate; | ||
|
||
// Disconnect from MQTT broker and measure disconnect time | ||
var stopwatchDisconnect = Stopwatch.StartNew(); | ||
var disconnectTasks = clients.Select(c => c.DisconnectAsync()).ToList(); | ||
await Task.WhenAll(disconnectTasks); | ||
stopwatchDisconnect.Stop(); | ||
var elapsedDisconnect = stopwatchDisconnect.Elapsed; | ||
|
||
// Print results | ||
Console.ForegroundColor = ConsoleColor.Green; | ||
Console.WriteLine("Benchmark completed 🚀"); | ||
Console.WriteLine("======================================="); | ||
Console.WriteLine($"{"Messages sent",-20} {messagesSent:N0}"); | ||
Console.WriteLine($"{"Elapsed time",-20} {elapsed.TotalSeconds:F3}"); | ||
Console.WriteLine($"{"Throughput",-20} {throughput:N0} messages/second"); | ||
Console.WriteLine($"{"Connect time",-20} {elapsedConnect.TotalSeconds:F3} seconds"); | ||
Console.WriteLine($"{"Disconnect time",-20} {elapsedDisconnect.TotalSeconds:F3} seconds"); | ||
Console.WriteLine($"{"Success rate",-20} {successRate:P0}"); | ||
Console.WriteLine($"{"Loss rate",-20} {lossRate:P0}"); | ||
|
||
// Convert data size to appropriate units | ||
var dataSize = (double) (totalMessagesSent * settings.Get<int>("MessageSize")); | ||
var dataUnits = new[] {"B", "KB", "MB", "GB", "TB"}; | ||
var dataUnitIndex = 0; | ||
while (dataSize >= 1024 && dataUnitIndex < dataUnits.Length - 1) { | ||
dataSize /= 1024; | ||
dataUnitIndex++; | ||
} | ||
|
||
Console.WriteLine($"{"Data sent",-20} {dataSize:N3} {dataUnits[dataUnitIndex]}"); | ||
Console.WriteLine("======================================="); | ||
Console.ResetColor(); | ||
|
||
// Prompt the user to run the benchmark again | ||
await Main(); | ||
} | ||
} | ||
|
||
private static (TomlTable settings, string serverUri, int port, bool cleanSession, string userName, string password, TimeSpan keepAlivePeriod, TimeSpan connectionTimeOut, MqttProtocolVersion mqttVersion, int clientCount, int messageCount, int messageSize, int qos, bool retain) LoadSettings() { | ||
// Load settings from config.toml | ||
var settings = Toml.ReadFile(Path.Combine(Directory.GetCurrentDirectory(), "config.toml")); | ||
|
||
// Parse benchmark settings | ||
var serverUri = settings.Get<string>("ServerUri"); | ||
var port = settings.Get<int>("Port"); | ||
var cleanSession = settings.Get<bool>("CleanSession"); | ||
var userName = settings.Get<string>("Username"); | ||
var password = settings.Get<string>("Password"); | ||
var keepAlivePeriod = TimeSpan.FromSeconds(settings.Get<int>("KeepAlivePeriod")); | ||
var connectionTimeOut = TimeSpan.FromSeconds(settings.Get<int>("ConnectionTimeOut")); | ||
var mqttVersion = ParseMqttProtocolVersion(settings.Get<string>("MqttVersion")); | ||
var clientCount = settings.Get<int>("ClientCount"); | ||
var messageCount = settings.Get<int>("MessageCount"); | ||
var messageSize = settings.Get<int>("MessageSize"); | ||
var qos = settings.Get<int>("Qos"); | ||
var retain = settings.Get<bool>("Retain"); | ||
|
||
// Print benchmark settings | ||
Console.ForegroundColor = ConsoleColor.Blue; | ||
Console.WriteLine($"Benchmark settings: {clientCount} clients, {messageCount} messages/client, {messageSize:N0} bytes/message, QoS {qos}, retain {retain}, MQTT version {mqttVersion}."); | ||
Console.WriteLine($"Server URI: {serverUri}"); | ||
Console.WriteLine($"Port: {port}"); | ||
Console.WriteLine($"Clean session: {cleanSession}"); | ||
Console.WriteLine($"User name: {userName}"); | ||
Console.WriteLine(!string.IsNullOrEmpty(password) ? $"Password: {password[0]}{new string('*', password.Length - 1)}" : "Password: (empty)"); | ||
Console.WriteLine($"Keep alive period: {keepAlivePeriod}"); | ||
Console.WriteLine($"Connection timeout: {connectionTimeOut}"); | ||
Console.ResetColor(); | ||
return (settings, serverUri, port, cleanSession, userName, password, keepAlivePeriod, connectionTimeOut, mqttVersion, clientCount, messageCount, messageSize, qos, retain); | ||
} | ||
|
||
// Create MQTT client options from parsed settings | ||
private static MqttClientOptions CreateMqttClientOptions(string serverUri, int port, bool cleanSession, string userName, string password, TimeSpan keepAlivePeriod, TimeSpan connectionTimeOut, MqttProtocolVersion mqttVersion) { | ||
var options = new MqttClientOptionsBuilder() | ||
.WithClientId(Guid.NewGuid().ToString()) | ||
.WithTcpServer(serverUri, port) | ||
.WithCleanSession(cleanSession) | ||
.WithCredentials(userName, password) | ||
.WithKeepAlivePeriod(keepAlivePeriod) | ||
.WithTimeout(connectionTimeOut) | ||
.WithProtocolVersion(mqttVersion) | ||
.Build(); | ||
return options; | ||
} | ||
|
||
// Parse MQTT protocol version from a string | ||
private static MqttProtocolVersion ParseMqttProtocolVersion(string value) { | ||
switch (value.ToLowerInvariant()) { | ||
case "v310": | ||
return MqttProtocolVersion.V310; | ||
case "v311": | ||
return MqttProtocolVersion.V311; | ||
case "v500": | ||
return MqttProtocolVersion.V500; | ||
default: | ||
throw new ArgumentException($"Invalid MQTT version '{value}'."); | ||
} | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# ThingsOn MQTT Bench | ||
|
||
ThingsOn MQTT Bench is a benchmark tool for MQTT brokers. It measures the maximum number of messages that can be sent by the broker in a specified amount of time. | ||
|
||
## Features | ||
|
||
* Measures the maximum number of messages that can be sent by an MQTT broker in a specified amount of time. | ||
* Supports MQTT brokers running MQTT protocol versions 3.1.1 (MQTTv3.1.1) and 5.0 (MQTTv5.0). | ||
* Allows customization of the following benchmark settings: | ||
* Number of MQTT clients to use for benchmarking | ||
* Number of messages to send per client | ||
* Message size in bytes | ||
* Quality of Service (QoS) level for messages (0, 1, or 2) | ||
* Whether messages should be retained by the broker | ||
* Outputs progress information to the console during benchmarking. | ||
* Outputs the following information upon benchmark completion: | ||
* Number of messages sent | ||
* Total time taken to send messages | ||
* Message throughput (messages per second) | ||
* Time taken to connect to the MQTT broker | ||
* Time taken to disconnect from the MQTT broker | ||
* Success rate (percentage of messages that were successfully sent) | ||
* Loss rate (percentage of messages that were not successfully sent) | ||
|
||
## Usage | ||
|
||
To use ThingsOn MQTT Bench, first make sure that you have .NET 7 installed on your system. Then, download the latest release of ThingsOn MQTT Bench for your operating system from the [releases page](https://github.com/yourusername/ThingsOn-MQTT-Bench/releases). | ||
|
||
Once you have downloaded the tool, you can run it from the command line by navigating to the directory where the tool is located and running the following command: | ||
|
||
<pre><div class="bg-black mb-4 rounded-md"><div class="flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans"><button class="flex ml-auto gap-2"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>Copy code</button></div><div class="p-4 overflow-y-auto"><code class="!whitespace-pre hljs">dotnet ThingsOnMqttBench.dll | ||
</code></div></div></pre> | ||
|
||
By default, the tool will read its settings from a TOML file named `config.toml` in the same directory as the tool. You can customize the settings by editing this file. | ||
|
||
## Settings | ||
|
||
The following settings are available in the `config.toml` file: | ||
|
||
* `Mqtt`: MQTT broker settings | ||
* `ServerUri`: URI of the MQTT broker | ||
* `Port`: Port number of the MQTT broker | ||
* `MqttVersion`: MQTT protocol version (either "V311" or "V500") | ||
* `Username`: Username for connecting to the MQTT broker | ||
* `Password`: Password for connecting to the MQTT broker | ||
* `ClientIdPrefix`: Prefix for MQTT client IDs | ||
* `KeepAlivePeriod`: Keep-alive period in seconds | ||
* `CleanSession`: Whether to use a clean session when connecting to the MQTT broker | ||
* `MaximumQoS`: Maximum quality of service level for messages | ||
* `Benchmark`: Benchmark settings | ||
* `ClientCount`: Number of MQTT clients to use for benchmarking | ||
* `MessageCount`: Number of messages to send per client | ||
* `MessageSize`: Size of messages in bytes | ||
* `Qos`: Quality of service level for messages (0, 1, or 2) | ||
* `Retain`: Whether messages should be retained by the broker | ||
|
||
|
||
## Building from Code | ||
|
||
To build ThingsOn MQTT Bench from code, follow these steps: | ||
|
||
1. Install [.NET 7](https://dotnet.microsoft.com/download/dotnet/7.0). | ||
2. Clone the GitHub repository: | ||
|
||
<pre><div class="bg-black mb-4 rounded-md"><div class="flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans"><span class="">bash</span><button class="flex ml-auto gap-2"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>Copy code</button></div><div class="p-4 overflow-y-auto"><code class="!whitespace-pre hljs language-bash">git clone https://github.com/your-username/ThingsOn-MQTT-Bench.git | ||
</code></div></div></pre> | ||
|
||
3. Navigate to the cloned repository directory: | ||
|
||
<pre><div class="bg-black mb-4 rounded-md"><div class="flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans"><span class="">bash</span><button class="flex ml-auto gap-2"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>Copy code</button></div><div class="p-4 overflow-y-auto"><code class="!whitespace-pre hljs language-bash">cd ThingsOn-MQTT-Bench | ||
</code></div></div></pre> | ||
|
||
4. Build the project using the following command: | ||
|
||
<pre><div class="bg-black mb-4 rounded-md"><div class="flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans"><button class="flex ml-auto gap-2"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>Copy code</button></div><div class="p-4 overflow-y-auto"><code class="!whitespace-pre hljs">dotnet build | ||
</code></div></div></pre> | ||
|
||
5. Once the project has built successfully, you can run the benchmark using the following command: | ||
|
||
<pre><div class="bg-black mb-4 rounded-md"><div class="flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans"><span class="">css</span><button class="flex ml-auto gap-2"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>Copy code</button></div><div class="p-4 overflow-y-auto"><code class="!whitespace-pre hljs language-css">dotnet run --project ThingsOnMqttBench | ||
</code></div></div></pre> | ||
|
||
|
||
## Contributing | ||
|
||
Contributions to ThingsOn MQTT Bench are welcome! If you find a bug or would like to suggest a new feature, please open an issue on the [GitHub repository](https://github.com/yourusername/ThingsOn-MQTT-Bench). | ||
|
||
If you would like to contribute code to ThingsOn MQTT Bench, please fork the repository and submit a pull request. | ||
|
||
## License | ||
|
||
ThingsOn MQTT Bench is licensed under the MIT license. See the [LICENSE](https://chat.openai.com/chat/LICENSE) file for more information. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<RootNamespace>ThingsOn_MQTT_Bench</RootNamespace> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="MQTTnet" Version="4.1.4.563" /> | ||
<PackageReference Include="Nett" Version="0.15.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<None Remove="config.toml" /> | ||
<Content Include="config.toml"> | ||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||
</Content> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThingsOn.MQTT.Bench", "ThingsOn.MQTT.Bench.csproj", "{5512F858-5184-4530-95F7-26D8ED9BD26F}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{5512F858-5184-4530-95F7-26D8ED9BD26F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{5512F858-5184-4530-95F7-26D8ED9BD26F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{5512F858-5184-4530-95F7-26D8ED9BD26F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{5512F858-5184-4530-95F7-26D8ED9BD26F}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
ServerUri = "127.0.0.1" | ||
Port = 1883 | ||
# MQTT protocol version to use ("V311", "V310" or "V500") | ||
MqttVersion = "V500" | ||
Username = "" | ||
Password = "" | ||
ConnectionTimeOut = 1 | ||
KeepAlivePeriod = 60 | ||
CleanSession = true | ||
# number of clients to use for the benchmark | ||
ClientCount = 50 | ||
# number of messages to send from each client | ||
MessageCount = 10000 | ||
# size of each message in bytes | ||
MessageSize = 100 | ||
# quality of service level to use for message delivery (0, 1 or 2) | ||
Qos = 0 | ||
Retain = false |