Skip to content

Commit

Permalink
[mrp] Implement MRP_BACKOFF_MARGIN
Browse files Browse the repository at this point in the history
Base interval (active or idle) should be multiplied by
MRP_BACKOFF_MARGIN = 1.1 before putting it in the MRP
backoff formula.

Signed-off-by: Damian Krolik <[email protected]>
  • Loading branch information
Damian-Nordic committed Jul 28, 2022
1 parent 15443cc commit 1758f54
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 25 deletions.
18 changes: 13 additions & 5 deletions src/messaging/ReliableMessageMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand Down
83 changes: 63 additions & 20 deletions src/messaging/tests/TestReliableMessageProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
},
};

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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());
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 1758f54

Please sign in to comment.