diff --git a/src/messaging/ReliableMessageMgr.cpp b/src/messaging/ReliableMessageMgr.cpp index f764d62c8cde30..753c95871e4335 100644 --- a/src/messaging/ReliableMessageMgr.cpp +++ b/src/messaging/ReliableMessageMgr.cpp @@ -204,26 +204,35 @@ CHIP_ERROR ReliableMessageMgr::AddToRetransTable(ReliableMessageContext * rc, Re System::Clock::Timestamp ReliableMessageMgr::GetBackoff(System::Clock::Timestamp baseInterval, uint8_t sendCount) { + // See section "4.11.8. Parameters and Constants" for the parameters below: + // MRP_BACKOFF_JITTER = 0.25 constexpr uint32_t MRP_BACKOFF_JITTER_BASE = 1024; - // MRP_BACKOFF_BASE = 1.6; see section "4.11.8. Parameters and Constants" + // MRP_BACKOFF_MARGIN = 1.1 + constexpr uint32_t MRP_BACKOFF_MARGIN_NUMERATOR = 1127; + constexpr uint32_t MRP_BACKOFF_MARGIN_DENOMINATOR = 1024; + // MRP_BACKOFF_BASE = 1.6 constexpr uint32_t MRP_BACKOFF_BASE_NUMERATOR = 16; constexpr uint32_t MRP_BACKOFF_BASE_DENOMINATOR = 10; constexpr int MRP_BACKOFF_THRESHOLD = 1; + // Implement `i = MRP_BACKOFF_MARGIN * i` from section "4.11.2.1. Retransmissions", where: + // i == baseInterval + baseInterval = baseInterval * MRP_BACKOFF_MARGIN_NUMERATOR / MRP_BACKOFF_MARGIN_DENOMINATOR; + // Implement: // mrpBackoffTime = i * MRP_BACKOFF_BASE^(max(0,n-MRP_BACKOFF_THRESHOLD)) * (1.0 + random(0,1) * MRP_BACKOFF_JITTER) // from section "4.11.2.1. Retransmissions", where: // i == baseInterval // n == sendCount - // Calculate exponent `max(0,n−MRP_BACKOFF_THRESHOLD)` + // 1. Calculate exponent `max(0,n−MRP_BACKOFF_THRESHOLD)` int exponent = sendCount - MRP_BACKOFF_THRESHOLD; if (exponent < 0) exponent = 0; // Enforce floor if (exponent > 4) exponent = 4; // Enforce reasonable maximum after 5 tries - // Calculate `mrpBackoffTime = i * MRP_BACKOFF_BASE^(max(0,n-MRP_BACKOFF_THRESHOLD))` + // 2. Calculate `mrpBackoffTime = i * MRP_BACKOFF_BASE^(max(0,n-MRP_BACKOFF_THRESHOLD))` uint32_t backoffNum = 1; uint32_t backoffDenom = 1; @@ -235,8 +244,7 @@ System::Clock::Timestamp ReliableMessageMgr::GetBackoff(System::Clock::Timestamp System::Clock::Timestamp mrpBackoffTime = baseInterval * backoffNum / backoffDenom; - // Multiply `mrpBackoffTime` by `(1.0 + random(0,1) * MRP_BACKOFF_JITTER)`, - // where MRP_BACKOFF_JITTER = 0.25; see section "4.11.8. Parameters and Constants". + // 3. Calculate `mrpBackoffTime *= (1.0 + random(0,1) * MRP_BACKOFF_JITTER)` uint32_t jitter = MRP_BACKOFF_JITTER_BASE + Crypto::GetRandU8(); mrpBackoffTime = mrpBackoffTime * jitter / MRP_BACKOFF_JITTER_BASE; diff --git a/src/messaging/tests/TestReliableMessageProtocol.cpp b/src/messaging/tests/TestReliableMessageProtocol.cpp index 68c0ad717693f4..e4e9f609d2b275 100644 --- a/src/messaging/tests/TestReliableMessageProtocol.cpp +++ b/src/messaging/tests/TestReliableMessageProtocol.cpp @@ -183,44 +183,86 @@ struct BackoffComplianceTestVector theBackoffComplianceTestVector[] = { { .sendCount = 0, .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(300), - .backoffMax = System::Clock::Timeout(375), + .backoffMin = System::Clock::Timeout(330), + .backoffMax = System::Clock::Timeout(413), }, { .sendCount = 1, .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(300), - .backoffMax = System::Clock::Timeout(375), + .backoffMin = System::Clock::Timeout(330), + .backoffMax = System::Clock::Timeout(413), }, { .sendCount = 2, .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(480), - .backoffMax = System::Clock::Timeout(600), + .backoffMin = System::Clock::Timeout(528), + .backoffMax = System::Clock::Timeout(660), }, { .sendCount = 3, .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(768), - .backoffMax = System::Clock::Timeout(960), + .backoffMin = System::Clock::Timeout(844), + .backoffMax = System::Clock::Timeout(1057), }, { .sendCount = 4, .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(1228), - .backoffMax = System::Clock::Timeout(1536), + .backoffMin = System::Clock::Timeout(1351), + .backoffMax = System::Clock::Timeout(1690), }, { .sendCount = 5, .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(1966), - .backoffMax = System::Clock::Timeout(2458), + .backoffMin = System::Clock::Timeout(2162), + .backoffMax = System::Clock::Timeout(2704), }, { .sendCount = 6, .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(1966), - .backoffMax = System::Clock::Timeout(2458), + .backoffMin = System::Clock::Timeout(2162), + .backoffMax = System::Clock::Timeout(2704), + }, + { + .sendCount = 0, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(4400), + .backoffMax = System::Clock::Timeout(5500), + }, + { + .sendCount = 1, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(4400), + .backoffMax = System::Clock::Timeout(5500), + }, + { + .sendCount = 2, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(7040), + .backoffMax = System::Clock::Timeout(8800), + }, + { + .sendCount = 3, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(11264), + .backoffMax = System::Clock::Timeout(14081), + }, + { + .sendCount = 4, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(18022), + .backoffMax = System::Clock::Timeout(22529), + }, + { + .sendCount = 5, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(28835), + .backoffMax = System::Clock::Timeout(36045), + }, + { + .sendCount = 6, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(28835), + .backoffMax = System::Clock::Timeout(36045), }, }; @@ -323,7 +365,7 @@ void CheckResendApplicationMessage(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, loopback.mDroppedMessageCount == 1); NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 1); - // Wait for the initial message to fail (should take 300-375ms) + // Wait for the initial message to fail (should take 330-413ms) ctx.GetIOContext().DriveIOUntil(1000_ms32, [&] { return loopback.mSentMessageCount >= 2; }); now = System::SystemClock().GetMonotonicTimestamp(); timeoutTime = now - startTime; @@ -340,7 +382,7 @@ void CheckResendApplicationMessage(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, loopback.mDroppedMessageCount == 2); NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 1); - // Wait for the 1st retry to fail (should take 300-375ms) + // Wait for the 1st retry to fail (should take 330-413ms) ctx.GetIOContext().DriveIOUntil(1000_ms32, [&] { return loopback.mSentMessageCount >= 3; }); now = System::SystemClock().GetMonotonicTimestamp(); timeoutTime = now - startTime; @@ -357,7 +399,7 @@ void CheckResendApplicationMessage(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, loopback.mDroppedMessageCount == 3); NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 1); - // Wait for the 2nd retry to fail (should take 480-600msms) + // Wait for the 2nd retry to fail (should take 528-660ms) ctx.GetIOContext().DriveIOUntil(1000_ms32, [&] { return loopback.mSentMessageCount >= 4; }); now = System::SystemClock().GetMonotonicTimestamp(); timeoutTime = now - startTime; @@ -374,8 +416,8 @@ void CheckResendApplicationMessage(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, loopback.mDroppedMessageCount == 4); NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 1); - // Wait for the 3rd retry to fail (should take 768-960ms) - ctx.GetIOContext().DriveIOUntil(1000_ms32, [&] { return loopback.mSentMessageCount >= 5; }); + // Wait for the 3rd retry to fail (should take 845-1056ms) + ctx.GetIOContext().DriveIOUntil(1500_ms32, [&] { return loopback.mSentMessageCount >= 5; }); now = System::SystemClock().GetMonotonicTimestamp(); timeoutTime = now - startTime; ChipLogProgress(Test, "Attempt #4 Timeout : %d ms", timeoutTime.count()); @@ -1613,7 +1655,8 @@ void CheckGetBackoff(nlTestSuite * inSuite, void * inContext) { struct BackoffComplianceTestVector * test = &theBackoffComplianceTestVector[i]; System::Clock::Timeout backoff = ReliableMessageMgr::GetBackoff(test->backoffBase, test->sendCount); - ChipLogProgress(Test, "Backoff # %d: %" PRIu32, test->sendCount, (uint32_t) backoff.count()); + ChipLogProgress(Test, "Backoff base %" PRIu32 " # %d: %" PRIu32, test->backoffBase.count(), test->sendCount, + backoff.count()); NL_TEST_ASSERT(inSuite, backoff >= test->backoffMin); NL_TEST_ASSERT(inSuite, backoff <= test->backoffMax);