Skip to content

Commit 530eccf

Browse files
anush-applehuangxuyong
authored andcommitted
Modified MTRMetrics to vend specific object rather than id type (project-chip#32425)
- MTRMetrics vends MTRMetricData which has well defined schema - Cleaned up internals of MTRMetricData - Fixed potential unbounded growth if metrics are enabled on Darwin - Removed stale metric keys that are not used and were meant to be removed in initial framework for metrics
1 parent 36b306a commit 530eccf

7 files changed

+135
-131
lines changed

src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm

+4-2
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@
122122
id<MTRDeviceControllerDelegate> strongDelegate = mDelegate;
123123
MTRDeviceController * strongController = mController;
124124
if (strongDelegate && mQueue && strongController) {
125+
126+
// Always collect the metrics to avoid unbounded growth of the stats in the collector
127+
MTRMetrics * metrics = [[MTRMetricsCollector sharedInstance] metricSnapshot:TRUE];
128+
125129
if ([strongDelegate respondsToSelector:@selector(controller:commissioningComplete:nodeID:)] ||
126130
[strongDelegate respondsToSelector:@selector(controller:commissioningComplete:nodeID:metrics:)]) {
127131
dispatch_async(mQueue, ^{
@@ -133,8 +137,6 @@
133137

134138
// If the client implements the metrics delegate, prefer that over others
135139
if ([strongDelegate respondsToSelector:@selector(controller:commissioningComplete:nodeID:metrics:)]) {
136-
// Create a snapshot and clear for next operation
137-
MTRMetrics * metrics = [[MTRMetricsCollector sharedInstance] metricSnapshot:TRUE];
138140
[strongDelegate controller:strongController commissioningComplete:nsError nodeID:nodeID metrics:metrics];
139141
} else {
140142
[strongDelegate controller:strongController commissioningComplete:nsError nodeID:nodeID];

src/darwin/Framework/CHIP/MTRMetrics.h

+28-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,31 @@
2020

2121
NS_ASSUME_NONNULL_BEGIN
2222

23+
/**
24+
* Representation of metric data corresponding to a metric event.
25+
*/
26+
MTR_NEWLY_AVAILABLE
27+
@interface MTRMetricData : NSObject
28+
29+
/**
30+
* Value for the metric data. The value may be nil depending on the event emitted.
31+
*/
32+
@property (nonatomic, nullable, readonly, copy) NSNumber * value;
33+
34+
/**
35+
* Error code for the metric data. This value when valid, holds the error code value
36+
* of the operation associated with the event.
37+
*/
38+
@property (nonatomic, nullable, readonly, copy) NSNumber * errorCode;
39+
40+
/**
41+
* Duration of event associated with the metric. This value may be nil depending on
42+
* the event emitted.
43+
*/
44+
@property (nonatomic, nullable, readonly, copy) NSNumber * durationMicroseconds;
45+
46+
@end
47+
2348
/**
2449
* A representation of a collection of metrics data for an operation.
2550
*/
@@ -35,13 +60,13 @@ MTR_NEWLY_AVAILABLE
3560
@property (nonatomic, readonly, copy) NSArray<NSString *> * allKeys;
3661

3762
/**
38-
* @brief Returns metric object corresponding to the metric identified by its key
63+
* @brief Returns metric data corresponding to the metric identified by its key.
3964
*
4065
* @param [in] key Name of the metric
4166
*
42-
* @return An object containing the metric data, nil if key is invalid
67+
* @return An object containing the metric data, nil if key is invalid.
4368
*/
44-
- (nullable id)valueForKey:(NSString *)key;
69+
- (nullable MTRMetricData *)metricDataForKey:(NSString *)key;
4570

4671
@end
4772

src/darwin/Framework/CHIP/MTRMetrics.mm

+4-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include <Matter/MTRMetrics.h>
2222

2323
@implementation MTRMetrics {
24-
NSMutableDictionary<NSString *, id> * _metricsData;
24+
NSMutableDictionary<NSString *, MTRMetricData *> * _metricsData;
2525
}
2626

2727
- (instancetype)init
@@ -42,8 +42,7 @@ - (instancetype)initWithCapacity:(NSUInteger)numItems
4242
{
4343
return [_metricsData allKeys];
4444
}
45-
46-
- (nullable id)valueForKey:(NSString *)key
45+
- (nullable MTRMetricData *)metricDataForKey:(NSString *)key
4746
{
4847
if (!key) {
4948
MTR_LOG_ERROR("Cannot get metrics value for nil key");
@@ -53,7 +52,7 @@ - (nullable id)valueForKey:(NSString *)key
5352
return _metricsData[key];
5453
}
5554

56-
- (void)setValue:(id _Nullable)value forKey:(NSString *)key
55+
- (void)setMetricData:(MTRMetricData * _Nullable)value forKey:(NSString *)key
5756
{
5857
if (!key) {
5958
MTR_LOG_ERROR("Cannot set metrics value for nil key");
@@ -63,7 +62,7 @@ - (void)setValue:(id _Nullable)value forKey:(NSString *)key
6362
[_metricsData setValue:value forKey:key];
6463
}
6564

66-
- (void)removeValueForKey:(NSString *)key
65+
- (void)removeMetricDataForKey:(NSString *)key
6766
{
6867
if (!key) {
6968
MTR_LOG_ERROR("Cannot remove metrics value for nil key");

src/darwin/Framework/CHIP/MTRMetricsCollector.mm

+60-54
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#import "MTRMetricsCollector.h"
1919
#import "MTRLogging_Internal.h"
2020
#include "MTRMetrics_Internal.h"
21+
#include <MTRMetrics.h>
2122
#import <MTRUnfairLock.h>
2223
#include <platform/Darwin/Tracing.h>
2324
#include <system/SystemClock.h>
@@ -26,13 +27,17 @@
2627

2728
using MetricEvent = chip::Tracing::MetricEvent;
2829

29-
static NSString * kMTRMetricDataValueKey = @"value";
30-
static NSString * kMTRMetricDataTimepointKey = @"time_point";
31-
static NSString * kMTRMetricDataDurationKey = @"duration_us";
32-
33-
@implementation MTRMetricsData {
30+
@implementation MTRMetricData {
3431
chip::System::Clock::Microseconds64 _timePoint;
35-
chip::System::Clock::Microseconds64 _duration;
32+
MetricEvent::Type _type;
33+
}
34+
35+
- (instancetype)init
36+
{
37+
// Default is to create data for instant event type.
38+
// The key can be anything since it is not really used in this context.
39+
MetricEvent event(MetricEvent::Type::kInstantEvent, "");
40+
return [self initWithMetricEvent:event];
3641
}
3742

3843
- (instancetype)initWithMetricEvent:(const MetricEvent &)event
@@ -41,60 +46,50 @@ - (instancetype)initWithMetricEvent:(const MetricEvent &)event
4146
return nil;
4247
}
4348

49+
_type = event.type();
50+
51+
using EventType = MetricEvent::Type;
52+
switch (_type) {
53+
// Capture timepoint for begin and end to calculate duration
54+
case EventType::kBeginEvent:
55+
case EventType::kEndEvent:
56+
_timePoint = chip::System::SystemClock().GetMonotonicMicroseconds64();
57+
break;
58+
case EventType::kInstantEvent:
59+
_timePoint = chip::System::Clock::Microseconds64(0);
60+
break;
61+
}
62+
4463
using ValueType = MetricEvent::Value::Type;
4564
switch (event.ValueType()) {
4665
case ValueType::kInt32:
4766
_value = [NSNumber numberWithInteger:event.ValueInt32()];
4867
break;
4968
case ValueType::kUInt32:
50-
_value = [NSNumber numberWithInteger:event.ValueUInt32()];
69+
_value = [NSNumber numberWithUnsignedInteger:event.ValueUInt32()];
5170
break;
5271
case ValueType::kChipErrorCode:
53-
_value = [NSNumber numberWithInteger:event.ValueErrorCode()];
72+
_errorCode = [NSNumber numberWithUnsignedInteger:event.ValueErrorCode()];
5473
break;
5574
case ValueType::kUndefined:
56-
default:
57-
_value = nil;
75+
break;
5876
}
59-
60-
_timePoint = chip::System::SystemClock().GetMonotonicMicroseconds64();
61-
_duration = chip::System::Clock::Microseconds64(0);
6277
return self;
6378
}
6479

65-
- (void)setDurationFromMetricData:(MTRMetricsData *)fromData
66-
{
67-
_duration = _timePoint - fromData->_timePoint;
68-
}
69-
70-
- (NSNumber *)timePointMicroseconds
80+
- (void)setDurationFromMetricDataAndClearCounters:(MTRMetricData *)fromData
7181
{
72-
return [NSNumber numberWithUnsignedLongLong:_timePoint.count()];
73-
}
82+
auto duration = _timePoint - fromData->_timePoint;
83+
_durationMicroseconds = [NSNumber numberWithUnsignedLongLong:duration.count()];
7484

75-
- (NSNumber *)durationMicroseconds
76-
{
77-
return [NSNumber numberWithUnsignedLongLong:_duration.count()];
85+
// Clear timepoints to minimize history
86+
_timePoint = fromData->_timePoint = chip::System::Clock::Microseconds64(0);
7887
}
7988

8089
- (NSString *)description
8190
{
82-
return [NSString stringWithFormat:@"MTRMetricsData: Value = %@, TimePoint = %@, Duration = %@ us", self.value, self.timePointMicroseconds, self.durationMicroseconds];
83-
}
84-
85-
- (NSDictionary *)toDictionary
86-
{
87-
NSMutableDictionary * dictRepresentation = [NSMutableDictionary dictionary];
88-
if (self.value) {
89-
[dictRepresentation setValue:self.value forKey:kMTRMetricDataValueKey];
90-
}
91-
if (auto tmPt = self.timePointMicroseconds) {
92-
[dictRepresentation setValue:tmPt forKey:kMTRMetricDataTimepointKey];
93-
}
94-
if (auto duration = self.durationMicroseconds) {
95-
[dictRepresentation setValue:duration forKey:kMTRMetricDataDurationKey];
96-
}
97-
return dictRepresentation;
91+
return [NSString stringWithFormat:@"<MTRMetricData>: Type %d, Value = %@, Error Code = %@, Duration = %@ us",
92+
static_cast<int>(_type), self.value, self.errorCode, self.durationMicroseconds];
9893
}
9994

10095
@end
@@ -123,8 +118,9 @@ void ShutdownMetricsCollection()
123118

124119
@implementation MTRMetricsCollector {
125120
os_unfair_lock _lock;
126-
NSMutableDictionary<NSString *, MTRMetricsData *> * _metricsDataCollection;
121+
NSMutableDictionary<NSString *, MTRMetricData *> * _metricsDataCollection;
127122
chip::Tracing::signposts::DarwinTracingBackend _tracingBackend;
123+
BOOL _tracingBackendRegistered;
128124
}
129125

130126
+ (instancetype)sharedInstance
@@ -152,32 +148,43 @@ - (instancetype)init
152148
}
153149
_lock = OS_UNFAIR_LOCK_INIT;
154150
_metricsDataCollection = [NSMutableDictionary dictionary];
151+
_tracingBackendRegistered = FALSE;
155152
return self;
156153
}
157154

158155
- (void)registerTracingBackend
159156
{
160157
std::lock_guard lock(_lock);
161-
chip::Tracing::Register(_tracingBackend);
162-
MTR_LOG_INFO("Registered tracing backend with the registry");
158+
159+
// Register only once
160+
if (!_tracingBackendRegistered) {
161+
chip::Tracing::Register(_tracingBackend);
162+
MTR_LOG_INFO("Registered tracing backend with the registry");
163+
_tracingBackendRegistered = TRUE;
164+
}
163165
}
164166

165167
- (void)unregisterTracingBackend
166168
{
167169
std::lock_guard lock(_lock);
168-
chip::Tracing::Unregister(_tracingBackend);
169-
MTR_LOG_INFO("Unregistered tracing backend with the registry");
170+
171+
// Unregister only if registered before
172+
if (_tracingBackendRegistered) {
173+
chip::Tracing::Unregister(_tracingBackend);
174+
MTR_LOG_INFO("Unregistered tracing backend with the registry");
175+
_tracingBackendRegistered = FALSE;
176+
}
170177
}
171178

172179
static inline NSString * suffixNameForMetricType(MetricEvent::Type type)
173180
{
174181
switch (type) {
175182
case MetricEvent::Type::kBeginEvent:
176-
return @"-begin";
183+
return @"_begin";
177184
case MetricEvent::Type::kEndEvent:
178-
return @"-end";
185+
return @"_end";
179186
case MetricEvent::Type::kInstantEvent:
180-
return @"-instant";
187+
return @"_instant";
181188
}
182189
}
183190

@@ -211,14 +218,14 @@ - (void)handleMetricEvent:(MetricEvent)event
211218

212219
// Create the new metric key based event type
213220
auto metricsKey = [NSString stringWithFormat:@"%s%@", event.key(), suffixNameForMetric(event)];
214-
MTRMetricsData * data = [[MTRMetricsData alloc] initWithMetricEvent:event];
221+
MTRMetricData * data = [[MTRMetricData alloc] initWithMetricEvent:event];
215222

216223
// If End event, compute its duration using the Begin event
217224
if (event.type() == MetricEvent::Type::kEndEvent) {
218225
auto metricsBeginKey = [NSString stringWithFormat:@"%s%@", event.key(), suffixNameForMetricType(MetricEvent::Type::kBeginEvent)];
219-
MTRMetricsData * beginMetric = _metricsDataCollection[metricsBeginKey];
226+
MTRMetricData * beginMetric = _metricsDataCollection[metricsBeginKey];
220227
if (beginMetric) {
221-
[data setDurationFromMetricData:beginMetric];
228+
[data setDurationFromMetricDataAndClearCounters:beginMetric];
222229
} else {
223230
// Unbalanced end
224231
MTR_LOG_ERROR("Unable to find Begin event corresponding to Metric Event: %s", event.key());
@@ -230,7 +237,7 @@ - (void)handleMetricEvent:(MetricEvent)event
230237
// If the event is a begin or end event, implicitly emit a corresponding instant event
231238
if (event.type() == MetricEvent::Type::kBeginEvent || event.type() == MetricEvent::Type::kEndEvent) {
232239
MetricEvent instantEvent(MetricEvent::Type::kInstantEvent, event.key());
233-
data = [[MTRMetricsData alloc] initWithMetricEvent:instantEvent];
240+
data = [[MTRMetricData alloc] initWithMetricEvent:instantEvent];
234241
metricsKey = [NSString stringWithFormat:@"%s%@", event.key(), suffixNameForMetric(instantEvent)];
235242
[_metricsDataCollection setValue:data forKey:metricsKey];
236243
}
@@ -240,10 +247,9 @@ - (MTRMetrics *)metricSnapshot:(BOOL)resetCollection
240247
{
241248
std::lock_guard lock(_lock);
242249

243-
// Copy the MTRMetrics as NSDictionary
244250
MTRMetrics * metrics = [[MTRMetrics alloc] initWithCapacity:[_metricsDataCollection count]];
245251
for (NSString * key in _metricsDataCollection) {
246-
[metrics setValue:[_metricsDataCollection[key] toDictionary] forKey:key];
252+
[metrics setMetricData:_metricsDataCollection[key] forKey:key];
247253
}
248254

249255
// Clear curent stats, if specified

src/darwin/Framework/CHIP/MTRMetrics_Internal.h

+2-21
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,13 @@
1919

2020
NS_ASSUME_NONNULL_BEGIN
2121

22-
/**
23-
* A representation of a metric data for an operation.
24-
*/
25-
@interface MTRMetricsData : NSObject
26-
27-
// Value for the metric. This can be null if the metric is just a fire event with no value
28-
@property (nonatomic, nullable, readonly, copy) NSNumber * value;
29-
30-
// Relative time point at which the metric was emitted. This may be null.
31-
@property (nonatomic, nullable, readonly, copy) NSNumber * timePointMicroseconds;
32-
33-
// During for the event. This may be null.
34-
@property (nonatomic, nullable, readonly, copy) NSNumber * durationMicroseconds;
35-
36-
// Convert contents to a dictionary
37-
- (NSDictionary *)toDictionary;
38-
39-
@end
40-
4122
@interface MTRMetrics ()
4223

4324
- (instancetype)initWithCapacity:(NSUInteger)numItems;
4425

45-
- (void)setValue:(id _Nullable)value forKey:(NSString *)key;
26+
- (void)setMetricData:(MTRMetricData * _Nullable)value forKey:(NSString *)key;
4627

47-
- (void)removeValueForKey:(NSString *)key;
28+
- (void)removeMetricDataForKey:(NSString *)key;
4829

4930
@end
5031

0 commit comments

Comments
 (0)