Skip to content

Commit f35f910

Browse files
Change Thread OTA throttling algorithm in Matter.framework. (#37562)
Throttle by rounding up to the nearest multiple of our throttle interval, not by just comparing to that interval. This matches the old "poll at 50ms" behavior we had.
1 parent 4e1c44b commit f35f910

File tree

4 files changed

+18
-18
lines changed

4 files changed

+18
-18
lines changed

src/darwin/Framework/CHIP/MTROTAImageTransferHandler.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class MTROTAImageTransferHandler : public chip::bdx::AsyncResponder {
7777

7878
bool mIsPeerNodeAKnownThreadDevice = NO;
7979

80-
chip::System::Clock::Milliseconds32 mBDXThrottleIntervalForThreadDevicesInMSecs;
80+
chip::System::Clock::Milliseconds32 mBDXThrottleIntervalForThreadDevices;
8181
};
8282

8383
NS_ASSUME_NONNULL_END

src/darwin/Framework/CHIP/MTROTAImageTransferHandler.mm

+13-14
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
// To override the throttle interval,
4141
// use ` defaults write <domain> BDXThrottleIntervalForThreadDevicesInMSecs <throttleIntervalinMsecs>`
4242
// See UserDefaults.mm for details.
43-
constexpr auto kBdxThrottleDefaultIntervalInMsecs = System::Clock::Milliseconds32(50);
43+
constexpr auto kBdxThrottleDefaultInterval = System::Clock::Milliseconds32(50);
4444

4545
constexpr bdx::TransferRole kBdxRole = bdx::TransferRole::kSender;
4646

@@ -64,7 +64,7 @@ - (instancetype)initWithMTROTAImageTransferHandler:(MTROTAImageTransferHandler *
6464
}
6565
@end
6666

67-
MTROTAImageTransferHandler::MTROTAImageTransferHandler(chip::System::Layer * layer)
67+
MTROTAImageTransferHandler::MTROTAImageTransferHandler(System::Layer * layer)
6868
{
6969
assertChipStackLockedByCurrentThread();
7070

@@ -91,8 +91,7 @@ - (instancetype)initWithMTROTAImageTransferHandler:(MTROTAImageTransferHandler *
9191

9292
mIsPeerNodeAKnownThreadDevice = [controller definitelyUsesThreadForDevice:mPeer.GetNodeId()];
9393

94-
uint16_t throttleInterval = chip::Platform::GetUserDefaultBDXThrottleIntervalForThreadInMSecs().value_or(kBdxThrottleDefaultIntervalInMsecs.count());
95-
mBDXThrottleIntervalForThreadDevicesInMSecs = System::Clock::Milliseconds32(throttleInterval);
94+
mBDXThrottleIntervalForThreadDevices = Platform::GetUserDefaultBDXThrottleIntervalForThread().value_or(kBdxThrottleDefaultInterval);
9695

9796
BitFlags<bdx::TransferControlFlags> flags(bdx::TransferControlFlags::kReceiverDrive);
9897

@@ -249,9 +248,8 @@ - (instancetype)initWithMTROTAImageTransferHandler:(MTROTAImageTransferHandler *
249248
{
250249
assertChipStackLockedByCurrentThread();
251250

252-
// For thread devices, we need to throttle sending the response to BlockQuery, if the query is processed, before kBdxThrottleDefaultIntervalInMsecs
253-
// has elapsed to prevent the BDX messages spamming up the network. Get the timestamp at which we start processing the BlockQuery message.
254-
251+
// For thread devices, we need to throttle sending the response to
252+
// BlockQuery, so need to track when we started handling BlockQuery.
255253
auto startBlockQueryHandlingTimestamp = System::SystemClock().GetMonotonicTimestamp();
256254

257255
auto blockSize = @(mTransfer.GetTransferBlockSize());
@@ -306,19 +304,20 @@ - (instancetype)initWithMTROTAImageTransferHandler:(MTROTAImageTransferHandler *
306304

307305
void (^completionHandler)(NSData * _Nullable data, BOOL isEOF) = nil;
308306

309-
// If the peer node is a Thread device, check how much time has elapsed since we started processing the BlockQuery.
310-
// If the time elapsed is greater than kBdxThrottleDefaultIntervalInMsecs, call the completion handler to respond with a Block right away.
311-
// If time elapsed is less than kBdxThrottleDefaultIntervalInMsecs, dispatch the completion handler to respond with a Block after kBdxThrottleDefaultIntervalInMsecs has elapsed.
312-
307+
// If the peer node is a Thread device, check how much time has elapsed since we started processing the BlockQuery,
308+
// round it up to the nearest multiple of kBdxThrottleDefaultInterval, and respond with the block at that point.
313309
if (mIsPeerNodeAKnownThreadDevice) {
314310
completionHandler = ^(NSData * _Nullable data, BOOL isEOF) {
315311
auto timeElapsed = System::SystemClock().GetMonotonicTimestamp() - startBlockQueryHandlingTimestamp;
312+
// Integer division rounds down, so dividing by mBDXThrottleIntervalForThreadDevices and then multiplying
313+
// by it again rounds down to the nearest multiple of mBDXThrottleIntervalForThreadDevices.
314+
auto remainder = timeElapsed - (timeElapsed / mBDXThrottleIntervalForThreadDevices) * mBDXThrottleIntervalForThreadDevices;
316315

317-
if (timeElapsed >= mBDXThrottleIntervalForThreadDevicesInMSecs) {
316+
if (remainder == System::Clock::Milliseconds32(0)) {
318317
respondWithBlock(data, isEOF);
319318
} else {
320-
auto timeRemaining = std::chrono::duration_cast<std::chrono::nanoseconds>(mBDXThrottleIntervalForThreadDevicesInMSecs - timeElapsed);
321-
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t) (timeRemaining.count()));
319+
auto nsRemaining = std::chrono::duration_cast<std::chrono::nanoseconds>(remainder);
320+
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, nsRemaining.count());
322321
dispatch_after(time, delegateQueue, ^{
323322
respondWithBlock(data, isEOF);
324323
});

src/platform/Darwin/UserDefaults.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@
1818

1919
#include <cstdint>
2020
#include <optional>
21+
#include <system/SystemClock.h>
2122

2223
namespace chip {
2324
namespace Platform {
2425

2526
std::optional<uint16_t> GetUserDefaultDnssdSRPTimeoutInMSecs();
2627

27-
std::optional<uint16_t> GetUserDefaultBDXThrottleIntervalForThreadInMSecs();
28+
std::optional<System::Clock::Milliseconds16> GetUserDefaultBDXThrottleIntervalForThread();
2829

2930
} // namespace Platform
3031
} // namespace chip

src/platform/Darwin/UserDefaults.mm

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@
4040
return std::nullopt;
4141
}
4242

43-
std::optional<uint16_t> GetUserDefaultBDXThrottleIntervalForThreadInMSecs()
43+
std::optional<System::Clock::Milliseconds16> GetUserDefaultBDXThrottleIntervalForThread()
4444
{
4545
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
4646
NSInteger bdxThrottleIntervalInMsecs = [defaults integerForKey:kBDXThrottleIntervalInMsecsUserDefaultKey];
4747

4848
if (bdxThrottleIntervalInMsecs > 0 && CanCastTo<uint16_t>(bdxThrottleIntervalInMsecs)) {
4949
uint16_t intervalInMsecs = static_cast<uint16_t>(bdxThrottleIntervalInMsecs);
5050
ChipLogProgress(BDX, "Got a user default value for BDX Throttle Interval for Thread devices - %d msecs", intervalInMsecs);
51-
return std::make_optional(intervalInMsecs);
51+
return std::make_optional(System::Clock::Milliseconds16(intervalInMsecs));
5252
}
5353

5454
// For now return NullOptional if value returned in bdxThrottleIntervalInMsecs is 0, since that either means the key was not found or value was zero.

0 commit comments

Comments
 (0)