Skip to content

Commit 9acdca2

Browse files
authored
ref: extract other implementations from SentryProfiler (#3132)
1 parent 6c31077 commit 9acdca2

File tree

10 files changed

+255
-226
lines changed

10 files changed

+255
-226
lines changed

Sentry.xcodeproj/project.pbxproj

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,9 @@
601601
7DC83100239826280043DD9A /* SentryIntegrationProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DC830FF239826280043DD9A /* SentryIntegrationProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
602602
7DC8310A2398283C0043DD9A /* SentryCrashIntegration.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DC831082398283C0043DD9A /* SentryCrashIntegration.h */; };
603603
7DC8310C2398283C0043DD9A /* SentryCrashIntegration.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DC831092398283C0043DD9A /* SentryCrashIntegration.m */; };
604+
84281C432A578E5600EE88F2 /* SentryProfilerState.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84281C422A578E5600EE88F2 /* SentryProfilerState.mm */; };
605+
84281C462A57905700EE88F2 /* SentrySample.h in Headers */ = {isa = PBXBuildFile; fileRef = 84281C442A57905700EE88F2 /* SentrySample.h */; };
606+
84281C472A57905700EE88F2 /* SentrySample.m in Sources */ = {isa = PBXBuildFile; fileRef = 84281C452A57905700EE88F2 /* SentrySample.m */; };
604607
8431EE5B29ADB8EA00D8DC56 /* SentryTimeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8431EE5A29ADB8EA00D8DC56 /* SentryTimeTests.m */; };
605608
8431EFD129B27B1100D8DC56 /* Sentry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63AA759B1EB8AEF500D153DE /* Sentry.framework */; settings = {ATTRIBUTES = (Required, ); }; };
606609
8431EFD329B27B1100D8DC56 /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 630C01951EC341D600C52CEF /* Resources */; };
@@ -1521,6 +1524,9 @@
15211524
7DC831082398283C0043DD9A /* SentryCrashIntegration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryCrashIntegration.h; path = include/SentryCrashIntegration.h; sourceTree = "<group>"; };
15221525
7DC831092398283C0043DD9A /* SentryCrashIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryCrashIntegration.m; sourceTree = "<group>"; };
15231526
8419C0C328C1889D001C8259 /* SentryProfilerSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryProfilerSwiftTests.swift; sourceTree = "<group>"; };
1527+
84281C422A578E5600EE88F2 /* SentryProfilerState.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryProfilerState.mm; sourceTree = "<group>"; };
1528+
84281C442A57905700EE88F2 /* SentrySample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentrySample.h; path = ../include/SentrySample.h; sourceTree = "<group>"; };
1529+
84281C452A57905700EE88F2 /* SentrySample.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySample.m; sourceTree = "<group>"; };
15241530
8431EE5A29ADB8EA00D8DC56 /* SentryTimeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryTimeTests.m; sourceTree = "<group>"; };
15251531
8431EFD929B27B1100D8DC56 /* SentryProfilerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SentryProfilerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
15261532
8431EFDA29B27B1200D8DC56 /* SentryTests copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "SentryTests copy-Info.plist"; path = "/Users/andrewmcknight/Code/organization/getsentry/repos/public/sentry-cocoa/SentryTests copy-Info.plist"; sourceTree = "<absolute>"; };
@@ -1556,7 +1562,6 @@
15561562
844EDC74294144DB00C86F34 /* SentrySystemWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentrySystemWrapper.h; path = include/SentrySystemWrapper.h; sourceTree = "<group>"; };
15571563
844EDC75294144DB00C86F34 /* SentrySystemWrapper.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentrySystemWrapper.mm; sourceTree = "<group>"; };
15581564
844EDC7829415AB300C86F34 /* TestSentrySystemWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSentrySystemWrapper.swift; sourceTree = "<group>"; };
1559-
844EDC7B2942843400C86F34 /* SentryProfiler+SwiftTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryProfiler+SwiftTest.h"; path = "Tests/SentryTests/Helper/SentryProfiler+SwiftTest.h"; sourceTree = SOURCE_ROOT; };
15601565
844EDCE32947DC3100C86F34 /* SentryNSTimerFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryNSTimerFactory.h; path = include/SentryNSTimerFactory.h; sourceTree = "<group>"; };
15611566
844EDCE42947DC3100C86F34 /* SentryNSTimerFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSTimerFactory.m; sourceTree = "<group>"; };
15621567
844EDCE72947DCD700C86F34 /* TestSentryNSTimerFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSentryNSTimerFactory.swift; sourceTree = "<group>"; };
@@ -3086,37 +3091,40 @@
30863091
8405A517279906EF001B38A1 /* Profiling */ = {
30873092
isa = PBXGroup;
30883093
children = (
3089-
84354E0F29BF944900CDBB8B /* SentryProfileTimeseries.h */,
3090-
84354E1029BF944900CDBB8B /* SentryProfileTimeseries.mm */,
30913094
03F84D1327DD414C008FE43F /* SentryAsyncSafeLogging.h */,
3092-
03F84D1227DD414C008FE43F /* SentryBacktrace.hpp */,
30933095
03F84D3127DD4191008FE43F /* SentryBacktrace.cpp */,
3096+
03F84D1227DD414C008FE43F /* SentryBacktrace.hpp */,
30943097
03F84D1827DD414C008FE43F /* SentryCompiler.h */,
30953098
03F84D1C27DD414C008FE43F /* SentryCPU.h */,
3096-
03F84D1B27DD414C008FE43F /* SentryMachLogging.hpp */,
30973099
03F84D2C27DD4191008FE43F /* SentryMachLogging.cpp */,
3098-
03F84D1127DD414C008FE43F /* SentryProfiler.h */,
3100+
03F84D1B27DD414C008FE43F /* SentryMachLogging.hpp */,
30993101
844EDD6B2949387000C86F34 /* SentryMetricProfiler.h */,
31003102
8454CF8B293EAF9A006AC140 /* SentryMetricProfiler.mm */,
3101-
0354A22A2A134D9C003C3A04 /* SentryProfilerState.h */,
3102-
84A888FC28D9B11700C51DFD /* SentryProfiler+Test.h */,
3103+
03F84D1127DD414C008FE43F /* SentryProfiler.h */,
31033104
03F84D2B27DD4191008FE43F /* SentryProfiler.mm */,
3105+
84A888FC28D9B11700C51DFD /* SentryProfiler+Test.h */,
3106+
0354A22A2A134D9C003C3A04 /* SentryProfilerState.h */,
3107+
84281C422A578E5600EE88F2 /* SentryProfilerState.mm */,
3108+
0356A56E288B4612008BF593 /* SentryProfilesSampler.h */,
3109+
0356A56F288B4612008BF593 /* SentryProfilesSampler.m */,
3110+
84354E0F29BF944900CDBB8B /* SentryProfileTimeseries.h */,
3111+
84354E1029BF944900CDBB8B /* SentryProfileTimeseries.mm */,
31043112
03BCC38D27E2A377003232C7 /* SentryProfilingConditionals.h */,
31053113
03F84D2927DD416B008FE43F /* SentryProfilingLogging.hpp */,
31063114
03F84D2F27DD4191008FE43F /* SentryProfilingLogging.mm */,
3107-
03F84D1527DD414C008FE43F /* SentrySamplingProfiler.hpp */,
3115+
84281C442A57905700EE88F2 /* SentrySample.h */,
3116+
84281C452A57905700EE88F2 /* SentrySample.m */,
31083117
03F84D3027DD4191008FE43F /* SentrySamplingProfiler.cpp */,
3109-
03F84D1727DD414C008FE43F /* SentryThreadHandle.hpp */,
3110-
03F84D2E27DD4191008FE43F /* SentryThreadHandle.cpp */,
3111-
03F84D1A27DD414C008FE43F /* SentryThreadMetadataCache.hpp */,
3112-
03F84D2D27DD4191008FE43F /* SentryThreadMetadataCache.cpp */,
3118+
03F84D1527DD414C008FE43F /* SentrySamplingProfiler.hpp */,
31133119
03F84D1427DD414C008FE43F /* SentryStackBounds.hpp */,
31143120
03F84D1627DD414C008FE43F /* SentryStackFrame.hpp */,
3121+
03F84D2E27DD4191008FE43F /* SentryThreadHandle.cpp */,
3122+
03F84D1727DD414C008FE43F /* SentryThreadHandle.hpp */,
3123+
03F84D2D27DD4191008FE43F /* SentryThreadMetadataCache.cpp */,
3124+
03F84D1A27DD414C008FE43F /* SentryThreadMetadataCache.hpp */,
31153125
03F84D1927DD414C008FE43F /* SentryThreadState.hpp */,
31163126
03BCC38927E1BF49003232C7 /* SentryTime.h */,
31173127
03BCC38B27E1C01A003232C7 /* SentryTime.mm */,
3118-
0356A56E288B4612008BF593 /* SentryProfilesSampler.h */,
3119-
0356A56F288B4612008BF593 /* SentryProfilesSampler.m */,
31203128
);
31213129
path = Profiling;
31223130
sourceTree = "<group>";
@@ -3564,6 +3572,7 @@
35643572
D8603DD8284F894C000E1227 /* SentryBaggage.h in Headers */,
35653573
03F84D2127DD414C008FE43F /* SentrySamplingProfiler.hpp in Headers */,
35663574
84AC61D229F7541E009EEF61 /* SentryDispatchSourceWrapper.h in Headers */,
3575+
84281C462A57905700EE88F2 /* SentrySample.h in Headers */,
35673576
63FE712B20DA4C1100CDBAE8 /* SentryCrashStackCursor.h in Headers */,
35683577
D8C67E9C28000E24007E326E /* SentryScreenshot.h in Headers */,
35693578
7BA61CBF247CEA8100C130A8 /* SentryFormatter.h in Headers */,
@@ -4091,6 +4100,7 @@
40914100
7BB65501253DC1B500887E87 /* SentryUserFeedback.m in Sources */,
40924101
7D5C441A237C2E1F00DAB0A3 /* SentrySDK.m in Sources */,
40934102
7D65260E237F649E00113EA2 /* SentryScope.m in Sources */,
4103+
84281C472A57905700EE88F2 /* SentrySample.m in Sources */,
40944104
84AC61D329F7541E009EEF61 /* SentryDispatchSourceWrapper.m in Sources */,
40954105
63FE712D20DA4C1100CDBAE8 /* SentryCrashJSONCodecObjC.m in Sources */,
40964106
7BBD18932449BEDD00427C76 /* SentryDefaultRateLimits.m in Sources */,
@@ -4131,6 +4141,7 @@
41314141
7BC9A20428F4166D001E7C4C /* SentryMeasurementValue.m in Sources */,
41324142
D859696B27BECD8F0036A46E /* SentryCoreDataTrackingIntegration.m in Sources */,
41334143
7BD86EC7264A641D005439DB /* SentrySysctl.m in Sources */,
4144+
84281C432A578E5600EE88F2 /* SentryProfilerState.mm in Sources */,
41344145
D859697327BECDD20036A46E /* SentryCoreDataSwizzling.m in Sources */,
41354146
639889BD1EDED18400EA7442 /* SentrySwizzle.m in Sources */,
41364147
D8ABB0BC29264275005D1E24 /* Sentry.swift in Sources */,
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#import "SentryProfilerState.h"
2+
#if SENTRY_TARGET_PROFILING_SUPPORTED
3+
# import "SentryBacktrace.hpp"
4+
# import "SentryFormatter.h"
5+
# import "SentryProfileTimeseries.h"
6+
# import "SentrySample.h"
7+
# import <mutex>
8+
9+
# if defined(DEBUG)
10+
# include <execinfo.h>
11+
# endif
12+
13+
using namespace sentry::profiling;
14+
15+
NSString *
16+
parseBacktraceSymbolsFunctionName(const char *symbol)
17+
{
18+
static NSRegularExpression *regex = nil;
19+
static dispatch_once_t onceToken;
20+
dispatch_once(&onceToken, ^{
21+
regex = [NSRegularExpression
22+
regularExpressionWithPattern:@"\\d+\\s+\\S+\\s+0[xX][0-9a-fA-F]+\\s+(.+)\\s+\\+\\s+\\d+"
23+
options:0
24+
error:nil];
25+
});
26+
const auto symbolNSStr = [NSString stringWithUTF8String:symbol];
27+
const auto match = [regex firstMatchInString:symbolNSStr
28+
options:0
29+
range:NSMakeRange(0, [symbolNSStr length])];
30+
if (match == nil) {
31+
return symbolNSStr;
32+
}
33+
return [symbolNSStr substringWithRange:[match rangeAtIndex:1]];
34+
}
35+
36+
@implementation SentryProfilerMutableState
37+
38+
- (instancetype)init
39+
{
40+
if (self = [super init]) {
41+
_samples = [NSMutableArray<SentrySample *> array];
42+
_stacks = [NSMutableArray<NSArray<NSNumber *> *> array];
43+
_frames = [NSMutableArray<NSDictionary<NSString *, id> *> array];
44+
_threadMetadata = [NSMutableDictionary<NSString *, NSMutableDictionary *> dictionary];
45+
_queueMetadata = [NSMutableDictionary<NSString *, NSDictionary *> dictionary];
46+
_frameIndexLookup = [NSMutableDictionary<NSString *, NSNumber *> dictionary];
47+
_stackIndexLookup = [NSMutableDictionary<NSString *, NSNumber *> dictionary];
48+
}
49+
return self;
50+
}
51+
52+
@end
53+
54+
@implementation SentryProfilerState {
55+
SentryProfilerMutableState *_mutableState;
56+
std::mutex _lock;
57+
}
58+
59+
- (instancetype)init
60+
{
61+
if (self = [super init]) {
62+
_mutableState = [[SentryProfilerMutableState alloc] init];
63+
}
64+
return self;
65+
}
66+
67+
- (void)mutate:(void (^)(SentryProfilerMutableState *))block
68+
{
69+
NSParameterAssert(block);
70+
std::lock_guard<std::mutex> l(_lock);
71+
block(_mutableState);
72+
}
73+
74+
- (void)appendBacktrace:(const Backtrace &)backtrace
75+
{
76+
[self mutate:^(SentryProfilerMutableState *state) {
77+
const auto threadID = sentry_stringForUInt64(backtrace.threadMetadata.threadID);
78+
79+
NSString *queueAddress = nil;
80+
if (backtrace.queueMetadata.address != 0) {
81+
queueAddress = sentry_formatHexAddressUInt64(backtrace.queueMetadata.address);
82+
}
83+
NSMutableDictionary<NSString *, id> *metadata = state.threadMetadata[threadID];
84+
if (metadata == nil) {
85+
metadata = [NSMutableDictionary<NSString *, id> dictionary];
86+
state.threadMetadata[threadID] = metadata;
87+
}
88+
if (!backtrace.threadMetadata.name.empty() && metadata[@"name"] == nil) {
89+
metadata[@"name"] =
90+
[NSString stringWithUTF8String:backtrace.threadMetadata.name.c_str()];
91+
}
92+
if (backtrace.threadMetadata.priority != -1 && metadata[@"priority"] == nil) {
93+
metadata[@"priority"] = @(backtrace.threadMetadata.priority);
94+
}
95+
if (queueAddress != nil && state.queueMetadata[queueAddress] == nil
96+
&& backtrace.queueMetadata.label != nullptr) {
97+
NSString *const labelNSStr =
98+
[NSString stringWithUTF8String:backtrace.queueMetadata.label->c_str()];
99+
// -[NSString stringWithUTF8String:] can return `nil` for malformed string data
100+
if (labelNSStr != nil) {
101+
state.queueMetadata[queueAddress] = @ { @"label" : labelNSStr };
102+
}
103+
}
104+
# if defined(DEBUG)
105+
const auto symbols
106+
= backtrace_symbols(reinterpret_cast<void *const *>(backtrace.addresses.data()),
107+
static_cast<int>(backtrace.addresses.size()));
108+
# endif
109+
110+
const auto stack = [NSMutableArray<NSNumber *> array];
111+
for (std::vector<uintptr_t>::size_type backtraceAddressIdx = 0;
112+
backtraceAddressIdx < backtrace.addresses.size(); backtraceAddressIdx++) {
113+
const auto instructionAddress
114+
= sentry_formatHexAddressUInt64(backtrace.addresses[backtraceAddressIdx]);
115+
116+
const auto frameIndex = state.frameIndexLookup[instructionAddress];
117+
if (frameIndex == nil) {
118+
const auto frame = [NSMutableDictionary<NSString *, id> dictionary];
119+
frame[@"instruction_addr"] = instructionAddress;
120+
# if defined(DEBUG)
121+
frame[@"function"]
122+
= parseBacktraceSymbolsFunctionName(symbols[backtraceAddressIdx]);
123+
# endif
124+
const auto newFrameIndex = @(state.frames.count);
125+
[stack addObject:newFrameIndex];
126+
state.frameIndexLookup[instructionAddress] = newFrameIndex;
127+
[state.frames addObject:frame];
128+
} else {
129+
[stack addObject:frameIndex];
130+
}
131+
}
132+
133+
const auto sample = [[SentrySample alloc] init];
134+
sample.absoluteTimestamp = backtrace.absoluteTimestamp;
135+
sample.threadID = backtrace.threadMetadata.threadID;
136+
if (queueAddress != nil) {
137+
sample.queueAddress = queueAddress;
138+
}
139+
140+
const auto stackKey = [stack componentsJoinedByString:@"|"];
141+
const auto stackIndex = state.stackIndexLookup[stackKey];
142+
if (stackIndex) {
143+
sample.stackIndex = stackIndex;
144+
} else {
145+
const auto nextStackIndex = @(state.stacks.count);
146+
sample.stackIndex = nextStackIndex;
147+
state.stackIndexLookup[stackKey] = nextStackIndex;
148+
[state.stacks addObject:stack];
149+
}
150+
151+
[state.samples addObject:sample];
152+
}];
153+
}
154+
155+
- (NSDictionary<NSString *, id> *)copyProfilingData
156+
{
157+
std::lock_guard<std::mutex> l(_lock);
158+
159+
NSMutableArray<SentrySample *> *const samples = [_mutableState.samples copy];
160+
NSMutableArray<NSArray<NSNumber *> *> *const stacks = [_mutableState.stacks copy];
161+
NSMutableArray<NSDictionary<NSString *, id> *> *const frames = [_mutableState.frames copy];
162+
NSMutableDictionary<NSString *, NSDictionary *> *const queueMetadata =
163+
[_mutableState.queueMetadata copy];
164+
165+
// thread metadata contains a mutable substructure, so it's not enough to perform a copy of
166+
// the top-level dictionary, we need to go deeper to copy the mutable subdictionaries
167+
const auto threadMetadata = [NSMutableDictionary<NSString *, NSDictionary *> dictionary];
168+
[_mutableState.threadMetadata enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key,
169+
NSDictionary *_Nonnull obj, BOOL *_Nonnull stop) { threadMetadata[key] = [obj copy]; }];
170+
171+
return @{
172+
@"profile" : @ {
173+
@"samples" : samples,
174+
@"stacks" : stacks,
175+
@"frames" : frames,
176+
@"thread_metadata" : threadMetadata,
177+
@"queue_metadata" : queueMetadata
178+
}
179+
};
180+
}
181+
182+
@end
183+
184+
#endif // SENTRY_TARGET_PROFILING_SUPPORTED
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#import "SentrySample.h"
2+
3+
@implementation SentrySample
4+
@end

Sources/Sentry/SentryProfileTimeseries.mm

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# import "SentryEvent+Private.h"
66
# import "SentryInternalDefines.h"
77
# import "SentryLog.h"
8+
# import "SentrySample.h"
89
# import "SentryTransaction.h"
910

1011
/**
@@ -83,7 +84,4 @@
8384
return [samples objectsAtIndexes:indices];
8485
}
8586

86-
@implementation SentrySample
87-
@end
88-
8987
#endif // SENTRY_TARGET_PROFILING_SUPPORTED

0 commit comments

Comments
 (0)