Skip to content

Commit

Permalink
feat(launch profiling): use dedicated traces instead of auto perf tra…
Browse files Browse the repository at this point in the history
…ces (#3621)
  • Loading branch information
armcknight authored Feb 15, 2024
1 parent b625d72 commit 856083f
Show file tree
Hide file tree
Showing 25 changed files with 243 additions and 350 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,25 @@

## Unreleased

### Features

- Automatically profile app launches (#3529)

### Improvements

- Cache installationID async to avoid file IO on the main thread when starting the SDK (#3601)

### Fixes

- Finish TTID span when transaction finishes (#3610)
- Dont take screenshot and view hierarchy for app hanging (#3620)
- Don't take screenshot and view hierarchy for app hanging (#3620)

## 8.20.0

### Features

- Add visionOS as device family (#3548)
- Add VisionOS Support for Carthage (#3565)
- Automatically profile app launches (#3529)

### Fixes

Expand Down
6 changes: 0 additions & 6 deletions Samples/iOS-Swift/iOS-Swift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
84B527BD28DD25E400475E8D /* SentryDevice.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84B527BC28DD25E400475E8D /* SentryDevice.mm */; };
84BE546F287503F100ACC735 /* SentrySDKPerformanceBenchmarkTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 84BE546E287503F100ACC735 /* SentrySDKPerformanceBenchmarkTests.m */; };
84BE547E287645B900ACC735 /* SentryProcessInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 84BE54792876451D00ACC735 /* SentryProcessInfo.m */; };
84DEE88E2B6A4D1200A7BC17 /* AppStartup.m in Sources */ = {isa = PBXBuildFile; fileRef = 84DEE88D2B6A4D1200A7BC17 /* AppStartup.m */; };
84FB812A284001B800F3A94A /* SentryBenchmarking.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84FB8129284001B800F3A94A /* SentryBenchmarking.mm */; };
84FB812B284001B800F3A94A /* SentryBenchmarking.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84FB8129284001B800F3A94A /* SentryBenchmarking.mm */; };
8E8C57AF25EF16E6001CEEFA /* TraceTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E8C57AE25EF16E6001CEEFA /* TraceTestViewController.swift */; };
Expand Down Expand Up @@ -315,8 +314,6 @@
84BE546E287503F100ACC735 /* SentrySDKPerformanceBenchmarkTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySDKPerformanceBenchmarkTests.m; sourceTree = "<group>"; };
84BE54782876451D00ACC735 /* SentryProcessInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryProcessInfo.h; sourceTree = "<group>"; };
84BE54792876451D00ACC735 /* SentryProcessInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryProcessInfo.m; sourceTree = "<group>"; };
84DEE88C2B6A4D1200A7BC17 /* AppStartup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppStartup.h; sourceTree = "<group>"; };
84DEE88D2B6A4D1200A7BC17 /* AppStartup.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppStartup.m; sourceTree = "<group>"; };
84FB8125284001B800F3A94A /* SentryBenchmarking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryBenchmarking.h; sourceTree = "<group>"; };
84FB8129284001B800F3A94A /* SentryBenchmarking.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryBenchmarking.mm; sourceTree = "<group>"; };
84FB812C2840021B00F3A94A /* iOS-Swift-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "iOS-Swift-Bridging-Header.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -478,8 +475,6 @@
D8DBDA73274D4DF900007380 /* ViewControllers */,
63F93AA9245AC91600A500DB /* iOS-Swift.entitlements */,
637AFDA9243B02760034958B /* AppDelegate.swift */,
84DEE88C2B6A4D1200A7BC17 /* AppStartup.h */,
84DEE88D2B6A4D1200A7BC17 /* AppStartup.m */,
637AFDAD243B02760034958B /* TransactionsViewController.swift */,
84AB90782A50031B0054C99A /* Profiling */,
D80D021229EE93630084393D /* ErrorsViewController.swift */,
Expand Down Expand Up @@ -958,7 +953,6 @@
7B79000429028C7300A7F467 /* MetricKitManager.swift in Sources */,
D8D7BB4A2750067900044146 /* UIAssert.swift in Sources */,
D8F3D057274E574200B56F8C /* LoremIpsumViewController.swift in Sources */,
84DEE88E2B6A4D1200A7BC17 /* AppStartup.m in Sources */,
629EC8AD2B0B537400858855 /* ANRs.swift in Sources */,
D8DBDA78274D5FC400007380 /* SplitViewController.swift in Sources */,
84ACC43C2A73CB5900932A18 /* ProfilingNetworkScanner.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@
argument = "--disable-file-io-tracing"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--io.sentry.wipe-data"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "--io.sentry.slow-load-method"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "--disable-watchdog-tracking"
isEnabled = "NO">
Expand All @@ -82,8 +90,8 @@
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--io.sentry.test.profilesAppLaunches"
isEnabled = "NO">
argument = "--profile-app-launches"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "--disable-crash-handler"
Expand Down
21 changes: 19 additions & 2 deletions Samples/iOS-Swift/iOS-Swift/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

print("[iOS-Swift] launch arguments: \(ProcessInfo.processInfo.arguments)")
print("[iOS-Swift] environment: \(ProcessInfo.processInfo.environment)")
print("[iOS-Swift] [debug] launch arguments: \(ProcessInfo.processInfo.arguments)")
print("[iOS-Swift] [debug] environment: \(ProcessInfo.processInfo.environment)")

maybeWipeData()
AppDelegate.startSentry()

if #available(iOS 15.0, *) {
Expand Down Expand Up @@ -162,3 +163,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// swiftlint:enable force_cast
}
}

private extension AppDelegate {
// previously tried putting this in an AppDelegate.load override in ObjC, but it wouldn't run until after a launch profiler would have an opportunity to run, since SentryProfiler.load would always run first due to being dynamically linked in a framework module. it is sufficient to do it before calling SentrySDK.startWithOptions to clear state for testProfiledAppLaunches because we don't make any assertions on a launch profile the first launch of the app in that test
func maybeWipeData() {
if ProcessInfo.processInfo.arguments.contains("--io.sentry.wipe-data") {
print("[iOS-Swift] [debug] removing app data")
let appSupport = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first!
let cache = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!
for path in [appSupport, cache] {
for item in FileManager.default.enumerator(atPath: path)! {
try! FileManager.default.removeItem(atPath: (path as NSString).appendingPathComponent((item as! String)))
}
}
}
}
}
17 changes: 0 additions & 17 deletions Samples/iOS-Swift/iOS-Swift/AppStartup.h

This file was deleted.

26 changes: 0 additions & 26 deletions Samples/iOS-Swift/iOS-Swift/AppStartup.m

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class ProfilingViewController: UIViewController, UITextFieldDelegate {
let value = SentryBenchmarking.stopBenchmark()!
valueTextField.isHidden = false
valueTextField.text = value
print("[iOS-Swift] [ProfilingViewController] benchmarking results:\n\(value)")
print("[iOS-Swift] [debug] [ProfilingViewController] benchmarking results:\n\(value)")
}

@IBAction func startCPUWork(_ sender: UIButton) {
Expand Down Expand Up @@ -130,7 +130,7 @@ extension ProfilingViewController {
let url = file as! URL
if url.absoluteString.contains(fileName) {
block(url)
print("[iOS-Swift] [ProfilingViewController] removing file at \(url)")
print("[iOS-Swift] [debug] [ProfilingViewController] removing file at \(url)")
try! FileManager.default.removeItem(at: url)
return
}
Expand All @@ -150,7 +150,7 @@ extension ProfilingViewController {
return
}
let contents = data.base64EncodedString()
print("[iOS-Swift] [ProfilingViewController] contents of file at \(file): \(String(describing: String(data: data, encoding: .utf8)))")
print("[iOS-Swift] [debug] [ProfilingViewController] contents of file at \(file): \(String(describing: String(data: data, encoding: .utf8)))")
profilingUITestDataMarshalingTextField.text = contents
profilingUITestDataMarshalingStatus.text = ""
}
Expand Down
21 changes: 9 additions & 12 deletions Samples/iOS-Swift/iOS-SwiftUITests/ProfilingUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ProfilingUITests: BaseUITest {
app.launchArguments.append("--io.sentry.wipe-data")
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
// 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.
try performAssertions(shouldProfileThisLaunch: false, shouldProfileNextLaunch: false)

// no profiling should be done on this launch; set the option to allow launch profiling for the next launch, keeping the default numerical sampling rates of 1 for traces and profiles
Expand All @@ -28,20 +28,17 @@ class ProfilingUITests: BaseUITest {
// this launch should not run the profiler; configure sampler functions returning 1 and numerical rates set to 0, which should result in a profile being taken as samplers override numerical rates
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, shouldEnableLaunchProfilingOptionForNextLaunch: true, profilesSampleRate: 0, tracesSampleRate: 0, profilesSamplerValue: 1, tracesSamplerValue: 1)

// this launch has the configuration to run the profiler, but because swizzling is disabled, it will not be saved due to the ui.load transaction not being allowed to be created. it will also configure it to not run a profile for the next launch due to disabling swizzling, which would override the option to enable launch profiling. this specific scenario, where a previous launch configures a profile, but then something prevents the associated tx from running, is not automatically avoidable. in the future we will create a dummy transaction to attach the profile to.
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, shouldEnableLaunchProfilingOptionForNextLaunch: true, shouldDisableSwizzling: true)
// this launch should run the profiler; configure sampler functions returning 0 and numerical rates set to 0, which should result in no profile being taken next launch
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: true, shouldEnableLaunchProfilingOptionForNextLaunch: true, profilesSamplerValue: 0, tracesSamplerValue: 0)

// this launch should not run the profiler and configure it not to run the next launch due to disabling automatic performance tracking, which would override the option to enable launch profiling
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, shouldEnableLaunchProfilingOptionForNextLaunch: true, shouldDisableAutoPerformanceTracking: true)

// this launch should not run the profiler and configure it not to run the next launch launch due to disabling UIViewController tracing, which would override the option to enable launch profiling
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, shouldEnableLaunchProfilingOptionForNextLaunch: true, shouldDisableUIViewControllerTracing: true)
// this launch should not run the profiler, but configure it to run the next launch
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, shouldEnableLaunchProfilingOptionForNextLaunch: true)

// this launch should not run the profiler and configure it not to run the next launch launch due to disabling tracing, which would override the option to enable launch profiling
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, shouldEnableLaunchProfilingOptionForNextLaunch: true, shouldDisableTracing: true)
// this launch should run the profiler, and configure it not to run the next launch due to disabling tracing, which would override the option to enable launch profiling
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: true, shouldEnableLaunchProfilingOptionForNextLaunch: true, shouldDisableTracing: true)

// make sure the profiler respects the last configuration not to run
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, shouldEnableLaunchProfilingOptionForNextLaunch: true)
// make sure the profiler respects the last configuration not to run; don't let another config file get written
try relaunchAndConfigureSubsequentLaunches(shouldProfileThisLaunch: false, shouldEnableLaunchProfilingOptionForNextLaunch: false)
}

/**
Expand Down
Loading

0 comments on commit 856083f

Please sign in to comment.