Commit e2ea3ea8765aa80177758b3401a9e9294235cb26
Committed by
Wiebe Cazemier
1 parent
bf2193f9
Add stats about connection count in $SYS
This required adding a global stats object. It also contains a bit of refactor to make a type out of the derived counters.
Showing
11 changed files
with
134 additions
and
70 deletions
CMakeLists.txt
| @@ -61,6 +61,8 @@ add_executable(FlashMQ | @@ -61,6 +61,8 @@ add_executable(FlashMQ | ||
| 61 | publishcopyfactory.h | 61 | publishcopyfactory.h |
| 62 | variablebyteint.h | 62 | variablebyteint.h |
| 63 | mqtt5properties.h | 63 | mqtt5properties.h |
| 64 | + globalstats.h | ||
| 65 | + derivablecounter.h | ||
| 64 | 66 | ||
| 65 | mainapp.cpp | 67 | mainapp.cpp |
| 66 | main.cpp | 68 | main.cpp |
| @@ -101,6 +103,8 @@ add_executable(FlashMQ | @@ -101,6 +103,8 @@ add_executable(FlashMQ | ||
| 101 | publishcopyfactory.cpp | 103 | publishcopyfactory.cpp |
| 102 | variablebyteint.cpp | 104 | variablebyteint.cpp |
| 103 | mqtt5properties.cpp | 105 | mqtt5properties.cpp |
| 106 | + globalstats.cpp | ||
| 107 | + derivablecounter.cpp | ||
| 104 | 108 | ||
| 105 | ) | 109 | ) |
| 106 | 110 |
FlashMQTests/FlashMQTests.pro
| @@ -52,6 +52,8 @@ SOURCES += tst_maintests.cpp \ | @@ -52,6 +52,8 @@ SOURCES += tst_maintests.cpp \ | ||
| 52 | ../publishcopyfactory.cpp \ | 52 | ../publishcopyfactory.cpp \ |
| 53 | ../variablebyteint.cpp \ | 53 | ../variablebyteint.cpp \ |
| 54 | ../mqtt5properties.cpp \ | 54 | ../mqtt5properties.cpp \ |
| 55 | + ../globalstats.cpp \ | ||
| 56 | + ../derivablecounter.cpp \ | ||
| 55 | mainappthread.cpp \ | 57 | mainappthread.cpp \ |
| 56 | twoclienttestcontext.cpp | 58 | twoclienttestcontext.cpp |
| 57 | 59 | ||
| @@ -96,6 +98,8 @@ HEADERS += \ | @@ -96,6 +98,8 @@ HEADERS += \ | ||
| 96 | ../publishcopyfactory.h \ | 98 | ../publishcopyfactory.h \ |
| 97 | ../variablebyteint.h \ | 99 | ../variablebyteint.h \ |
| 98 | ../mqtt5properties.h \ | 100 | ../mqtt5properties.h \ |
| 101 | + ../globalstats.h \ | ||
| 102 | + ../derivablecounter.h \ | ||
| 99 | mainappthread.h \ | 103 | mainappthread.h \ |
| 100 | twoclienttestcontext.h | 104 | twoclienttestcontext.h |
| 101 | 105 |
client.cpp
| @@ -223,7 +223,7 @@ void Client::writeMqttPacket(const MqttPacket &packet) | @@ -223,7 +223,7 @@ void Client::writeMqttPacket(const MqttPacket &packet) | ||
| 223 | if (packet.packetType == PacketType::PUBLISH) | 223 | if (packet.packetType == PacketType::PUBLISH) |
| 224 | { | 224 | { |
| 225 | ThreadData *td = ThreadGlobals::getThreadData(); | 225 | ThreadData *td = ThreadGlobals::getThreadData(); |
| 226 | - td->incrementSentMessageCount(1); | 226 | + td->sentMessageCounter.inc(); |
| 227 | } | 227 | } |
| 228 | else if (packet.packetType == PacketType::DISCONNECT) | 228 | else if (packet.packetType == PacketType::DISCONNECT) |
| 229 | setReadyForDisconnect(); | 229 | setReadyForDisconnect(); |
derivablecounter.cpp
0 → 100644
| 1 | +#include "derivablecounter.h" | ||
| 2 | + | ||
| 3 | +void DerivableCounter::inc(uint64_t n) | ||
| 4 | +{ | ||
| 5 | + val += n; | ||
| 6 | +} | ||
| 7 | + | ||
| 8 | +uint64_t DerivableCounter::get() const | ||
| 9 | +{ | ||
| 10 | + return val; | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * @brief DerivableCounter::getPerSecond returns the amount per second since last time this method was called. | ||
| 15 | + * @return | ||
| 16 | + * | ||
| 17 | + * Even though the class it not meant to be thread-safe, this method does use a mutex, because obtaining the value can be | ||
| 18 | + * scheduled in different threads. | ||
| 19 | + */ | ||
| 20 | +uint64_t DerivableCounter::getPerSecond() | ||
| 21 | +{ | ||
| 22 | + std::lock_guard<std::mutex> locker(timeMutex); | ||
| 23 | + | ||
| 24 | + std::chrono::time_point<std::chrono::steady_clock> now = std::chrono::steady_clock::now(); | ||
| 25 | + std::chrono::milliseconds msSinceLastTime = std::chrono::duration_cast<std::chrono::milliseconds>(now - timeOfPrevious); | ||
| 26 | + uint64_t messagesTimes1000 = (val - valPrevious) * 1000; | ||
| 27 | + uint64_t result = messagesTimes1000 / (msSinceLastTime.count() + 1); // branchless avoidance of div by 0; | ||
| 28 | + timeOfPrevious = now; | ||
| 29 | + valPrevious = val; | ||
| 30 | + return result; | ||
| 31 | +} |
derivablecounter.h
0 → 100644
| 1 | +#ifndef DERIVABLECOUNTER_H | ||
| 2 | +#define DERIVABLECOUNTER_H | ||
| 3 | + | ||
| 4 | +#include <chrono> | ||
| 5 | +#include <mutex> | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @brief The DerivableCounter is a counter which can derive val/dt. | ||
| 9 | + * | ||
| 10 | + * It's not thread-safe, to avoid unnecessary locking. You should have counters per thread. | ||
| 11 | + */ | ||
| 12 | +class DerivableCounter | ||
| 13 | +{ | ||
| 14 | + uint64_t val = 0; | ||
| 15 | + uint64_t valPrevious = 0; | ||
| 16 | + std::chrono::time_point<std::chrono::steady_clock> timeOfPrevious = std::chrono::steady_clock::now(); | ||
| 17 | + std::mutex timeMutex; | ||
| 18 | + | ||
| 19 | +public: | ||
| 20 | + | ||
| 21 | + void inc(uint64_t n = 1); | ||
| 22 | + uint64_t get() const; | ||
| 23 | + uint64_t getPerSecond(); | ||
| 24 | +}; | ||
| 25 | + | ||
| 26 | +#endif // DERIVABLECOUNTER_H |
globalstats.cpp
0 → 100644
| 1 | +#include "globalstats.h" | ||
| 2 | + | ||
| 3 | +GlobalStats *GlobalStats::instance = nullptr; | ||
| 4 | + | ||
| 5 | +GlobalStats::GlobalStats() | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +GlobalStats *GlobalStats::getInstance() | ||
| 11 | +{ | ||
| 12 | + if (GlobalStats::instance == nullptr) | ||
| 13 | + GlobalStats::instance = new GlobalStats(); | ||
| 14 | + | ||
| 15 | + return GlobalStats::instance; | ||
| 16 | +} | ||
| 17 | + |
globalstats.h
0 → 100644
| 1 | +#ifndef GLOBALSTATS_H | ||
| 2 | +#define GLOBALSTATS_H | ||
| 3 | + | ||
| 4 | +#include "stdint.h" | ||
| 5 | +#include "derivablecounter.h" | ||
| 6 | + | ||
| 7 | +class GlobalStats | ||
| 8 | +{ | ||
| 9 | + static GlobalStats *instance; | ||
| 10 | + | ||
| 11 | + GlobalStats(); | ||
| 12 | +public: | ||
| 13 | + static GlobalStats *getInstance(); | ||
| 14 | + | ||
| 15 | + DerivableCounter socketConnects; | ||
| 16 | +}; | ||
| 17 | + | ||
| 18 | +#endif // GLOBALSTATS_H |
mainapp.cpp
| @@ -33,6 +33,7 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | @@ -33,6 +33,7 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | ||
| 33 | #include "threadloop.h" | 33 | #include "threadloop.h" |
| 34 | #include "authplugin.h" | 34 | #include "authplugin.h" |
| 35 | #include "threadglobals.h" | 35 | #include "threadglobals.h" |
| 36 | +#include "globalstats.h" | ||
| 36 | 37 | ||
| 37 | MainApp *MainApp::instance = nullptr; | 38 | MainApp *MainApp::instance = nullptr; |
| 38 | 39 | ||
| @@ -529,6 +530,8 @@ void MainApp::start() | @@ -529,6 +530,8 @@ void MainApp::start() | ||
| 529 | } | 530 | } |
| 530 | #endif | 531 | #endif |
| 531 | 532 | ||
| 533 | + GlobalStats *globalStats = GlobalStats::getInstance(); | ||
| 534 | + | ||
| 532 | for (int i = 0; i < num_threads; i++) | 535 | for (int i = 0; i < num_threads; i++) |
| 533 | { | 536 | { |
| 534 | std::shared_ptr<ThreadData> t = std::make_shared<ThreadData>(i, subscriptionStore, settings); | 537 | std::shared_ptr<ThreadData> t = std::make_shared<ThreadData>(i, subscriptionStore, settings); |
| @@ -592,6 +595,8 @@ void MainApp::start() | @@ -592,6 +595,8 @@ void MainApp::start() | ||
| 592 | 595 | ||
| 593 | std::shared_ptr<Client> client = std::make_shared<Client>(fd, thread_data, clientSSL, listener->websocket, addr, settings.get()); | 596 | std::shared_ptr<Client> client = std::make_shared<Client>(fd, thread_data, clientSSL, listener->websocket, addr, settings.get()); |
| 594 | thread_data->giveClient(client); | 597 | thread_data->giveClient(client); |
| 598 | + | ||
| 599 | + globalStats->socketConnects.inc(); | ||
| 595 | } | 600 | } |
| 596 | else | 601 | else |
| 597 | { | 602 | { |
mqttpacket.cpp
| @@ -328,6 +328,8 @@ void MqttPacket::handleConnect() | @@ -328,6 +328,8 @@ void MqttPacket::handleConnect() | ||
| 328 | 328 | ||
| 329 | std::shared_ptr<SubscriptionStore> subscriptionStore = sender->getThreadData()->getSubscriptionStore(); | 329 | std::shared_ptr<SubscriptionStore> subscriptionStore = sender->getThreadData()->getSubscriptionStore(); |
| 330 | 330 | ||
| 331 | + sender->getThreadData()->mqttConnectCounter.inc(); | ||
| 332 | + | ||
| 331 | uint16_t variable_header_length = readTwoBytesToUInt16(); | 333 | uint16_t variable_header_length = readTwoBytesToUInt16(); |
| 332 | 334 | ||
| 333 | const Settings &settings = *ThreadGlobals::getSettings(); | 335 | const Settings &settings = *ThreadGlobals::getSettings(); |
| @@ -1129,7 +1131,7 @@ void MqttPacket::handlePublish() | @@ -1129,7 +1131,7 @@ void MqttPacket::handlePublish() | ||
| 1129 | 1131 | ||
| 1130 | ReasonCodes ackCode = ReasonCodes::Success; | 1132 | ReasonCodes ackCode = ReasonCodes::Success; |
| 1131 | 1133 | ||
| 1132 | - sender->getThreadData()->incrementReceivedMessageCount(); | 1134 | + sender->getThreadData()->receivedMessageCounter.inc(); |
| 1133 | 1135 | ||
| 1134 | Authentication &authentication = *ThreadGlobals::getAuth(); | 1136 | Authentication &authentication = *ThreadGlobals::getAuth(); |
| 1135 | 1137 |
threaddata.cpp
| @@ -20,6 +20,8 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | @@ -20,6 +20,8 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | ||
| 20 | #include <sstream> | 20 | #include <sstream> |
| 21 | #include <cassert> | 21 | #include <cassert> |
| 22 | 22 | ||
| 23 | +#include "globalstats.h" | ||
| 24 | + | ||
| 23 | KeepAliveCheck::KeepAliveCheck(const std::shared_ptr<Client> client) : | 25 | KeepAliveCheck::KeepAliveCheck(const std::shared_ptr<Client> client) : |
| 24 | client(client) | 26 | client(client) |
| 25 | { | 27 | { |
| @@ -143,17 +145,31 @@ void ThreadData::publishStatsOnDollarTopic(std::vector<std::shared_ptr<ThreadDat | @@ -143,17 +145,31 @@ void ThreadData::publishStatsOnDollarTopic(std::vector<std::shared_ptr<ThreadDat | ||
| 143 | uint64_t sentMessageCountPerSecond = 0; | 145 | uint64_t sentMessageCountPerSecond = 0; |
| 144 | uint64_t sentMessageCount = 0; | 146 | uint64_t sentMessageCount = 0; |
| 145 | 147 | ||
| 148 | + uint64_t mqttConnectCountPerSecond = 0; | ||
| 149 | + uint64_t mqttConnectCount = 0; | ||
| 150 | + | ||
| 146 | for (const std::shared_ptr<ThreadData> &thread : threads) | 151 | for (const std::shared_ptr<ThreadData> &thread : threads) |
| 147 | { | 152 | { |
| 148 | nrOfClients += thread->getNrOfClients(); | 153 | nrOfClients += thread->getNrOfClients(); |
| 149 | 154 | ||
| 150 | - receivedMessageCountPerSecond += thread->getReceivedMessagePerSecond(); | ||
| 151 | - receivedMessageCount += thread->getReceivedMessageCount(); | 155 | + receivedMessageCountPerSecond += thread->receivedMessageCounter.getPerSecond(); |
| 156 | + receivedMessageCount += thread->receivedMessageCounter.get(); | ||
| 152 | 157 | ||
| 153 | - sentMessageCountPerSecond += thread->getSentMessagePerSecond(); | ||
| 154 | - sentMessageCount += thread->getSentMessageCount(); | 158 | + sentMessageCountPerSecond += thread->sentMessageCounter.getPerSecond(); |
| 159 | + sentMessageCount += thread->sentMessageCounter.get(); | ||
| 160 | + | ||
| 161 | + mqttConnectCountPerSecond += thread->mqttConnectCounter.getPerSecond(); | ||
| 162 | + mqttConnectCount += thread->mqttConnectCounter.get(); | ||
| 155 | } | 163 | } |
| 156 | 164 | ||
| 165 | + GlobalStats *globalStats = GlobalStats::getInstance(); | ||
| 166 | + | ||
| 167 | + publishStat("$SYS/broker/network/socketconnects/total", globalStats->socketConnects.get()); | ||
| 168 | + publishStat("$SYS/broker/network/socketconnects/persecond", globalStats->socketConnects.getPerSecond()); | ||
| 169 | + | ||
| 170 | + publishStat("$SYS/broker/clients/mqttconnects/total", mqttConnectCount); | ||
| 171 | + publishStat("$SYS/broker/clients/mqttconnects/persecond", mqttConnectCountPerSecond); | ||
| 172 | + | ||
| 157 | publishStat("$SYS/broker/clients/total", nrOfClients); | 173 | publishStat("$SYS/broker/clients/total", nrOfClients); |
| 158 | 174 | ||
| 159 | publishStat("$SYS/broker/load/messages/received/total", receivedMessageCount); | 175 | publishStat("$SYS/broker/load/messages/received/total", receivedMessageCount); |
| @@ -391,54 +407,6 @@ int ThreadData::getNrOfClients() const | @@ -391,54 +407,6 @@ int ThreadData::getNrOfClients() const | ||
| 391 | return clients_by_fd.size(); | 407 | return clients_by_fd.size(); |
| 392 | } | 408 | } |
| 393 | 409 | ||
| 394 | -void ThreadData::incrementReceivedMessageCount() | ||
| 395 | -{ | ||
| 396 | - receivedMessageCount++; | ||
| 397 | -} | ||
| 398 | - | ||
| 399 | -uint64_t ThreadData::getReceivedMessageCount() const | ||
| 400 | -{ | ||
| 401 | - return receivedMessageCount; | ||
| 402 | -} | ||
| 403 | - | ||
| 404 | -/** | ||
| 405 | - * @brief ThreadData::getReceivedMessagePerSecond gets the amount of seconds received, averaged over the last time this was called. | ||
| 406 | - * @return | ||
| 407 | - * | ||
| 408 | - * Locking is not required, because the counter is not written to from here. | ||
| 409 | - */ | ||
| 410 | -uint64_t ThreadData::getReceivedMessagePerSecond() | ||
| 411 | -{ | ||
| 412 | - std::chrono::time_point<std::chrono::steady_clock> now = std::chrono::steady_clock::now(); | ||
| 413 | - std::chrono::milliseconds msSinceLastTime = std::chrono::duration_cast<std::chrono::milliseconds>(now - receivedMessagePreviousTime); | ||
| 414 | - uint64_t messagesTimes1000 = (receivedMessageCount - receivedMessageCountPrevious) * 1000; | ||
| 415 | - uint64_t result = messagesTimes1000 / (msSinceLastTime.count() + 1); // branchless avoidance of div by 0; | ||
| 416 | - receivedMessagePreviousTime = now; | ||
| 417 | - receivedMessageCountPrevious = receivedMessageCount; | ||
| 418 | - return result; | ||
| 419 | -} | ||
| 420 | - | ||
| 421 | -void ThreadData::incrementSentMessageCount(uint64_t n) | ||
| 422 | -{ | ||
| 423 | - sentMessageCount += n; | ||
| 424 | -} | ||
| 425 | - | ||
| 426 | -uint64_t ThreadData::getSentMessageCount() const | ||
| 427 | -{ | ||
| 428 | - return sentMessageCount; | ||
| 429 | -} | ||
| 430 | - | ||
| 431 | -uint64_t ThreadData::getSentMessagePerSecond() | ||
| 432 | -{ | ||
| 433 | - std::chrono::time_point<std::chrono::steady_clock> now = std::chrono::steady_clock::now(); | ||
| 434 | - std::chrono::milliseconds msSinceLastTime = std::chrono::duration_cast<std::chrono::milliseconds>(now - sentMessagePreviousTime); | ||
| 435 | - uint64_t messagesTimes1000 = (sentMessageCount - sentMessageCountPrevious) * 1000; | ||
| 436 | - uint64_t result = messagesTimes1000 / (msSinceLastTime.count() + 1); // branchless avoidance of div by 0; | ||
| 437 | - sentMessagePreviousTime = now; | ||
| 438 | - sentMessageCountPrevious = sentMessageCount; | ||
| 439 | - return result; | ||
| 440 | -} | ||
| 441 | - | ||
| 442 | void ThreadData::queueAuthPluginPeriodicEvent() | 410 | void ThreadData::queueAuthPluginPeriodicEvent() |
| 443 | { | 411 | { |
| 444 | std::lock_guard<std::mutex> locker(taskQueueMutex); | 412 | std::lock_guard<std::mutex> locker(taskQueueMutex); |
threaddata.h
| @@ -37,6 +37,7 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | @@ -37,6 +37,7 @@ License along with FlashMQ. If not, see <https://www.gnu.org/licenses/>. | ||
| 37 | #include "configfileparser.h" | 37 | #include "configfileparser.h" |
| 38 | #include "authplugin.h" | 38 | #include "authplugin.h" |
| 39 | #include "logger.h" | 39 | #include "logger.h" |
| 40 | +#include "derivablecounter.h" | ||
| 40 | 41 | ||
| 41 | typedef void (*thread_f)(ThreadData *); | 42 | typedef void (*thread_f)(ThreadData *); |
| 42 | 43 | ||
| @@ -55,14 +56,6 @@ class ThreadData | @@ -55,14 +56,6 @@ class ThreadData | ||
| 55 | std::shared_ptr<SubscriptionStore> subscriptionStore; | 56 | std::shared_ptr<SubscriptionStore> subscriptionStore; |
| 56 | Logger *logger; | 57 | Logger *logger; |
| 57 | 58 | ||
| 58 | - uint64_t receivedMessageCount = 0; | ||
| 59 | - uint64_t receivedMessageCountPrevious = 0; | ||
| 60 | - std::chrono::time_point<std::chrono::steady_clock> receivedMessagePreviousTime = std::chrono::steady_clock::now(); | ||
| 61 | - | ||
| 62 | - uint64_t sentMessageCount = 0; | ||
| 63 | - uint64_t sentMessageCountPrevious = 0; | ||
| 64 | - std::chrono::time_point<std::chrono::steady_clock> sentMessagePreviousTime = std::chrono::steady_clock::now(); | ||
| 65 | - | ||
| 66 | std::mutex clientsToRemoveMutex; | 59 | std::mutex clientsToRemoveMutex; |
| 67 | std::forward_list<std::weak_ptr<Client>> clientsQueuedForRemoving; | 60 | std::forward_list<std::weak_ptr<Client>> clientsQueuedForRemoving; |
| 68 | 61 | ||
| @@ -97,6 +90,10 @@ public: | @@ -97,6 +90,10 @@ public: | ||
| 97 | std::mutex taskQueueMutex; | 90 | std::mutex taskQueueMutex; |
| 98 | std::forward_list<std::function<void()>> taskQueue; | 91 | std::forward_list<std::function<void()>> taskQueue; |
| 99 | 92 | ||
| 93 | + DerivableCounter receivedMessageCounter; | ||
| 94 | + DerivableCounter sentMessageCounter; | ||
| 95 | + DerivableCounter mqttConnectCounter; | ||
| 96 | + | ||
| 100 | ThreadData(int threadnr, std::shared_ptr<SubscriptionStore> &subscriptionStore, std::shared_ptr<Settings> settings); | 97 | ThreadData(int threadnr, std::shared_ptr<SubscriptionStore> &subscriptionStore, std::shared_ptr<Settings> settings); |
| 101 | ThreadData(const ThreadData &other) = delete; | 98 | ThreadData(const ThreadData &other) = delete; |
| 102 | ThreadData(ThreadData &&other) = delete; | 99 | ThreadData(ThreadData &&other) = delete; |
| @@ -124,14 +121,6 @@ public: | @@ -124,14 +121,6 @@ public: | ||
| 124 | 121 | ||
| 125 | int getNrOfClients() const; | 122 | int getNrOfClients() const; |
| 126 | 123 | ||
| 127 | - void incrementReceivedMessageCount(); | ||
| 128 | - uint64_t getReceivedMessageCount() const; | ||
| 129 | - uint64_t getReceivedMessagePerSecond(); | ||
| 130 | - | ||
| 131 | - void incrementSentMessageCount(uint64_t n); | ||
| 132 | - uint64_t getSentMessageCount() const; | ||
| 133 | - uint64_t getSentMessagePerSecond(); | ||
| 134 | - | ||
| 135 | void queueAuthPluginPeriodicEvent(); | 124 | void queueAuthPluginPeriodicEvent(); |
| 136 | void authPluginPeriodicEvent(); | 125 | void authPluginPeriodicEvent(); |
| 137 | 126 |