Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(profiling): new launch profiling option #4981

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
fec6a18
fix(profiling): reevaluate session sample rate on every fg, not just …
armcknight Mar 18, 2025
2b33ecf
use float instead of NSNumber; never needs nil
armcknight Mar 18, 2025
6291921
fix tvos build
armcknight Mar 19, 2025
ccf28c8
test(profiling): fix some tests failing due to bad switch in logic
armcknight Mar 18, 2025
c3c3cfd
organization
armcknight Mar 18, 2025
918a8f0
add app start profiling option
armcknight Mar 14, 2025
df7156f
pr feedback
armcknight Mar 17, 2025
7bcfe6d
fix sample app usage
armcknight Mar 18, 2025
a681551
fix objc sample, fix after merges from upstream
armcknight Mar 18, 2025
7acb607
wip testing all possible configuration options for launch profiling
armcknight Mar 19, 2025
6075785
more wip
armcknight Mar 19, 2025
b486df6
fix remaining combinations of tests
armcknight Mar 19, 2025
679ded9
clean up
armcknight Mar 19, 2025
369ef21
Format code
getsentry-bot Mar 19, 2025
8a63d20
implement some new tests, add writing config file, reading it, and ma…
armcknight Mar 20, 2025
55fd64a
more tests
armcknight Mar 20, 2025
2489f1e
go back to explicit lists of valid/invalid configs
armcknight Mar 20, 2025
3de68ab
finish up remainig tests
armcknight Mar 20, 2025
38d0a02
Format code
getsentry-bot Mar 21, 2025
a65fcde
fix bad merge conflict resolution
armcknight Mar 21, 2025
5e6ad9f
track fg to reevaluate from session tracker
armcknight Mar 21, 2025
b4e1070
Format code
getsentry-bot Mar 21, 2025
d3283e3
fix macos build and analyzer warning; only compile SentryProfileOptio…
armcknight Mar 21, 2025
fe43118
Format code
getsentry-bot Mar 21, 2025
2482631
Merge branch 'armcknight/profiling/new-continuous-apis/reevaluate-sam…
armcknight Mar 21, 2025
5652013
Merge branch 'armcknight/profiling/new-continuous-apis/fix-tests' int…
armcknight Mar 21, 2025
9f7a1f4
fix a couple build issues from bad merge i guess
armcknight Mar 31, 2025
3dd8992
Merge branch 'main' into armcknight/git-chain/profiling/new-continuou…
armcknight Mar 31, 2025
e587372
Merge branch 'armcknight/git-chain/profiling/new-continuous-apis/0-to…
armcknight Mar 31, 2025
b6a464f
Merge branch 'armcknight/git-chain/profiling/new-continuous-apis/0-to…
armcknight Mar 31, 2025
aec2899
fix bad merge conflict resolution
armcknight Mar 31, 2025
b8d0e7d
ref(profiling): public methods for new API (#4995)
armcknight Apr 1, 2025
d21e64c
ref(profiling): function renames (#5007)
armcknight Apr 1, 2025
6f65428
fix(profiling): add ui tests for new launch profiling modes (#5008)
armcknight Apr 1, 2025
2588a27
Revert "NOMAIN: temporarily disable warnings as errors until we figur…
armcknight Apr 1, 2025
4fd672c
trying to work around building with tooling versions both before and …
armcknight Apr 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

## Unreleased

### Features

- New continuous profiling configuration API (#4952)

> [!Important]
> With the addition of the new profiling configuation API, the previous profiling API are deprecated and will be removed in the next major version of the SDK:
>
> - `SentryOptions.enableProfiling`
> - `SentryOptions.isProfilingEnabled`
> - `SentryOptions.profilesSampleRate`
> - `SentryOptions.profilesSampler`
> - `SentryOptions.enableLaunchProfiling`
>
> Additionally, note that the behavior of `SentrySDK.startProfiler()` will change once the above API are removed, as follows: before adding the new configuration API (`SentryProfileOptions`), `SentrySDK.startProfiler()` would unconditionally start a continuous profile if both `SentryOptions.profilesSampleRate` and `SentryOptions.profilesSampler` were `nil`, or no-op if either was non-`nil` (meaning the SDK would operate under original, transaction-based, profiling model). In the next major version, `SentryOptions.profilesSampleRate` and `SentryOptions.profilesSampler` will be removed, and `SentrySDK.startProfile()` will become a no-op unless you configure `SentryProfileOptions.sessionSampleRate` to a value greater than zero (which is it's default). If you already have calls to `SentrySDK.startProfiler()` in your code, ensure you properly configure `SentryProfileOptions` via `SentryOptions.configureProfiling` to avoid losing profiling coverage.
> Additionally, note that the behavior of `SentrySDK.startProfiler()` will change once the above APIs are removed, as follows: before adding the new configuration API (`SentryProfileOptions`), `SentrySDK.startProfiler()` would unconditionally start a continuous profile if both `SentryOptions.profilesSampleRate` and `SentryOptions.profilesSampler` were `nil`, or no-op if either was non-`nil` (meaning the SDK would operate under original, transaction-based, profiling model). In the next major version, `SentryOptions.profilesSampleRate` and `SentryOptions.profilesSampler` will be removed, and `SentrySDK.startProfile()` will become a no-op unless you configure `SentryProfileOptions.sessionSampleRate` to a value greater than zero (which is its default). If you already have calls to `SentrySDK.startProfiler()` in your code, ensure you properly configure `SentryProfileOptions` via `SentryOptions.configureProfiling` to avoid losing profiling coverage.

### Fixes

- Continuous profile stop requests are cancelled by subsequent timely calls to start (#4993)
Expand Down Expand Up @@ -39,7 +55,6 @@
### Features

- Add extension for `Data` to track file I/O operations with Sentry (#4862)
- New continuous profiling API (#4952)
- Send fatal app hang session updates (#4921) only when enabling the option `enableAppHangTrackingV2`.
- Add experimental flag `options.sessionReplay.enableExperimentalViewRenderer` to enable up to 5x times more performance in Session Replay (#4940)

Expand Down
21 changes: 11 additions & 10 deletions Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,17 @@ - (BOOL)application:(UIApplication *)application
}

if ([args containsObject:@"--io.sentry.profile-options-v2"]) {
options.profiling.lifecycle =
[args containsObject:@"--io.sentry.profile-lifecycle-manual"]
? SentryProfileLifecycleManual
: SentryProfileLifecycleTrace;

options.profiling.sessionSampleRate = 1.f;
if (env[@"--io.sentry.profile-session-sample-rate"] != nil) {
options.profiling.sessionSampleRate =
[env[@"--io.sentry.profile-session-sample-rate"] floatValue];
}
options.configureProfiling = ^(SentryProfileOptions *_Nonnull profiling) {
profiling.lifecycle = [args containsObject:@"--io.sentry.profile-lifecycle-manual"]
? SentryProfileLifecycleManual
: SentryProfileLifecycleTrace;

profiling.sessionSampleRate = 1.f;
if (env[@"--io.sentry.profile-session-sample-rate"] != nil) {
profiling.sessionSampleRate =
[env[@"--io.sentry.profile-session-sample-rate"] floatValue];
}
};
} else {
NSNumber *profilesSampleRate = @1;
if ([args containsObject:@"--io.sentry.enableContinuousProfiling"]) {
Expand Down
49 changes: 46 additions & 3 deletions Samples/iOS-Swift/iOS-Swift-UITests/ProfilingUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ProfilingUITests: BaseUITest {
try launchAndConfigureSubsequentLaunches(terminatePriorSession: true, shouldProfileThisLaunch: true)
}

func testAppLaunchesWithContinuousProfiler() throws {
func testAppLaunchesWithContinuousProfilerV1() throws {
guard #available(iOS 16, *) else {
throw XCTSkip("Only run for latest iOS version we test; we've had issues with prior versions in SauceLabs")
}
Expand All @@ -37,6 +37,30 @@ class ProfilingUITests: BaseUITest {
try launchAndConfigureSubsequentLaunches(terminatePriorSession: true, shouldProfileThisLaunch: true, continuousProfiling: true)
}

func testAppLaunchesWithContinuousProfilerV2TraceLifecycle() throws {
guard #available(iOS 16, *) else {
throw XCTSkip("Only run for latest iOS version we test; we've had issues with prior versions in SauceLabs")
}

// by default, launch profiling is not enabled
try launchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, continuousProfiling: true, v2TraceLifecycle: true)

// after configuring for launch profiling, check the marker file exists, and that the profile happens
try launchAndConfigureSubsequentLaunches(terminatePriorSession: true, shouldProfileThisLaunch: true, continuousProfiling: true, v2TraceLifecycle: true)
}

func testAppLaunchesWithContinuousProfilerV2ManualLifeCycle() throws {
guard #available(iOS 16, *) else {
throw XCTSkip("Only run for latest iOS version we test; we've had issues with prior versions in SauceLabs")
}

// by default, launch profiling is not enabled
try launchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, continuousProfiling: true, v2ManualLifecycle: true)

// after configuring for launch profiling, check the marker file exists, and that the profile happens
try launchAndConfigureSubsequentLaunches(terminatePriorSession: true, shouldProfileThisLaunch: true, continuousProfiling: true, v2ManualLifecycle: true)
}

/**
* We had a bug where we forgot to install the frames tracker into the profiler, so weren't sending any GPU frame information with profiles. Since it's not possible to enforce such installation via the compiler, we test for the results we expect here, by starting a transaction, triggering an ANR which will cause degraded frame rendering, stop the transaction, and inspect the profile payload.
*/
Expand Down Expand Up @@ -133,7 +157,9 @@ extension ProfilingUITests {
func launchAndConfigureSubsequentLaunches(
terminatePriorSession: Bool = false,
shouldProfileThisLaunch: Bool,
continuousProfiling: Bool = false
continuousProfiling: Bool = false,
v2TraceLifecycle: Bool = false,
v2ManualLifecycle: Bool = false
) throws {
if terminatePriorSession {
app.terminate()
Expand All @@ -155,8 +181,23 @@ extension ProfilingUITests {
// override full chunk completion before stoppage introduced in https://github.com/getsentry/sentry-cocoa/pull/4214
"--io.sentry.continuous-profiler-immediate-stop"
])

if continuousProfiling {
app.launchArguments.append("--io.sentry.enableContinuousProfiling")
if v2TraceLifecycle {
app.launchArguments.append(contentsOf: [
"--io.sentry.profile-options-v2",
"--io.sentry.profile-app-starts-v2"
])
app.launchEnvironment["--io.sentry.profile-session-sample-rate"] = "1"
} else if v2ManualLifecycle {
app.launchArguments.append(contentsOf: [
"--io.sentry.profile-options-v2",
"--io.sentry.profile-app-starts-v2",
"--io.sentry.profile-lifecycle-manual"
])
app.launchEnvironment["--io.sentry.profile-session-sample-rate"] = "1"
}
}

launchApp()
Expand All @@ -168,7 +209,9 @@ extension ProfilingUITests {
}

if continuousProfiling {
stopContinuousProfiler()
if !v2TraceLifecycle {
stopContinuousProfiler()
}
retrieveFirstProfileChunkData()
} else {
retrieveLastProfileData()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ class ProfilingViewController: UIViewController, UITextFieldDelegate {
}

@IBAction func startContinuousProfiler(_ sender: Any) {
SentrySDK.startProfileSession()
SentrySDK.startProfiler()
}

@IBAction func stopContinuousProfiler(_ sender: Any) {
SentrySDK.stopProfileSession()
SentrySDK.stopProfiler()
}

@IBAction func viewLastProfile(_ sender: Any) {
Expand Down
7 changes: 5 additions & 2 deletions Samples/iOS-Swift/iOS-Swift/SentrySDKWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,11 @@ extension SentrySDKWrapper {
extension SentrySDKWrapper {
func configureProfiling(_ options: Options) {
if args.contains("--io.sentry.profile-options-v2") {
options.profiling.lifecycle = args.contains("--io.sentry.profile-lifecycle-manual") ? .manual : .trace
options.profiling.sessionSampleRate = (env["--io.sentry.profile-session-sample-rate"] as? NSString)?.floatValue ?? 1
options.configureProfiling = {
$0.lifecycle = args.contains("--io.sentry.profile-lifecycle-manual") ? .manual : .trace
$0.sessionSampleRate = (env["--io.sentry.profile-session-sample-rate"] as? NSString)?.floatValue ?? 1
$0.profileAppStarts = args.contains("--io.sentry.profile-app-starts-v2")
}
} else {
options.profilesSampleRate = profilesSampleRate
options.profilesSampler = profilesSampler
Expand Down
4 changes: 4 additions & 0 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@
8459FCC02BD73EB20038E9C9 /* SentryProfilerSerialization.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8459FCBF2BD73EB20038E9C9 /* SentryProfilerSerialization.mm */; };
845C16D52A622A5B00EC9519 /* SentryTracer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 845C16D42A622A5B00EC9519 /* SentryTracer+Private.h */; };
845CEAEF2D83F79500B6B325 /* SentryProfilingPublicAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845CEAEE2D83F79500B6B325 /* SentryProfilingPublicAPITests.swift */; };
845CEB172D8A979700B6B325 /* SentryAppStartProfilingConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845CEB162D8A979700B6B325 /* SentryAppStartProfilingConfigurationTests.swift */; };
848A45192BBF8D33006AAAEC /* SentryContinuousProfiler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 848A45182BBF8D33006AAAEC /* SentryContinuousProfiler.mm */; };
848A451A2BBF8D33006AAAEC /* SentryContinuousProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 848A45172BBF8D33006AAAEC /* SentryContinuousProfiler.h */; };
848A451D2BBF9504006AAAEC /* SentryProfilerTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 848A451C2BBF9504006AAAEC /* SentryProfilerTestHelpers.m */; };
Expand Down Expand Up @@ -1844,6 +1845,7 @@
8459FCC12BD73EEF0038E9C9 /* SentryProfilerSerialization+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryProfilerSerialization+Test.h"; sourceTree = "<group>"; };
845C16D42A622A5B00EC9519 /* SentryTracer+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryTracer+Private.h"; path = "include/SentryTracer+Private.h"; sourceTree = "<group>"; };
845CEAEE2D83F79500B6B325 /* SentryProfilingPublicAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryProfilingPublicAPITests.swift; sourceTree = "<group>"; };
845CEB162D8A979700B6B325 /* SentryAppStartProfilingConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryAppStartProfilingConfigurationTests.swift; sourceTree = "<group>"; };
846F90332D56F59D009E86C1 /* Brewfile-ci-deploy */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = "Brewfile-ci-deploy"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
848A45172BBF8D33006AAAEC /* SentryContinuousProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryContinuousProfiler.h; path = ../include/SentryContinuousProfiler.h; sourceTree = "<group>"; };
848A45182BBF8D33006AAAEC /* SentryContinuousProfiler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryContinuousProfiler.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3674,6 +3676,7 @@
035E73CD27D5790A005EEB11 /* SentryThreadMetadataCacheTests.mm */,
03F9D37B2819A65C00602916 /* SentryProfilerTests.mm */,
84A305472BC72A0A00D84283 /* SentryAppLaunchProfilingTests.swift */,
845CEB162D8A979700B6B325 /* SentryAppStartProfilingConfigurationTests.swift */,
845CEAEE2D83F79500B6B325 /* SentryProfilingPublicAPITests.swift */,
8419C0C328C1889D001C8259 /* SentryTraceProfilerTests.swift */,
8446F5182BE172290040D57E /* SentryContinuousProfilerTests.swift */,
Expand Down Expand Up @@ -5554,6 +5557,7 @@
845CEAEF2D83F79500B6B325 /* SentryProfilingPublicAPITests.swift in Sources */,
8431EFE829B27BAD00D8DC56 /* SentrySystemWrapperTests.swift in Sources */,
84A305492BC7328400D84283 /* SentryAppLaunchProfilingTests.swift in Sources */,
845CEB172D8A979700B6B325 /* SentryAppStartProfilingConfigurationTests.swift in Sources */,
8431EFE529B27BAD00D8DC56 /* SentryNSProcessInfoWrapperTests.swift in Sources */,
8431EFDE29B27B5300D8DC56 /* SentryTraceProfilerTests.swift in Sources */,
);
Expand Down
9 changes: 2 additions & 7 deletions SentryTestUtils/SentryLaunchProfiling+Tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ typedef struct {
SentrySamplerDecision *_Nullable profilesDecision;
} SentryLaunchProfileConfig;

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

SENTRY_EXTERN SentryTracer *_Nullable sentry_launchTracer;

SentryLaunchProfileConfig sentry_shouldProfileNextLaunch(SentryOptions *options);
Expand All @@ -41,7 +35,8 @@ BOOL sentry_willProfileNextLaunch(SentryOptions *options);
*/
void _sentry_nondeduplicated_startLaunchProfile(void);

SentryTransactionContext *sentry_context(NSNumber *tracesRate, NSNumber *tracesRand);
SentryTransactionContext *sentry_contextForLaunchProfilerForTrace(
NSNumber *tracesRate, NSNumber *tracesRand);

NS_ASSUME_NONNULL_END

Expand Down
6 changes: 3 additions & 3 deletions Sources/Sentry/PrivateSentrySDKOnly.mm
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#import "SentryInstallation.h"
#import "SentryInternalDefines.h"
#import "SentryMeta.h"
#import "SentryOptions.h"
#import "SentryOptions+Private.h"
#import "SentrySDK+Private.h"
#import "SentrySerialization.h"
#import "SentrySessionReplayIntegration+Private.h"
Expand Down Expand Up @@ -224,9 +224,9 @@
return payload;
}

+ (void)discardProfilerForTrace:(SentryId *)traceId traceSampled:(BOOL)traceSampled;
+ (void)discardProfilerForTrace:(SentryId *)traceId traceSampled:(BOOL)isProfiling;
{
sentry_discardProfiler(traceId, SentrySDK.currentHub, traceSampled);
sentry_discardProfilerCorrelatedToTrace(traceId, SentrySDK.currentHub, isProfiling);

Check warning on line 229 in Sources/Sentry/PrivateSentrySDKOnly.mm

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/PrivateSentrySDKOnly.mm#L229

Added line #L229 was not covered by tests
}

#endif // SENTRY_TARGET_PROFILING_SUPPORTED
Expand Down
Loading
Loading