@@ -213,6 +213,7 @@ @implementation MTRDeviceClusterData {
213
213
214
214
static NSString * const sDataVersionKey = @" dataVersion" ;
215
215
static NSString * const sAttributesKey = @" attributes" ;
216
+ static NSString * const sLastInitialSubscribeLatencyKey = @" lastInitialSubscribeLatency" ;
216
217
217
218
- (void )storeValue : (MTRDeviceDataValueDictionary _Nullable)value forAttribute : (NSNumber *)attribute
218
219
{
@@ -414,6 +415,10 @@ @implementation MTRDevice {
414
415
// 2. OnResubscriptionNeeded is called
415
416
// 3. Subscription reset (including when getSessionForNode fails)
416
417
MTRAsyncWorkCompletionBlock _subscriptionPoolWorkCompletionBlock;
418
+
419
+ // Tracking of initial subscribe latency. When _initialSubscribeStart is
420
+ // nil, we are not tracking the latency.
421
+ NSDate * _Nullable _initialSubscribeStart;
417
422
}
418
423
419
424
- (instancetype )initWithNodeID : (NSNumber *)nodeID controller : (MTRDeviceController *)controller
@@ -705,6 +710,7 @@ - (void)setDelegate:(id<MTRDeviceDelegate>)delegate queue:(dispatch_queue_t)queu
705
710
}
706
711
707
712
if (setUpSubscription) {
713
+ _initialSubscribeStart = [NSDate now ];
708
714
if ([self _deviceUsesThread ]) {
709
715
[self _scheduleSubscriptionPoolWork: ^{
710
716
std::lock_guard lock (self->_lock );
@@ -954,6 +960,18 @@ - (void)_handleSubscriptionEstablished
954
960
// No need to monitor connectivity after subscription establishment
955
961
[self _stopConnectivityMonitoring ];
956
962
963
+ auto initialSubscribeStart = _initialSubscribeStart;
964
+ // We no longer need to track subscribe latency for this device.
965
+ _initialSubscribeStart = nil ;
966
+
967
+ if (initialSubscribeStart != nil ) {
968
+ // We want time interval from initialSubscribeStart to now, not the other
969
+ // way around.
970
+ NSTimeInterval subscriptionLatency = -[initialSubscribeStart timeIntervalSinceNow ];
971
+ _estimatedSubscriptionLatency = @(subscriptionLatency);
972
+ [self _storePersistedDeviceData ];
973
+ }
974
+
957
975
os_unfair_lock_unlock (&self->_lock );
958
976
959
977
os_unfair_lock_lock (&self->_timeSyncLock );
@@ -2884,6 +2902,50 @@ - (void)setPersistedClusterData:(NSDictionary<MTRClusterPath *, MTRDeviceCluster
2884
2902
}
2885
2903
}
2886
2904
2905
+ - (void )_setLastInitialSubscribeLatency : (id )latency
2906
+ {
2907
+ os_unfair_lock_assert_owner (&self->_lock );
2908
+
2909
+ if (![latency isKindOfClass: NSNumber .class ]) {
2910
+ // Unexpected value of some sort; just ignore it.
2911
+ return ;
2912
+ }
2913
+
2914
+ _estimatedSubscriptionLatency = latency;
2915
+ }
2916
+
2917
+ - (void )setPersistedDeviceData : (NSDictionary <NSString *, id> *)data
2918
+ {
2919
+ MTR_LOG_INFO (" %@ setPersistedDeviceData: %@" , self, data);
2920
+
2921
+ std::lock_guard lock (_lock);
2922
+
2923
+ // For now the only data we care about is our initial subscribe latency.
2924
+ id initialSubscribeLatency = data[sLastInitialSubscribeLatencyKey ];
2925
+ if (initialSubscribeLatency != nil ) {
2926
+ [self _setLastInitialSubscribeLatency: initialSubscribeLatency];
2927
+ }
2928
+ }
2929
+
2930
+ - (void )_storePersistedDeviceData
2931
+ {
2932
+ os_unfair_lock_assert_owner (&self->_lock );
2933
+
2934
+ auto datastore = _deviceController.controllerDataStore ;
2935
+ if (datastore == nil ) {
2936
+ // No way to store.
2937
+ return ;
2938
+ }
2939
+
2940
+ // For now the only data we have is our initial subscribe latency.
2941
+ NSMutableDictionary <NSString *, id > * data = [NSMutableDictionary dictionary ];
2942
+ if (_estimatedSubscriptionLatency != nil ) {
2943
+ data[sLastInitialSubscribeLatencyKey ] = _estimatedSubscriptionLatency;
2944
+ }
2945
+
2946
+ [datastore storeDeviceData: [data copy ] forNodeID: self .nodeID];
2947
+ }
2948
+
2887
2949
- (BOOL )deviceCachePrimed
2888
2950
{
2889
2951
std::lock_guard lock (_lock);
0 commit comments