Skip to content

Commit 25737cb

Browse files
authored
perf: gather profiler metrics gathering on a low-pri queue (#2956)
1 parent 7e8d5fd commit 25737cb

17 files changed

+240
-48
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- Improved performance serializing profiling data (#2863)
1717
- Possible crash in Core Data tracking (#2865)
1818
- Ensure the current GPU frame rate is always reported for concurrent transaction profiling metrics (#2929)
19+
- Move profiler metric collection to a background queue (#2956)
1920

2021
## 8.5.0
2122

Sentry.xcodeproj/project.pbxproj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,12 @@
639639
84A8891C28DBD28900C51DFD /* SentryDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 84A8891A28DBD28900C51DFD /* SentryDevice.h */; };
640640
84A8891D28DBD28900C51DFD /* SentryDevice.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84A8891B28DBD28900C51DFD /* SentryDevice.mm */; };
641641
84A8892128DBD8D600C51DFD /* SentryDeviceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84A8892028DBD8D600C51DFD /* SentryDeviceTests.mm */; };
642+
84AC61D229F7541E009EEF61 /* SentryDispatchSourceWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 84AC61D029F7541E009EEF61 /* SentryDispatchSourceWrapper.h */; };
643+
84AC61D329F7541E009EEF61 /* SentryDispatchSourceWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 84AC61D129F7541E009EEF61 /* SentryDispatchSourceWrapper.m */; };
644+
84AC61D629F75A98009EEF61 /* SentryDispatchFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 84AC61D429F75A98009EEF61 /* SentryDispatchFactory.h */; };
645+
84AC61D729F75A98009EEF61 /* SentryDispatchFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 84AC61D529F75A98009EEF61 /* SentryDispatchFactory.m */; };
646+
84AC61D929F7643B009EEF61 /* TestDispatchFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AC61D829F7643B009EEF61 /* TestDispatchFactory.swift */; };
647+
84AC61DB29F7654A009EEF61 /* TestDispatchSourceWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AC61DA29F7654A009EEF61 /* TestDispatchSourceWrapper.swift */; };
642648
84AF45A629A7FFA500FBB177 /* SentryTracerConcurrency.h in Headers */ = {isa = PBXBuildFile; fileRef = 84AF45A429A7FFA500FBB177 /* SentryTracerConcurrency.h */; };
643649
84AF45A729A7FFA500FBB177 /* SentryTracerConcurrency.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84AF45A529A7FFA500FBB177 /* SentryTracerConcurrency.mm */; };
644650
84B7FA3529B285FC00AD93B1 /* Sentry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63AA759B1EB8AEF500D153DE /* Sentry.framework */; };
@@ -1559,6 +1565,12 @@
15591565
84A8891A28DBD28900C51DFD /* SentryDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryDevice.h; path = include/SentryDevice.h; sourceTree = "<group>"; };
15601566
84A8891B28DBD28900C51DFD /* SentryDevice.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryDevice.mm; sourceTree = "<group>"; };
15611567
84A8892028DBD8D600C51DFD /* SentryDeviceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryDeviceTests.mm; sourceTree = "<group>"; };
1568+
84AC61D029F7541E009EEF61 /* SentryDispatchSourceWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryDispatchSourceWrapper.h; path = include/SentryDispatchSourceWrapper.h; sourceTree = "<group>"; };
1569+
84AC61D129F7541E009EEF61 /* SentryDispatchSourceWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryDispatchSourceWrapper.m; sourceTree = "<group>"; };
1570+
84AC61D429F75A98009EEF61 /* SentryDispatchFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryDispatchFactory.h; path = include/SentryDispatchFactory.h; sourceTree = "<group>"; };
1571+
84AC61D529F75A98009EEF61 /* SentryDispatchFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryDispatchFactory.m; sourceTree = "<group>"; };
1572+
84AC61D829F7643B009EEF61 /* TestDispatchFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDispatchFactory.swift; sourceTree = "<group>"; };
1573+
84AC61DA29F7654A009EEF61 /* TestDispatchSourceWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDispatchSourceWrapper.swift; sourceTree = "<group>"; };
15621574
84AF45A429A7FFA500FBB177 /* SentryTracerConcurrency.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryTracerConcurrency.h; path = include/SentryTracerConcurrency.h; sourceTree = "<group>"; };
15631575
84AF45A529A7FFA500FBB177 /* SentryTracerConcurrency.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryTracerConcurrency.mm; sourceTree = "<group>"; };
15641576
84B7FA3B29B2866200AD93B1 /* SentryTestUtils-ObjC-BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryTestUtils-ObjC-BridgingHeader.h"; sourceTree = "<group>"; };
@@ -1841,6 +1853,10 @@
18411853
638DC99F1EBC6B6400A66E41 /* SentryRequestOperation.m */,
18421854
7BDB03B6251364F800BAE198 /* SentryDispatchQueueWrapper.h */,
18431855
7BDB03BA2513652900BAE198 /* SentryDispatchQueueWrapper.m */,
1856+
84AC61D029F7541E009EEF61 /* SentryDispatchSourceWrapper.h */,
1857+
84AC61D429F75A98009EEF61 /* SentryDispatchFactory.h */,
1858+
84AC61D529F75A98009EEF61 /* SentryDispatchFactory.m */,
1859+
84AC61D129F7541E009EEF61 /* SentryDispatchSourceWrapper.m */,
18441860
0AAE202028ED9BCC00D0CD80 /* SentryReachability.h */,
18451861
0AAE201D28ED9B9400D0CD80 /* SentryReachability.m */,
18461862
);
@@ -3112,6 +3128,8 @@
31123128
isa = PBXGroup;
31133129
children = (
31143130
7BD47B4C268F0B080076A663 /* ClearTestState.swift */,
3131+
84AC61D829F7643B009EEF61 /* TestDispatchFactory.swift */,
3132+
84AC61DA29F7654A009EEF61 /* TestDispatchSourceWrapper.swift */,
31153133
84A5D75A29D5170700388BFA /* TimeInterval+Sentry.swift */,
31163134
7B30B68126527C55006B2752 /* TestDisplayLinkWrapper.swift */,
31173135
8E25C97425F8511A00DC215B /* TestRandom.swift */,
@@ -3370,6 +3388,7 @@
33703388
7B82D54524E2A05500EE670F /* SentryId.h in Headers */,
33713389
D867063D27C3BC2400048851 /* SentryCoreDataTrackingIntegration.h in Headers */,
33723390
0A2D8D5D289815EB008720F6 /* SentryBaseIntegration.h in Headers */,
3391+
84AC61D629F75A98009EEF61 /* SentryDispatchFactory.h in Headers */,
33733392
63FE716520DA4C1100CDBAE8 /* SentryCrashMemory.h in Headers */,
33743393
63FE713F20DA4C1100CDBAE8 /* SentryCrashStackCursor_SelfThread.h in Headers */,
33753394
639FCFA41EBC809A00778193 /* SentryStacktrace.h in Headers */,
@@ -3495,6 +3514,7 @@
34953514
632331F9240506DF008D91D6 /* SentryScope+Private.h in Headers */,
34963515
D8603DD8284F894C000E1227 /* SentryBaggage.h in Headers */,
34973516
03F84D2127DD414C008FE43F /* SentrySamplingProfiler.hpp in Headers */,
3517+
84AC61D229F7541E009EEF61 /* SentryDispatchSourceWrapper.h in Headers */,
34983518
63FE712B20DA4C1100CDBAE8 /* SentryCrashStackCursor.h in Headers */,
34993519
D8C67E9C28000E24007E326E /* SentryScreenshot.h in Headers */,
35003520
7BA61CBF247CEA8100C130A8 /* SentryFormatter.h in Headers */,
@@ -3905,6 +3925,7 @@
39053925
63FE712920DA4C1000CDBAE8 /* SentryCrashCPU_arm.c in Sources */,
39063926
03F84D3427DD4191008FE43F /* SentryThreadMetadataCache.cpp in Sources */,
39073927
7B88F30024BC5A7D00ADF90A /* SentrySdkInfo.m in Sources */,
3928+
84AC61D729F75A98009EEF61 /* SentryDispatchFactory.m in Sources */,
39083929
15360CD62432832400112302 /* SentryAutoSessionTrackingIntegration.m in Sources */,
39093930
7B63459F280EBA7200CFA05A /* SentryUIEventTracker.m in Sources */,
39103931
7BF9EF782722B35D00B5BBEF /* SentrySubClassFinder.m in Sources */,
@@ -4021,6 +4042,7 @@
40214042
7BB65501253DC1B500887E87 /* SentryUserFeedback.m in Sources */,
40224043
7D5C441A237C2E1F00DAB0A3 /* SentrySDK.m in Sources */,
40234044
7D65260E237F649E00113EA2 /* SentryScope.m in Sources */,
4045+
84AC61D329F7541E009EEF61 /* SentryDispatchSourceWrapper.m in Sources */,
40244046
63FE712D20DA4C1100CDBAE8 /* SentryCrashJSONCodecObjC.m in Sources */,
40254047
7BBD18932449BEDD00427C76 /* SentryDefaultRateLimits.m in Sources */,
40264048
7BD729982463E93500EA3610 /* SentryDateUtil.m in Sources */,
@@ -4353,6 +4375,7 @@
43534375
84B7FA4229B28CDE00AD93B1 /* TestCurrentDateProvider.swift in Sources */,
43544376
84B7FA3F29B28BAD00AD93B1 /* TestTransport.swift in Sources */,
43554377
84A5D75B29D5170700388BFA /* TimeInterval+Sentry.swift in Sources */,
4378+
84AC61D929F7643B009EEF61 /* TestDispatchFactory.swift in Sources */,
43564379
8431F01929B2852D00D8DC56 /* Invocation.swift in Sources */,
43574380
84B7FA4629B2935F00AD93B1 /* ClearTestState.swift in Sources */,
43584381
8431F01529B2851500D8DC56 /* TestSentryNSTimerWrapper.swift in Sources */,
@@ -4364,6 +4387,7 @@
43644387
8431F01B29B2852D00D8DC56 /* Logger.swift in Sources */,
43654388
8431F01829B2852D00D8DC56 /* TypeMapping.swift in Sources */,
43664389
84B7FA4529B2926900AD93B1 /* TestDisplayLinkWrapper.swift in Sources */,
4390+
84AC61DB29F7654A009EEF61 /* TestDispatchSourceWrapper.swift in Sources */,
43674391
8431F01729B2851500D8DC56 /* TestSentrySystemWrapper.swift in Sources */,
43684392
84B7FA4129B28CD200AD93B1 /* TestSentryDispatchQueueWrapper.swift in Sources */,
43694393
84B7FA3E29B28ADD00AD93B1 /* TestClient.swift in Sources */,

SentryTestUtils/SentryTestUtils-ObjC-BridgingHeader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
#import "SentryCurrentDateProvider.h"
99
#import "SentryDefines.h"
1010
#import "SentryDependencyContainer.h"
11+
#import "SentryDispatchFactory.h"
1112
#import "SentryDispatchQueueWrapper.h"
13+
#import "SentryDispatchSourceWrapper.h"
1214
#import "SentryDisplayLinkWrapper.h"
1315
#import "SentryEnvelope.h"
1416
#import "SentryFileManager.h"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Foundation
2+
import Sentry
3+
4+
public class TestDispatchFactory: SentryDispatchFactory {
5+
public var vendedSourceHandler: ((TestDispatchSourceWrapper) -> Void)?
6+
public var vendedQueueHandler: ((TestSentryDispatchQueueWrapper) -> Void)?
7+
8+
public override func queue(withName name: UnsafePointer<CChar>, attributes: __OS_dispatch_queue_attr) -> SentryDispatchQueueWrapper {
9+
let queue = TestSentryDispatchQueueWrapper(name: name, attributes: attributes)
10+
vendedQueueHandler?(queue)
11+
return queue
12+
}
13+
14+
public override func source(withInterval interval: UInt64, leeway: UInt64, queueName: UnsafePointer<CChar>, attributes: __OS_dispatch_queue_attr, eventHandler: @escaping () -> Void) -> SentryDispatchSourceWrapper {
15+
let source = TestDispatchSourceWrapper(eventHandler: eventHandler)
16+
vendedSourceHandler?(source)
17+
return source
18+
}
19+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Foundation
2+
import Sentry
3+
4+
public class TestDispatchSourceWrapper: SentryDispatchSourceWrapper {
5+
public struct Override {
6+
public var eventHandler: (() -> Void)?
7+
}
8+
public var overrides = Override()
9+
10+
public init(eventHandler: @escaping () -> Void) {
11+
self.overrides.eventHandler = eventHandler
12+
super.init()
13+
}
14+
15+
public override func cancel() {
16+
// no-op
17+
}
18+
19+
public func fire() {
20+
self.overrides.eventHandler?()
21+
}
22+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#import "SentryDispatchFactory.h"
2+
#import "SentryDispatchQueueWrapper.h"
3+
#import "SentryDispatchSourceWrapper.h"
4+
5+
@implementation SentryDispatchFactory
6+
7+
- (SentryDispatchQueueWrapper *)queueWithName:(const char *)name
8+
attributes:(dispatch_queue_attr_t)attributes
9+
{
10+
return [[SentryDispatchQueueWrapper alloc] initWithName:name attributes:attributes];
11+
}
12+
13+
- (SentryDispatchSourceWrapper *)sourceWithInterval:(uint64_t)interval
14+
leeway:(uint64_t)leeway
15+
queueName:(const char *)queueName
16+
attributes:(dispatch_queue_attr_t)attributes
17+
eventHandler:(void (^)(void))eventHandler
18+
{
19+
return [[SentryDispatchSourceWrapper alloc]
20+
initTimerWithInterval:interval
21+
leeway:leeway
22+
queue:[self queueWithName:queueName attributes:attributes]
23+
eventHandler:eventHandler];
24+
}
25+
26+
@end

Sources/Sentry/SentryDispatchQueueWrapper.m

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,7 @@
33

44
NS_ASSUME_NONNULL_BEGIN
55

6-
@implementation SentryDispatchQueueWrapper {
7-
// Don't use a normal property because on RN a user got a warning "Property with 'retain (or
8-
// strong)' attribute must be of object type". A dispatch queue is since iOS 6.0 an NSObject so
9-
// it should work with strong, but nevertheless, we use an instance variable to fix this
10-
// warning.
11-
dispatch_queue_t queue;
12-
}
6+
@implementation SentryDispatchQueueWrapper
137

148
- (instancetype)init
159
{
@@ -24,14 +18,14 @@ - (instancetype)init
2418
- (instancetype)initWithName:(const char *)name attributes:(dispatch_queue_attr_t)attributes;
2519
{
2620
if (self = [super init]) {
27-
queue = dispatch_queue_create(name, attributes);
21+
_queue = dispatch_queue_create(name, attributes);
2822
}
2923
return self;
3024
}
3125

3226
- (void)dispatchAsyncWithBlock:(void (^)(void))block
3327
{
34-
dispatch_async(queue, ^{
28+
dispatch_async(_queue, ^{
3529
@autoreleasepool {
3630
block();
3731
}
@@ -60,7 +54,7 @@ - (void)dispatchAfter:(NSTimeInterval)interval block:(dispatch_block_t)block
6054
{
6155
dispatch_time_t delta = (int64_t)(interval * NSEC_PER_SEC);
6256
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, delta);
63-
dispatch_after(when, queue, ^{
57+
dispatch_after(when, _queue, ^{
6458
@autoreleasepool {
6559
block();
6660
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#import "SentryDispatchSourceWrapper.h"
2+
#import "SentryDispatchQueueWrapper.h"
3+
4+
@implementation SentryDispatchSourceWrapper {
5+
SentryDispatchQueueWrapper *_queueWrapper;
6+
dispatch_source_t _source;
7+
}
8+
9+
- (instancetype)initTimerWithInterval:(uint64_t)interval
10+
leeway:(uint64_t)leeway
11+
queue:(SentryDispatchQueueWrapper *)queueWrapper
12+
eventHandler:(void (^)(void))eventHandler
13+
{
14+
if (self = [super init]) {
15+
_queueWrapper = queueWrapper;
16+
_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queueWrapper.queue);
17+
dispatch_source_set_event_handler(_source, eventHandler);
18+
dispatch_source_set_timer(
19+
_source, dispatch_time(DISPATCH_TIME_NOW, interval), interval, leeway);
20+
dispatch_resume(_source);
21+
}
22+
return self;
23+
}
24+
25+
- (void)cancel
26+
{
27+
dispatch_cancel(_source);
28+
}
29+
30+
@end

Sources/Sentry/SentryMetricProfiler.mm

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#if SENTRY_TARGET_PROFILING_SUPPORTED
44

55
# import "SentryCurrentDate.h"
6+
# import "SentryDispatchFactory.h"
7+
# import "SentryDispatchQueueWrapper.h"
8+
# import "SentryDispatchSourceWrapper.h"
69
# import "SentryEvent+Private.h"
710
# import "SentryFormatter.h"
811
# import "SentryLog.h"
@@ -23,19 +26,18 @@ @interface SentryMetricReading : NSObject
2326
@implementation SentryMetricReading
2427
@end
2528

26-
/**
27-
* Currently set to 10 Hz as we don't anticipate much utility out of a higher resolution when
28-
* sampling CPU usage and memory footprint, and we want to minimize the overhead of making the
29-
* necessary system calls to gather that information.
30-
*/
31-
static const NSTimeInterval kSentryMetricProfilerTimeseriesInterval = 0.1;
32-
3329
NSString *const kSentryMetricProfilerSerializationKeyMemoryFootprint = @"memory_footprint";
3430
NSString *const kSentryMetricProfilerSerializationKeyCPUUsageFormat = @"cpu_usage_%d";
3531

3632
NSString *const kSentryMetricProfilerSerializationUnitBytes = @"byte";
3733
NSString *const kSentryMetricProfilerSerializationUnitPercentage = @"percent";
3834

35+
// Currently set to 10 Hz as we don't anticipate much utility out of a higher resolution when
36+
// sampling CPU usage and memory footprint, and we want to minimize the overhead of making the
37+
// necessary system calls to gather that information. This is currently roughly 10% of the
38+
// backtrace profiler's resolution.
39+
static uint64_t frequencyHz = 10;
40+
3941
namespace {
4042
/**
4143
* @return a dictionary containing all the metric values recorded during the transaction, or @c nil
@@ -74,11 +76,11 @@ @implementation SentryMetricReading
7476
} // namespace
7577

7678
@implementation SentryMetricProfiler {
77-
NSTimer *_timer;
79+
SentryDispatchSourceWrapper *_dispatchSource;
7880

7981
SentryNSProcessInfoWrapper *_processInfoWrapper;
8082
SentrySystemWrapper *_systemWrapper;
81-
SentryNSTimerWrapper *_timerWrapper;
83+
SentryDispatchFactory *_dispatchFactory;
8284

8385
/// arrays of readings keyed on NSNumbers representing the core number for the set of readings
8486
NSMutableDictionary<NSNumber *, NSMutableArray<SentryMetricReading *> *> *_cpuUsage;
@@ -88,7 +90,7 @@ @implementation SentryMetricProfiler {
8890

8991
- (instancetype)initWithProcessInfoWrapper:(SentryNSProcessInfoWrapper *)processInfoWrapper
9092
systemWrapper:(SentrySystemWrapper *)systemWrapper
91-
timerWrapper:(SentryNSTimerWrapper *)timerWrapper
93+
dispatchFactory:(nonnull SentryDispatchFactory *)dispatchFactory
9294
{
9395
if (self = [super init]) {
9496
_cpuUsage =
@@ -102,7 +104,7 @@ - (instancetype)initWithProcessInfoWrapper:(SentryNSProcessInfoWrapper *)process
102104

103105
_systemWrapper = systemWrapper;
104106
_processInfoWrapper = processInfoWrapper;
105-
_timerWrapper = timerWrapper;
107+
_dispatchFactory = dispatchFactory;
106108

107109
_memoryFootprint = [NSMutableArray<SentryMetricReading *> array];
108110
}
@@ -123,24 +125,28 @@ - (void)start
123125

124126
- (void)stop
125127
{
126-
[_timer invalidate];
128+
[_dispatchSource cancel];
127129
}
128130

129131
- (NSMutableDictionary<NSString *, id> *)serializeForTransaction:(SentryTransaction *)transaction
130132
{
131-
NSMutableDictionary<NSString *, id> *dict;
133+
NSArray<SentryMetricReading *> *memoryFootprint;
134+
NSDictionary<NSNumber *, NSArray<SentryMetricReading *> *> *cpuUsage;
132135
@synchronized(self) {
133-
dict = [NSMutableDictionary<NSString *, id> dictionary];
136+
memoryFootprint = [NSArray<SentryMetricReading *> arrayWithArray:_memoryFootprint];
137+
cpuUsage = [NSDictionary<NSNumber *, NSArray<SentryMetricReading *> *>
138+
dictionaryWithDictionary:_cpuUsage];
134139
}
135140

136-
if (_memoryFootprint.count > 0) {
141+
const auto dict = [NSMutableDictionary<NSString *, id> dictionary];
142+
if (memoryFootprint.count > 0) {
137143
dict[kSentryMetricProfilerSerializationKeyMemoryFootprint]
138144
= serializeValuesWithNormalizedTime(
139-
_memoryFootprint, kSentryMetricProfilerSerializationUnitBytes, transaction);
145+
memoryFootprint, kSentryMetricProfilerSerializationUnitBytes, transaction);
140146
}
141147

142-
[_cpuUsage enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull core,
143-
NSMutableArray<SentryMetricReading *> *_Nonnull readings, BOOL *_Nonnull stop) {
148+
[cpuUsage enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull core,
149+
NSArray<SentryMetricReading *> *_Nonnull readings, BOOL *_Nonnull stop) {
144150
if (readings.count > 0) {
145151
dict[[NSString stringWithFormat:kSentryMetricProfilerSerializationKeyCPUUsageFormat,
146152
core.intValue]]
@@ -157,12 +163,18 @@ - (void)stop
157163
- (void)registerSampler
158164
{
159165
__weak auto weakSelf = self;
160-
_timer = [_timerWrapper scheduledTimerWithTimeInterval:kSentryMetricProfilerTimeseriesInterval
161-
repeats:YES
162-
block:^(NSTimer *_Nonnull timer) {
163-
[weakSelf recordCPUPercentagePerCore];
164-
[weakSelf recordMemoryFootprint];
165-
}];
166+
const auto intervalNs = (uint64_t)1e9 / frequencyHz;
167+
const auto leewayNs = intervalNs / 2;
168+
_dispatchSource =
169+
[_dispatchFactory sourceWithInterval:intervalNs
170+
leeway:leewayNs
171+
queueName:"io.sentry.metric-profiler"
172+
attributes:dispatch_queue_attr_make_with_qos_class(
173+
DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_UTILITY, 0)
174+
eventHandler:^{
175+
[weakSelf recordCPUPercentagePerCore];
176+
[weakSelf recordMemoryFootprint];
177+
}];
166178
}
167179

168180
- (void)recordMemoryFootprint

0 commit comments

Comments
 (0)