From e6df00dd66e245a54551d53512dd6e88237abcca Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 10 Jul 2023 13:34:35 -0700 Subject: [PATCH] [mesh-forwarder] add time-in-queue statistics collection feature (#9170) This commit adds the ability to collect statistics on the time messages spend in the TX queue. When enabled, a histogram of the time-in-queue is collected. The time-in-queue is tracked for direct transmissions only, and is measured as the duration from when a message is added to the TX queue until it is passed to the MAC layer for transmission or dropped. The histogram data consists of a number of bins, each representing a range of time-in-queue values. The bin interval length and maximum tracked interval can be configured using newly added configuration options. This commit also adds a new public OT API and a related CLI command (`timeinqueue`) to get the collected statistics or reset the data. --- etc/cmake/options.cmake | 1 + include/openthread/instance.h | 2 +- include/openthread/thread.h | 57 ++++++++++++ src/cli/README.md | 92 +++++++++++++++++++ src/cli/cli.cpp | 136 +++++++++++++++++++++++++++++ src/core/api/thread_api.cpp | 20 +++++ src/core/config/mesh_forwarder.h | 52 +++++++++++ src/core/thread/mesh_forwarder.cpp | 30 +++++++ src/core/thread/mesh_forwarder.hpp | 71 +++++++++++++++ 9 files changed, 460 insertions(+), 1 deletion(-) diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 236a9053d..abdfe3a27 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -150,6 +150,7 @@ ot_option(OT_TCP OPENTHREAD_CONFIG_TCP_ENABLE "TCP") ot_option(OT_TIME_SYNC OPENTHREAD_CONFIG_TIME_SYNC_ENABLE "time synchronization service") ot_option(OT_TREL OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE "TREL radio link for Thread over Infrastructure feature") ot_option(OT_TX_BEACON_PAYLOAD OPENTHREAD_CONFIG_MAC_OUTGOING_BEACON_PAYLOAD_ENABLE "tx beacon payload") +ot_option(OT_TX_QUEUE_STATS OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE "tx queue statistics") ot_option(OT_UDP_FORWARD OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE "UDP forward") ot_option(OT_UPTIME OPENTHREAD_CONFIG_UPTIME_ENABLE "uptime") diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 3920f6484..a92a6b532 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (341) +#define OPENTHREAD_API_VERSION (342) /** * @addtogroup api-instance diff --git a/include/openthread/thread.h b/include/openthread/thread.h index 47cd7865b..cb0d6bda2 100644 --- a/include/openthread/thread.h +++ b/include/openthread/thread.h @@ -902,6 +902,63 @@ const otIpCounters *otThreadGetIp6Counters(otInstance *aInstance); */ void otThreadResetIp6Counters(otInstance *aInstance); +/** + * Gets the time-in-queue histogram for messages in the TX queue. + * + * Requires `OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE`. + * + * Histogram of the time-in-queue of messages in the transmit queue is collected. The time-in-queue is tracked for + * direct transmissions only and is measured as the duration from when a message is added to the transmit queue until + * it is passed to the MAC layer for transmission or dropped. + * + * The histogram is returned as an array of `uint32_t` values with `aNumBins` entries. The first entry in the array + * (at index 0) represents the number of messages with a time-in-queue less than `aBinInterval`. The second entry + * represents the number of messages with a time-in-queue greater than or equal to `aBinInterval`, but less than + * `2 * aBinInterval`. And so on. The last entry represents the number of messages with time-in-queue greater than or + * equal to `(aNumBins - 1) * aBinInterval`. + * + * The collected statistics can be reset by calling `otThreadResetTimeInQueueStat()`. The histogram information is + * collected since the OpenThread instance was initialized or since the last time statistics collection was reset by + * calling the `otThreadResetTimeInQueueStat()`. + * + * Pointers @p aNumBins and @p aBinInterval MUST NOT be NULL. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[out] aNumBins Pointer to return the number of bins in histogram (array length). + * @param[out] aBinInterval Pointer to return the histogram bin interval length in milliseconds. + * + * @returns A pointer to an array of @p aNumBins entries representing the collected histogram info. + * + */ +const uint32_t *otThreadGetTimeInQueueHistogram(otInstance *aInstance, uint16_t *aNumBins, uint32_t *aBinInterval); + +/** + * Gets the maximum time-in-queue for messages in the TX queue. + * + * Requires `OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE`. + * + * The time-in-queue is tracked for direct transmissions only and is measured as the duration from when a message is + * added to the transmit queue until it is passed to the MAC layer for transmission or dropped. + * + * The collected statistics can be reset by calling `otThreadResetTimeInQueueStat()`. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The maximum time-in-queue in milliseconds for all messages in the TX queue (so far). + * + */ +uint32_t otThreadGetMaxTimeInQueue(otInstance *aInstance); + +/** + * Resets the TX queue time-in-queue statistics. + * + * Requires `OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE`. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + */ +void otThreadResetTimeInQueueStat(otInstance *aInstance); + /** * Gets the Thread MLE counters. * diff --git a/src/cli/README.md b/src/cli/README.md index c066a1f5d..1fbb49ff3 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -117,6 +117,7 @@ Done - [srp](README_SRP.md) - [tcp](README_TCP.md) - [thread](#thread-start) +- [timeinqueue](#timeinqueue) - [trel](#trel) - [tvcheck](#tvcheck-enable) - [txpower](#txpower) @@ -3362,6 +3363,97 @@ Get the Thread Version number. Done ``` +### timeinqueue + +Print the tx queue time-in-queue histogram. + +Requires `OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE`. + +The time-in-queue is tracked for direct transmissions only and is measured as the duration from when a message is added to the transmit queue until it is passed to the MAC layer for transmission or dropped. + +Each table row shows min and max time-in-queue (in milliseconds) followed by number of messages with time-in-queue within the specified min-max range. The histogram information is collected since the OpenThread instance was initialized or since the last time statistics collection was reset by the `timeinqueue reset` command. + +The collected statistics can be reset by `timeinqueue reset`. + +```bash +> timeinqueue +| Min | Max |Msg Count| ++------+------+---------+ +| 0 | 9 | 1537 | +| 10 | 19 | 156 | +| 20 | 29 | 57 | +| 30 | 39 | 108 | +| 40 | 49 | 60 | +| 50 | 59 | 76 | +| 60 | 69 | 88 | +| 70 | 79 | 51 | +| 80 | 89 | 86 | +| 90 | 99 | 45 | +| 100 | 109 | 43 | +| 110 | 119 | 44 | +| 120 | 129 | 38 | +| 130 | 139 | 44 | +| 140 | 149 | 35 | +| 150 | 159 | 41 | +| 160 | 169 | 34 | +| 170 | 179 | 13 | +| 180 | 189 | 24 | +| 190 | 199 | 3 | +| 200 | 209 | 0 | +| 210 | 219 | 0 | +| 220 | 229 | 2 | +| 230 | 239 | 0 | +| 240 | 249 | 0 | +| 250 | 259 | 0 | +| 260 | 269 | 0 | +| 270 | 279 | 0 | +| 280 | 289 | 0 | +| 290 | 299 | 1 | +| 300 | 309 | 0 | +| 310 | 319 | 0 | +| 320 | 329 | 0 | +| 330 | 339 | 0 | +| 340 | 349 | 0 | +| 350 | 359 | 0 | +| 360 | 369 | 0 | +| 370 | 379 | 0 | +| 380 | 389 | 0 | +| 390 | 399 | 0 | +| 400 | 409 | 0 | +| 410 | 419 | 0 | +| 420 | 429 | 0 | +| 430 | 439 | 0 | +| 440 | 449 | 0 | +| 450 | 459 | 0 | +| 460 | 469 | 0 | +| 470 | 479 | 0 | +| 480 | 489 | 0 | +| 490 | inf | 0 | +Done +``` + +### timeinqueue max + +Print the maximum observed time-in-queue in milliseconds. + +Requires `OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE`. + +The time-in-queue is tracked for direct transmissions only and is measured as the duration from when a message is added to the transmit queue until it is passed to the MAC layer for transmission or dropped. + +```bash +> timeinqueue max +291 +``` + +### timeinqueue reset + +Reset the TX queue time-in-queue statistics. + +```bash +> timeinqueue reset +Done +``` + ### trel Indicate whether TREL radio operation is enabled or not. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 30e752846..9b8a454bb 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -6948,6 +6948,139 @@ template <> otError Interpreter::Process(Arg aArgs[]) return error; } +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE +template <> otError Interpreter::Process(Arg aArgs[]) +{ + otError error = OT_ERROR_NONE; + + /** + * @cli timeinqueue + * @code + * timeinqueue + * | Min | Max |Msg Count| + * +------+------+---------+ + * | 0 | 9 | 1537 | + * | 10 | 19 | 156 | + * | 20 | 29 | 57 | + * | 30 | 39 | 108 | + * | 40 | 49 | 60 | + * | 50 | 59 | 76 | + * | 60 | 69 | 88 | + * | 70 | 79 | 51 | + * | 80 | 89 | 86 | + * | 90 | 99 | 45 | + * | 100 | 109 | 43 | + * | 110 | 119 | 44 | + * | 120 | 129 | 38 | + * | 130 | 139 | 44 | + * | 140 | 149 | 35 | + * | 150 | 159 | 41 | + * | 160 | 169 | 34 | + * | 170 | 179 | 13 | + * | 180 | 189 | 24 | + * | 190 | 199 | 3 | + * | 200 | 209 | 0 | + * | 210 | 219 | 0 | + * | 220 | 229 | 2 | + * | 230 | 239 | 0 | + * | 240 | 249 | 0 | + * | 250 | 259 | 0 | + * | 260 | 269 | 0 | + * | 270 | 279 | 0 | + * | 280 | 289 | 0 | + * | 290 | 299 | 1 | + * | 300 | 309 | 0 | + * | 310 | 319 | 0 | + * | 320 | 329 | 0 | + * | 330 | 339 | 0 | + * | 340 | 349 | 0 | + * | 350 | 359 | 0 | + * | 360 | 369 | 0 | + * | 370 | 379 | 0 | + * | 380 | 389 | 0 | + * | 390 | 399 | 0 | + * | 400 | 409 | 0 | + * | 410 | 419 | 0 | + * | 420 | 429 | 0 | + * | 430 | 439 | 0 | + * | 440 | 449 | 0 | + * | 450 | 459 | 0 | + * | 460 | 469 | 0 | + * | 470 | 479 | 0 | + * | 480 | 489 | 0 | + * | 490 | inf | 0 | + * Done + * @endcode + * @par api_copy + * #otThreadGetTimeInQueueHistogram + * @csa{timeinqueue reset} + */ + if (aArgs[0].IsEmpty()) + { + static const char *const kTimeInQueueTableTitles[] = {"Min", "Max", "Msg Count"}; + static const uint8_t kTimeInQueueTableColumnWidths[] = {6, 6, 9}; + + uint16_t numBins; + uint32_t binInterval; + const uint32_t *histogram; + + OutputTableHeader(kTimeInQueueTableTitles, kTimeInQueueTableColumnWidths); + + histogram = otThreadGetTimeInQueueHistogram(GetInstancePtr(), &numBins, &binInterval); + + for (uint16_t index = 0; index < numBins; index++) + { + OutputFormat("| %4lu | ", ToUlong(index * binInterval)); + + if (index < numBins - 1) + { + OutputFormat("%4lu", ToUlong((index + 1) * binInterval - 1)); + } + else + { + OutputFormat("%4s", "inf"); + } + + OutputLine(" | %7lu |", ToUlong(histogram[index])); + } + } + /** + * @cli timeinqueue max + * @code + * timeinqueue max + * 281 + * Done + * @endcode + * @par api_copy + * #otThreadGetMaxTimeInQueue + * @csa{timeinqueue reset} + */ + else if (aArgs[0] == "max") + { + OutputLine("%lu", ToUlong(otThreadGetMaxTimeInQueue(GetInstancePtr()))); + } + /** + * @cli timeinqueue reset + * @code + * timeinqueue reset + * Done + * @endcode + * @par api_copy + * #otThreadResetTimeInQueueStat + */ + else if (aArgs[0] == "reset") + { + otThreadResetTimeInQueueStat(GetInstancePtr()); + } + else + { + error = OT_ERROR_INVALID_ARGS; + } + + return error; +} +#endif // OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + template <> otError Interpreter::Process(Arg aArgs[]) { return mDataset.Process(aArgs); } template <> otError Interpreter::Process(Arg aArgs[]) @@ -7988,6 +8121,9 @@ otError Interpreter::ProcessCommand(Arg aArgs[]) CmdEntry("tcp"), #endif CmdEntry("thread"), +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + CmdEntry("timeinqueue"), +#endif #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE CmdEntry("trel"), #endif diff --git a/src/core/api/thread_api.cpp b/src/core/api/thread_api.cpp index 778a663c8..1811cf49b 100644 --- a/src/core/api/thread_api.cpp +++ b/src/core/api/thread_api.cpp @@ -430,6 +430,26 @@ const otIpCounters *otThreadGetIp6Counters(otInstance *aInstance) void otThreadResetIp6Counters(otInstance *aInstance) { AsCoreType(aInstance).Get().ResetCounters(); } +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE +const uint32_t *otThreadGetTimeInQueueHistogram(otInstance *aInstance, uint16_t *aNumBins, uint32_t *aBinInterval) +{ + AssertPointerIsNotNull(aNumBins); + AssertPointerIsNotNull(aBinInterval); + + return AsCoreType(aInstance).Get().GetTimeInQueueHistogram(*aNumBins, *aBinInterval); +} + +uint32_t otThreadGetMaxTimeInQueue(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().GetMaxTimeInQueue(); +} + +void otThreadResetTimeInQueueStat(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().ResetTimeInQueueStat(); +} +#endif + const otMleCounters *otThreadGetMleCounters(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetCounters(); diff --git a/src/core/config/mesh_forwarder.h b/src/core/config/mesh_forwarder.h index 497b84f0f..c5e12d48b 100644 --- a/src/core/config/mesh_forwarder.h +++ b/src/core/config/mesh_forwarder.h @@ -34,6 +34,8 @@ #ifndef CONFIG_MESH_FORWARDER_H_ #define CONFIG_MESH_FORWARDER_H_ +#include "config/border_router.h" + /** * @def OPENTHREAD_CONFIG_DROP_MESSAGE_ON_FRAGMENT_TX_FAILURE * @@ -148,4 +150,54 @@ #endif #endif +/** + * @def OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + * + * Define as 1 to enable TX queue time-in-queue statistics collection feature. + * + * When enabled, histogram of the time-in-queue of messages in the transmit queue is collected. The time-in-queue is + * tracked for direct transmissions only and is measured as the duration from when a message is added to the transmit + * queue until it is passed to the MAC layer for transmission or dropped. + * + * The histogram data consists of number of bins, each representing a range of time-in-queue values. The bin interval + * length is specified by the `OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_BIN_INTERVAL` configuration, and the + * maximum tracked interval is given by the `OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_MAX_INTERVAL`. + * + * Along with histogram, the maximum observed time-in-queue is also tracked. + * + */ +#ifndef OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE +#define OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE (OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_FTD) +#endif + +/** + * @def OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_MAX_INTERVAL + * + * Specifies the maximum time-in-queue interval in milliseconds tracked by the histogram when the TX queue time-in-queue + * statistics collection feature is enabled. + * + * By default the `OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL` is used which defines the + * maximum time-in-queue interval after which a non-ECN capable message is dropped by delay-aware queue management + * feature. + * + */ +#ifndef OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_MAX_INTERVAL +#define OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_MAX_INTERVAL \ + OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_MARK_ECN_INTERVAL +#endif + +/** + * @def OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_BIN_INTERVAL + * + * Specifies the time-in-queue histogram bin interval in milliseconds when the TX queue time-in-queue statistics + * collection feature is enabled. + * + * The number of bins is calculated by dividing `OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_MAX_INTERVAL` by + * `OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_BIN_INTERVAL` and rounding up to the nearest integer. + * + */ +#ifndef OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_BIN_INTERVAL +#define OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_BIN_INTERVAL 10 +#endif + #endif // CONFIG_MESH_FORWARDER_H_ diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index ca24fa41c..1e80d40d5 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -132,6 +132,10 @@ MeshForwarder::MeshForwarder(Instance &aInstance) #if OPENTHREAD_FTD mFragmentPriorityList.Clear(); #endif + +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + mTxQueueStats.Clear(); +#endif } void MeshForwarder::Start(void) @@ -380,6 +384,9 @@ Error MeshForwarder::UpdateEcnOrDrop(Message &aMessage, bool aPreparingToSend) exit: if (error == kErrorDrop) { +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + mTxQueueStats.UpdateFor(aMessage); +#endif LogMessage(kMessageQueueMgmtDrop, aMessage); aMessage.ClearDirectTransmission(); RemoveMessageIfNoPendingTx(aMessage); @@ -503,6 +510,23 @@ exit: #endif // (OPENTHREAD_CONFIG_MAX_FRAMES_IN_DIRECT_TX_QUEUE > 0) +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE +const uint32_t *MeshForwarder::TxQueueStats::GetHistogram(uint16_t &aNumBins, uint32_t &aBinInterval) const +{ + aNumBins = kNumHistBins; + aBinInterval = kHistBinInterval; + return mHistogram; +} + +void MeshForwarder::TxQueueStats::UpdateFor(const Message &aMessage) +{ + uint32_t timeInQueue = TimerMilli::GetNow() - aMessage.GetTimestamp(); + + mHistogram[Min(timeInQueue / kHistBinInterval, kNumHistBins - 1)]++; + mMaxInterval = Max(mMaxInterval, timeInQueue); +} +#endif + void MeshForwarder::ScheduleTransmissionTask(void) { VerifyOrExit(!mSendBusy && !mTxPaused); @@ -585,6 +609,9 @@ Message *MeshForwarder::PrepareNextDirectTransmission(void) switch (error) { case kErrorNone: +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + mTxQueueStats.UpdateFor(*curMessage); +#endif ExitNow(); #if OPENTHREAD_FTD @@ -594,6 +621,9 @@ Message *MeshForwarder::PrepareNextDirectTransmission(void) #endif default: +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + mTxQueueStats.UpdateFor(*curMessage); +#endif LogMessage(kMessageDrop, *curMessage, error); mSendQueue.DequeueAndFree(*curMessage); continue; diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index cfbb82aeb..7bb8f5c77 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -311,6 +311,55 @@ public: */ void ResetCounters(void) { memset(&mIpCounters, 0, sizeof(mIpCounters)); } +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + /** + * Gets the time-in-queue histogram for messages in the TX queue. + * + * Histogram of the time-in-queue of messages in the transmit queue is collected. The time-in-queue is tracked for + * direct transmissions only and is measured as the duration from when a message is added to the transmit queue + * until it is passed to the MAC layer for transmission or dropped. + * + * The histogram is returned as an array of `uint32_t` values with `aNumBins` entries. The first entry in the array + * (at index 0) represents the number of messages with a time-in-queue less than `aBinInterval`. The second entry + * represents the number of messages with a time-in-queue greater than or equal to `aBinInterval`, but less than + * `2 * aBinInterval`. And so on. The last entry represents the number of messages with time-in-queue greater than + * or * equal to `(aNumBins - 1) * aBinInterval`. + * + * The collected statistics can be reset by calling `ResetTimeInQueueStat()`. The histogram information is + * collected since the OpenThread instance was initialized or since the last time statistics collection was reset + * by calling the `ResetTimeInQueueStat()`. + * + * @param[out] aNumBins Reference to return the number of bins in histogram (array length). + * @param[out] aBinInterval Reference to return the histogram bin interval length in milliseconds. + * + * @returns A pointer to an array of @p aNumBins entries representing the collected histogram info. + * + */ + const uint32_t *GetTimeInQueueHistogram(uint16_t &aNumBins, uint32_t &aBinInterval) const + { + return mTxQueueStats.GetHistogram(aNumBins, aBinInterval); + } + + /** + * Gets the maximum time-in-queue for messages in the TX queue. + * + * The time-in-queue is tracked for direct transmissions only and is measured as the duration from when a message + * is added to the transmit queue until it is passed to the MAC layer for transmission or dropped. + * + * The collected statistics can be reset by calling `ResetTimeInQueueStat()`. + * + * @returns The maximum time-in-queue in milliseconds for all messages in the TX queue (so far). + * + */ + uint32_t GetMaxTimeInQueue(void) const { return mTxQueueStats.GetMaxInterval(); } + + /** + * Resets the TX queue time-in-queue statistics. + * + */ + void ResetTimeInQueueStat(void) { mTxQueueStats.Clear(); } +#endif + #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE /** * Handles a deferred ack. @@ -432,6 +481,24 @@ private: }; #endif // OPENTHREAD_FTD +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + class TxQueueStats : public Clearable + { + public: + const uint32_t *GetHistogram(uint16_t &aNumBins, uint32_t &aBinInterval) const; + uint32_t GetMaxInterval(void) const { return mMaxInterval; } + void UpdateFor(const Message &aMessage); + + private: + static constexpr uint32_t kHistMaxInterval = OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_MAX_INTERVAL; + static constexpr uint32_t kHistBinInterval = OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_HISTOGRAM_BIN_INTERVAL; + static constexpr uint16_t kNumHistBins = (kHistMaxInterval + kHistBinInterval - 1) / kHistBinInterval; + + uint32_t mMaxInterval; + uint32_t mHistogram[kNumHistBins]; + }; +#endif + void SendIcmpErrorIfDstUnreach(const Message &aMessage, const Mac::Addresses &aMacAddrs); Error CheckReachability(const FrameData &aFrameData, const Mac::Addresses &aMeshAddrs); void UpdateRoutes(const FrameData &aFrameData, const Mac::Addresses &aMeshAddrs); @@ -603,6 +670,10 @@ private: #endif DataPollSender mDataPollSender; + +#if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE + TxQueueStats mTxQueueStats; +#endif }; /**