Skip to content

Commit

Permalink
feat(profiling): continuous profiling from launch (#3938)
Browse files Browse the repository at this point in the history
  • Loading branch information
armcknight committed May 16, 2024
1 parent 2b9e267 commit f1d1166
Show file tree
Hide file tree
Showing 22 changed files with 404 additions and 287 deletions.
20 changes: 11 additions & 9 deletions Samples/iOS-Swift/iOS-Swift-UITests/ProfilingUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ProfilingUITests: BaseUITest {
func testProfiledAppLaunches() throws {
if #available(iOS 16, *) {
app.launchArguments.append("--io.sentry.wipe-data")
setDefaultLaunchArgs()
launchApp()

// First launch enables in-app profiling by setting traces/profiles sample rates to 1 (which is the default configuration in the sample app), but not launch profiling; assert that we did not write a config to allow the next launch to be profiled.
Expand Down Expand Up @@ -162,6 +163,15 @@ extension ProfilingUITests {
})
XCTAssert(try XCTUnwrap(sample["thread_id"] as? String) == "259") // the main thread is always ID 259
}

/**
* These cause traces to run the profiler, which can overwrite the launch profile file we need to retrieve to make assertions in the UI test.
*/
func setDefaultLaunchArgs() {
app.launchArguments.append("--disable-swizzling")
app.launchArguments.append("--disable-auto-performance-tracing")
app.launchArguments.append("--disable-uiviewcontroller-tracing")
}

/**
* Performs the various operations for the launch profiler test case:
Expand Down Expand Up @@ -216,16 +226,8 @@ extension ProfilingUITests {
if shouldDisableTracing {
app.launchArguments.append("--disable-tracing")
}
if shouldDisableSwizzling {
app.launchArguments.append("--disable-swizzling")
}
if shouldDisableAutoPerformanceTracking {
app.launchArguments.append("--disable-auto-performance-tracing")
}
if shouldDisableUIViewControllerTracing {
app.launchArguments.append("--disable-uiviewcontroller-tracing")
}

setDefaultLaunchArgs()
launchApp()

let sdkOptionsConfigurationAllowsLaunchProfiling = !(shouldDisableTracing || shouldDisableSwizzling || shouldDisableAutoPerformanceTracking || shouldDisableUIViewControllerTracing)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class ProfilingViewController: UIViewController, UITextFieldDelegate {

@IBAction func viewLaunchProfile(_ sender: Any) {
profilingUITestDataMarshalingTextField.text = "<fetching...>"
withProfile(fileName: "launchProfile") { file in
withProfile(fileName: "profile") { file in
handleContents(file: file)
}
}
Expand Down
16 changes: 10 additions & 6 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,8 @@
7DC8310A2398283C0043DD9A /* SentryCrashIntegration.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DC831082398283C0043DD9A /* SentryCrashIntegration.h */; };
7DC8310C2398283C0043DD9A /* SentryCrashIntegration.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DC831092398283C0043DD9A /* SentryCrashIntegration.m */; };
840A11122B61E27500650D02 /* SentrySamplerDecision.m in Sources */ = {isa = PBXBuildFile; fileRef = 840A11102B61E27500650D02 /* SentrySamplerDecision.m */; };
840A11132B61FE5800650D02 /* SentryAppLaunchProfilingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 840A11092B5F47F700650D02 /* SentryAppLaunchProfilingTests.m */; };
841325BC2BF4184B0029228F /* TestHub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B944FAD2469B43700A10721 /* TestHub.swift */; };
841325C52BF49EC40029228F /* SentryLaunchProfiling+Tests.h in Headers */ = {isa = PBXBuildFile; fileRef = 841325C42BF49EC40029228F /* SentryLaunchProfiling+Tests.h */; };
84281C432A578E5600EE88F2 /* SentryProfilerState.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84281C422A578E5600EE88F2 /* SentryProfilerState.mm */; };
84281C462A57905700EE88F2 /* SentrySample.h in Headers */ = {isa = PBXBuildFile; fileRef = 84281C442A57905700EE88F2 /* SentrySample.h */; };
84281C472A57905700EE88F2 /* SentrySample.m in Sources */ = {isa = PBXBuildFile; fileRef = 84281C452A57905700EE88F2 /* SentrySample.m */; };
Expand Down Expand Up @@ -681,6 +681,7 @@
848A451D2BBF9504006AAAEC /* SentryProfilerTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 848A451C2BBF9504006AAAEC /* SentryProfilerTestHelpers.m */; };
848A451E2BBF9504006AAAEC /* SentryProfilerTestHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 848A451B2BBF9504006AAAEC /* SentryProfilerTestHelpers.h */; };
849AC40029E0C1FF00889C16 /* SentryFormatterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849AC3FF29E0C1FF00889C16 /* SentryFormatterTests.swift */; };
84A305492BC7328400D84283 /* SentryAppLaunchProfilingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A305472BC72A0A00D84283 /* SentryAppLaunchProfilingTests.swift */; };
84A305572BC9EF8C00D84283 /* SentryLegacyProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 84A305552BC9EF8C00D84283 /* SentryLegacyProfiler.h */; };
84A305582BC9EF8C00D84283 /* SentryLegacyProfiler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84A305562BC9EF8C00D84283 /* SentryLegacyProfiler.mm */; };
84A5D75B29D5170700388BFA /* TimeInterval+Sentry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A5D75A29D5170700388BFA /* TimeInterval+Sentry.swift */; };
Expand Down Expand Up @@ -1644,16 +1645,15 @@
7DC27EC423997EB7006998B5 /* SentryAutoBreadcrumbTrackingIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryAutoBreadcrumbTrackingIntegration.m; sourceTree = "<group>"; };
7DC831082398283C0043DD9A /* SentryCrashIntegration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryCrashIntegration.h; path = include/SentryCrashIntegration.h; sourceTree = "<group>"; };
7DC831092398283C0043DD9A /* SentryCrashIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryCrashIntegration.m; sourceTree = "<group>"; };
840A11092B5F47F700650D02 /* SentryAppLaunchProfilingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryAppLaunchProfilingTests.m; sourceTree = "<group>"; };
840A11102B61E27500650D02 /* SentrySamplerDecision.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySamplerDecision.m; sourceTree = "<group>"; };
840A11142B62041600650D02 /* SentryLaunchProfiling+Tests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryLaunchProfiling+Tests.h"; path = "../Tests/SentryTests/SentryLaunchProfiling+Tests.h"; sourceTree = "<group>"; };
840B7EEA2BBF2ABA008B8120 /* .slather.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .slather.yml; sourceTree = "<group>"; };
840B7EEC2BBF2AFE008B8120 /* .gitattributes */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitattributes; sourceTree = "<group>"; };
840B7EED2BBF2B16008B8120 /* .pre-commit-config.yaml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = ".pre-commit-config.yaml"; sourceTree = "<group>"; };
840B7EEE2BBF2B23008B8120 /* .ruby-version */ = {isa = PBXFileReference; lastKnownFileType = text; path = ".ruby-version"; sourceTree = "<group>"; };
840B7EEF2BBF2B2B008B8120 /* .spi.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .spi.yml; sourceTree = "<group>"; };
840B7EF02BBF2B5F008B8120 /* MIGRATION.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = MIGRATION.md; sourceTree = "<group>"; };
840B7EF22BBF83DF008B8120 /* SentryProfiler+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryProfiler+Private.h"; path = "Sources/Sentry/include/SentryProfiler+Private.h"; sourceTree = SOURCE_ROOT; };
841325C42BF49EC40029228F /* SentryLaunchProfiling+Tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SentryLaunchProfiling+Tests.h"; sourceTree = "<group>"; };
8419C0C328C1889D001C8259 /* SentryLegacyProfilerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryLegacyProfilerTests.swift; sourceTree = "<group>"; };
84281C422A578E5600EE88F2 /* SentryProfilerState.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryProfilerState.mm; sourceTree = "<group>"; };
84281C442A57905700EE88F2 /* SentrySample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentrySample.h; path = ../include/SentrySample.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1721,6 +1721,7 @@
849472822971C2CD002603DE /* SentryNSProcessInfoWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryNSProcessInfoWrapperTests.swift; sourceTree = "<group>"; };
849472842971C41A002603DE /* SentryNSTimerFactoryTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryNSTimerFactoryTest.swift; sourceTree = "<group>"; };
849AC3FF29E0C1FF00889C16 /* SentryFormatterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SentryFormatterTests.swift; sourceTree = "<group>"; };
84A305472BC72A0A00D84283 /* SentryAppLaunchProfilingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryAppLaunchProfilingTests.swift; sourceTree = "<group>"; };
84A305552BC9EF8C00D84283 /* SentryLegacyProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryLegacyProfiler.h; path = ../include/SentryLegacyProfiler.h; sourceTree = "<group>"; };
84A305562BC9EF8C00D84283 /* SentryLegacyProfiler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryLegacyProfiler.mm; sourceTree = "<group>"; };
84A305592BC9FD1600D84283 /* SentryLegacyProfiler+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryLegacyProfiler+Test.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3404,7 +3405,7 @@
035E73CB27D575B3005EEB11 /* SentrySamplingProfilerTests.mm */,
035E73CD27D5790A005EEB11 /* SentryThreadMetadataCacheTests.mm */,
03F9D37B2819A65C00602916 /* SentryProfilerTests.mm */,
840A11092B5F47F700650D02 /* SentryAppLaunchProfilingTests.m */,
84A305472BC72A0A00D84283 /* SentryAppLaunchProfilingTests.swift */,
8419C0C328C1889D001C8259 /* SentryLegacyProfilerTests.swift */,
8446F5182BE172290040D57E /* SentryContinuousProfilerTests.swift */,
8431D4522BE1741E009EAEC1 /* SentryProfileTestFixture.swift */,
Expand All @@ -3426,10 +3427,10 @@
8431F00B29B284F200D8DC56 /* SentryTestUtils */ = {
isa = PBXGroup;
children = (
841325C42BF49EC40029228F /* SentryLaunchProfiling+Tests.h */,
7B4C817124D1BC2B0076ACE4 /* SentryFileManager+Test.h */,
7B944FAD2469B43700A10721 /* TestHub.swift */,
7B7A30C924B48523005A4C6E /* SentryHub+Test.h */,
840A11142B62041600650D02 /* SentryLaunchProfiling+Tests.h */,
7BD47B4C268F0B080076A663 /* ClearTestState.swift */,
7B18DE4328D9F8F6004845C6 /* TestNSNotificationCenterWrapper.swift */,
84AC61D829F7643B009EEF61 /* TestDispatchFactory.swift */,
Expand Down Expand Up @@ -4150,6 +4151,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
841325C52BF49EC40029228F /* SentryLaunchProfiling+Tests.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -4228,6 +4230,8 @@
8431EED229B27B1100D8DC56 /* PBXTargetDependency */,
);
name = SentryProfilerTests;
packageProductDependencies = (
);
productName = "Tests-iOS";
productReference = 8431EFD929B27B1100D8DC56 /* SentryProfilerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
Expand Down Expand Up @@ -4959,8 +4963,8 @@
8431EFE129B27B5300D8DC56 /* SentryThreadMetadataCacheTests.mm in Sources */,
8431EFE029B27B5300D8DC56 /* SentryBacktraceTests.mm in Sources */,
8431EFDF29B27B5300D8DC56 /* SentryThreadHandleTests.mm in Sources */,
840A11132B61FE5800650D02 /* SentryAppLaunchProfilingTests.m in Sources */,
8431EFE829B27BAD00D8DC56 /* SentrySystemWrapperTests.swift in Sources */,
84A305492BC7328400D84283 /* SentryAppLaunchProfilingTests.swift in Sources */,
8431EFE529B27BAD00D8DC56 /* SentryNSProcessInfoWrapperTests.swift in Sources */,
8431EFDE29B27B5300D8DC56 /* SentryLegacyProfilerTests.swift in Sources */,
);
Expand Down
2 changes: 2 additions & 0 deletions SentryTestUtils/ClearTestState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class TestCleanup: NSObject {
SentryLegacyProfiler.getCurrentProfiler()?.stop(for: SentryProfilerTruncationReason.normal)
SentryLegacyProfiler.resetConcurrencyTracking()
SentryContinuousProfiler.stop()
removeAppLaunchProfilingConfigFile()
sentry_stopAndDiscardLaunchProfileTracer()
#endif // os(iOS) || os(macOS) || targetEnvironment(macCatalyst)

#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst)
Expand Down
46 changes: 46 additions & 0 deletions SentryTestUtils/SentryLaunchProfiling+Tests.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#import "SentryLaunchProfiling.h"

#if SENTRY_TARGET_PROFILING_SUPPORTED

# import "SentryDefines.h"

@class SentryOptions;
@class SentrySamplerDecision;
@class SentryTracer;

NS_ASSUME_NONNULL_BEGIN

typedef struct {
BOOL shouldProfile;
SentrySamplerDecision *_Nullable tracesDecision;
SentrySamplerDecision *_Nullable profilesDecision;
} SentryLaunchProfileConfig;

SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyTracesSampleRate;
SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyProfilesSampleRate;
SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyContinuousProfiling;

SENTRY_EXTERN SentryTracer *_Nullable sentry_launchTracer;

SentryLaunchProfileConfig sentry_shouldProfileNextLaunch(SentryOptions *options);

/**
* `sentry_shouldProfileNextLaunch` cannot be exposed to Swift tests because its return type is not
* expressible in Swift. This wraps it and only returns the `BOOL shouldProfile` value in the
* struct.
*/
BOOL sentry_willProfileNextLaunch(SentryOptions *options);

/**
* Contains the logic to start a launch profile. Exposed separately from @c
* sentry_startLaunchProfile, because that function wraps everything in a @c dispatch_once , and
* that path is taken once when @c SenryProfiler.load is called at the start of the test suite, and
* can't be executed again by calling that function.
*/
void _sentry_nondeduplicated_startLaunchProfile(void);

SentryTransactionContext *sentry_context(NSNumber *tracesRate);

NS_ASSUME_NONNULL_END

#endif // SENTRY_TARGET_PROFILING_SUPPORTED
1 change: 1 addition & 0 deletions SentryTestUtils/SentryTestUtils-ObjC-BridgingHeader.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#if SENTRY_TARGET_PROFILING_SUPPORTED
# import "SentryContinuousProfiler.h"
# import "SentryLaunchProfiling.h"
# import "SentryLegacyProfiler+Test.h"
# import "SentryProfiler+Private.h"
#endif // SENTRY_TARGET_PROFILING_SUPPORTED
Expand Down

0 comments on commit f1d1166

Please sign in to comment.