[radio] refactor Radio::Statistics (#10961)

This commit refactors `Radio::Statistics` to be a nested type within
the `Radio` class. It is declared as a `friend` of `Radio` so that
its interaction with `Radio` can be defined as `private` methods.
This commit is contained in:
Abtin Keshavarzian
2024-11-22 17:07:54 -08:00
committed by GitHub
parent b29b6433d9
commit 051d8cd3c4
5 changed files with 88 additions and 74 deletions
+2 -2
View File
@@ -41,9 +41,9 @@ using namespace ot;
const otRadioTimeStats *otRadioTimeStatsGet(otInstance *aInstance)
{
return &AsCoreType(aInstance).Get<RadioStatistics>().GetStats();
return &AsCoreType(aInstance).Get<Radio::Statistics>().GetStats();
}
void otRadioTimeStatsReset(otInstance *aInstance) { AsCoreType(aInstance).Get<RadioStatistics>().ResetTime(); }
void otRadioTimeStatsReset(otInstance *aInstance) { AsCoreType(aInstance).Get<Radio::Statistics>().ResetTime(); }
#endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
+1 -1
View File
@@ -751,7 +751,7 @@ template <> inline Radio &Instance::Get(void) { return mRadio; }
template <> inline Radio::Callbacks &Instance::Get(void) { return mRadio.mCallbacks; }
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
template <> inline RadioStatistics &Instance::Get(void) { return mRadio.mRadioStatistics; }
template <> inline Radio::Statistics &Instance::Get(void) { return mRadio.mStatistics; }
#endif
#if OPENTHREAD_CONFIG_UPTIME_ENABLE
+10 -13
View File
@@ -117,19 +117,19 @@ Error Radio::Transmit(Mac::TxFrame &aFrame)
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
inline uint64_t UintSafeMinus(uint64_t aLhs, uint64_t aRhs) { return aLhs > aRhs ? (aLhs - aRhs) : 0; }
RadioStatistics::RadioStatistics(void)
Radio::Statistics::Statistics(void)
: mStatus(kDisabled)
{
ResetTime();
}
void RadioStatistics::RecordStateChange(Status aStatus)
void Radio::Statistics::RecordStateChange(Status aStatus)
{
UpdateTime();
mStatus = aStatus;
}
void RadioStatistics::HandleReceiveAt(uint32_t aDurationUs)
void Radio::Statistics::HandleReceiveAt(uint32_t aDurationUs)
{
// The actual rx time of ReceiveAt cannot be obtained from software level. This is a workaround.
if (mStatus == kSleep)
@@ -138,7 +138,7 @@ void RadioStatistics::HandleReceiveAt(uint32_t aDurationUs)
}
}
void RadioStatistics::RecordTxDone(otError aError, uint16_t aPsduLength)
void Radio::Statistics::RecordTxDone(otError aError, uint16_t aPsduLength)
{
if (aError == kErrorNone || aError == kErrorNoAck)
{
@@ -164,7 +164,7 @@ void RadioStatistics::RecordTxDone(otError aError, uint16_t aPsduLength)
}
}
void RadioStatistics::RecordRxDone(otError aError)
void Radio::Statistics::RecordRxDone(otError aError)
{
uint32_t ackTimeUs;
@@ -183,23 +183,20 @@ exit:
return;
}
const otRadioTimeStats &RadioStatistics::GetStats(void)
const Radio::Statistics::TimeStats &Radio::Statistics::GetStats(void)
{
UpdateTime();
return mTimeStats;
}
void RadioStatistics::ResetTime(void)
void Radio::Statistics::ResetTime(void)
{
mTimeStats.mDisabledTime = 0;
mTimeStats.mSleepTime = 0;
mTimeStats.mRxTime = 0;
mTimeStats.mTxTime = 0;
mLastUpdateTime = TimerMicro::GetNow();
ClearAllBytes(mTimeStats);
mLastUpdateTime = TimerMicro::GetNow();
}
void RadioStatistics::UpdateTime(void)
void Radio::Statistics::UpdateTime(void)
{
TimeMicro nowTime = TimerMicro::GetNow();
uint32_t timeElapsed = nowTime - mLastUpdateTime;
+73 -56
View File
@@ -79,59 +79,11 @@ static constexpr uint32_t kMinWakeupListenDuration = 100;
* @{
*/
/**
* Implements the radio statistics logic.
*
* The radio statistics are the time when the radio in TX/RX/radio state.
* Since this class collects these statistics from pure software level and no platform API is involved, a simplified
* model is used to calculate the time of different radio states. The data may not be very accurate, but it's
* sufficient to provide a general understanding of the proportion of time a device is in different radio states.
*
* The simplified model is:
* - The RadioStats is only aware of 2 states: RX and sleep.
* - Each time `Radio::Receive` or `Radio::Sleep` is called, it will check the current state and add the time since
* last time the methods were called. For example, `Sleep` is first called and `Receive` is called after 1 second,
* then 1 second will be added to SleepTime and the current state switches to `Receive`.
* - The time of TX will be calculated from the callback of TransmitDone. If TX returns OT_ERROR_NONE or
* OT_ERROR_NO_ACK, the tx time will be added according to the number of bytes sent. And the SleepTime or RxTime
* will be reduced accordingly.
* - When `GetStats` is called, an operation will be executed to calcute the time for the last state. And the result
* will be returned.
*/
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
#if !OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) && \
!OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
#error "OPENTHREAD_CONFIG_RADIO_STATS_ENABLE requires OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE".
#endif
class RadioStatistics
{
public:
enum Status : uint8_t
{
kDisabled,
kSleep,
kReceive,
};
explicit RadioStatistics(void);
void RecordStateChange(Status aStatus);
void HandleReceiveAt(uint32_t aDurationUs);
void RecordTxDone(otError aError, uint16_t aPsduLength);
void RecordRxDone(otError aError);
const otRadioTimeStats &GetStats(void);
void ResetTime(void);
private:
void UpdateTime(void);
Status mStatus;
otRadioTimeStats mTimeStats;
TimeMicro mLastUpdateTime;
};
#endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
/**
* Represents an OpenThread radio abstraction.
*/
@@ -263,6 +215,71 @@ public:
}
};
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
/**
* Implements the radio statistics logic.
*
* The radio statistics are the time when the radio in TX/RX/radio state.
* Since this class collects these statistics from pure software level
* and no platform API is involved, a simplified model is used to
* calculate the time of different radio states. The data may not be very
* accurate, but it's sufficient to provide a general understanding of
* the proportion of time a device is in different radio states.
*
* The simplified model is:
* - The radio statistics is only aware of 2 states: RX and sleep.
* - Each time `Radio::Receive` or `Radio::Sleep` is called, it will check
* the current state and add the time since last time the methods were
* called. For example, `Sleep` is first called and `Receive` is called
* after 1 second, then 1 second will be added to SleepTime and the
* current state switches to `Receive`.
* - The time of TX will be calculated from the callback of TransmitDone.
* If TX returns kErrorNone or kErrorNoAk, the tx time will be added
* according to the number of bytes sent. And the SleepTime or RxTime
* will be reduced accordingly.
* - When `GetStats` is called, an operation will be executed to calculate
* the time for the last state. And the result will be returned.
*/
class Statistics : private NonCopyable
{
friend class Radio;
friend class Callbacks;
public:
using TimeStats = otRadioTimeStats; ///< Radio statistics (time spend in each state).
/**
* Retrieves the current radio statistics.
*
* @return The current time statistics.
*/
const TimeStats &GetStats(void);
/**
* Resets the radio statistics.
*/
void ResetTime(void);
private:
enum Status : uint8_t{
kDisabled,
kSleep,
kReceive,
};
Statistics(void);
void RecordStateChange(Status aStatus);
void HandleReceiveAt(uint32_t aDurationUs);
void RecordTxDone(otError aError, uint16_t aPsduLength);
void RecordRxDone(otError aError);
void UpdateTime(void);
Status mStatus;
TimeStats mTimeStats;
TimeMicro mLastUpdateTime;
};
#endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
/**
* Initializes the `Radio` object.
*
@@ -835,7 +852,7 @@ private:
Callbacks mCallbacks;
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
RadioStatistics mRadioStatistics;
Statistics mStatistics;
#endif
};
@@ -912,7 +929,7 @@ inline otRadioState Radio::GetState(void) { return otPlatRadioGetState(GetInstan
inline Error Radio::Enable(void)
{
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
mRadioStatistics.RecordStateChange(RadioStatistics::kSleep);
mStatistics.RecordStateChange(Statistics::kSleep);
#endif
return otPlatRadioEnable(GetInstancePtr());
}
@@ -920,7 +937,7 @@ inline Error Radio::Enable(void)
inline Error Radio::Disable(void)
{
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
mRadioStatistics.RecordStateChange(RadioStatistics::kDisabled);
mStatistics.RecordStateChange(Statistics::kDisabled);
#endif
return otPlatRadioDisable(GetInstancePtr());
}
@@ -930,7 +947,7 @@ inline bool Radio::IsEnabled(void) { return otPlatRadioIsEnabled(GetInstancePtr(
inline Error Radio::Sleep(void)
{
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
mRadioStatistics.RecordStateChange(RadioStatistics::kSleep);
mStatistics.RecordStateChange(Statistics::kSleep);
#endif
return otPlatRadioSleep(GetInstancePtr());
}
@@ -938,7 +955,7 @@ inline Error Radio::Sleep(void)
inline Error Radio::Receive(uint8_t aChannel)
{
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
mRadioStatistics.RecordStateChange(RadioStatistics::kReceive);
mStatistics.RecordStateChange(Statistics::kReceive);
#endif
return otPlatRadioReceive(GetInstancePtr(), aChannel);
}
@@ -950,7 +967,7 @@ inline Error Radio::ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDurat
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
if (error == kErrorNone)
{
mRadioStatistics.HandleReceiveAt(aDuration);
mStatistics.HandleReceiveAt(aDuration);
}
#endif
return error;
+2 -2
View File
@@ -40,7 +40,7 @@ namespace ot {
void Radio::Callbacks::HandleReceiveDone(Mac::RxFrame *aFrame, Error aError)
{
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
Get<RadioStatistics>().RecordRxDone(aError);
Get<Radio::Statistics>().RecordRxDone(aError);
#endif
Get<Mac::SubMac>().HandleReceiveDone(aFrame, aError);
}
@@ -50,7 +50,7 @@ void Radio::Callbacks::HandleTransmitStarted(Mac::TxFrame &aFrame) { Get<Mac::Su
void Radio::Callbacks::HandleTransmitDone(Mac::TxFrame &aFrame, Mac::RxFrame *aAckFrame, Error aError)
{
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
Get<RadioStatistics>().RecordTxDone(aError, aFrame.GetLength());
Get<Radio::Statistics>().RecordTxDone(aError, aFrame.GetLength());
#endif
Get<Mac::SubMac>().HandleTransmitDone(aFrame, aAckFrame, aError);
}