-
-
Notifications
You must be signed in to change notification settings - Fork 332
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: SwiftUI time for initial display and time for full display #4596
base: main
Are you sure you want to change the base?
Conversation
|
Performance metrics 🚀
|
Revision | Plain | With Sentry | Diff |
---|---|---|---|
b9a9ffd | 1201.61 ms | 1215.06 ms | 13.45 ms |
282cc99 | 1238.27 ms | 1253.46 ms | 15.19 ms |
984eb2d | 1220.62 ms | 1235.24 ms | 14.62 ms |
4350d44 | 1228.75 ms | 1246.75 ms | 18.00 ms |
279841c | 1237.29 ms | 1254.12 ms | 16.83 ms |
e145ca1 | 1207.19 ms | 1230.67 ms | 23.48 ms |
9b9f2a0 | 1233.36 ms | 1244.04 ms | 10.68 ms |
7b022df | 1220.53 ms | 1227.56 ms | 7.03 ms |
aa225e2 | 1218.00 ms | 1236.45 ms | 18.45 ms |
9f0d9e0 | 1226.31 ms | 1242.70 ms | 16.40 ms |
App size
Revision | Plain | With Sentry | Diff |
---|---|---|---|
b9a9ffd | 21.58 KiB | 418.43 KiB | 396.85 KiB |
282cc99 | 22.85 KiB | 414.09 KiB | 391.24 KiB |
984eb2d | 20.76 KiB | 425.77 KiB | 405.01 KiB |
4350d44 | 21.58 KiB | 629.82 KiB | 608.24 KiB |
279841c | 22.84 KiB | 403.19 KiB | 380.34 KiB |
e145ca1 | 21.58 KiB | 669.70 KiB | 648.12 KiB |
9b9f2a0 | 21.58 KiB | 707.42 KiB | 685.84 KiB |
7b022df | 22.85 KiB | 412.95 KiB | 390.10 KiB |
aa225e2 | 21.58 KiB | 694.47 KiB | 672.89 KiB |
9f0d9e0 | 21.58 KiB | 424.28 KiB | 402.70 KiB |
Previous results on branch: feat/swiftui-ttid
Startup times
Revision | Plain | With Sentry | Diff |
---|---|---|---|
51e85b4 | 1228.22 ms | 1249.19 ms | 20.96 ms |
f583fd1 | 1243.27 ms | 1258.91 ms | 15.65 ms |
f38e16a | 1237.13 ms | 1262.76 ms | 25.62 ms |
1ea8b74 | 1229.67 ms | 1251.90 ms | 22.22 ms |
7ce0058 | 1230.49 ms | 1246.94 ms | 16.45 ms |
9ef5a81 | 1234.29 ms | 1256.35 ms | 22.07 ms |
fccfa3c | 1232.65 ms | 1254.22 ms | 21.57 ms |
11c93a2 | 1227.00 ms | 1246.31 ms | 19.31 ms |
895b829 | 1232.55 ms | 1250.90 ms | 18.35 ms |
f6a9e2b | 1234.94 ms | 1245.60 ms | 10.66 ms |
App size
Revision | Plain | With Sentry | Diff |
---|---|---|---|
51e85b4 | 22.31 KiB | 756.73 KiB | 734.42 KiB |
f583fd1 | 22.30 KiB | 750.46 KiB | 728.16 KiB |
f38e16a | 22.30 KiB | 750.46 KiB | 728.16 KiB |
1ea8b74 | 22.30 KiB | 760.46 KiB | 738.16 KiB |
7ce0058 | 22.30 KiB | 750.46 KiB | 728.16 KiB |
9ef5a81 | 22.30 KiB | 750.46 KiB | 728.16 KiB |
fccfa3c | 22.31 KiB | 756.70 KiB | 734.39 KiB |
11c93a2 | 22.31 KiB | 760.41 KiB | 738.10 KiB |
895b829 | 22.30 KiB | 750.46 KiB | 728.16 KiB |
f6a9e2b | 22.30 KiB | 750.46 KiB | 728.16 KiB |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #4596 +/- ##
=============================================
+ Coverage 90.584% 90.669% +0.084%
=============================================
Files 621 618 -3
Lines 71120 71060 -60
Branches 25306 25300 -6
=============================================
+ Hits 64424 64430 +6
+ Misses 6602 6537 -65
+ Partials 94 93 -1
... and 11 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
Samples/iOS-SwiftUI/iOS-SwiftUI-UITests/SentryRedactModifierTests.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have one important comment to address that could impact a rework of this PR. Therefore, I wait until we resolve it before giving this a more detailed review.
Co-authored-by: Philipp Hofmann <philipp.hofmann@sentry.io>
if !viewAppeared { | ||
trace = ensureTransactionExists() | ||
spanId = createAndPushBodySpan(transactionCreated: trace != nil) | ||
#if canImport(SwiftUI) && canImport(UIKit) && os(iOS) || os(tvOS) | ||
if let trace = trace { startTTDTraker(for: trace) } | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m
: I would prefer keeping the logic for creating the transaction or span and keeping track of the TTDTracker in the SentryUIViewControllerPerformanceTracker
. Now, we have two different places that can easily get out of sync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This specific piece of logic is particular to the SwiftUI lifecycle. I don’t think it makes sense to move it to SentryUIViewControllerPerformanceTracker, but I did move other parts related to TTID to SentryUIViewControllerPerformanceTracker to reduce the responsibilities of this class.
private func startTTDTraker(for trace: SentryTracer) { | ||
let tracker = SentryTimeToDisplayTracker(name: self.name, waitForFullDisplay: self.waitforFullDisplay) | ||
SentryUIViewControllerPerformanceTracker.shared.setTimeToDisplay(tracker) | ||
tracker.start(for: trace) | ||
|
||
viewModel.tracker = tracker | ||
} | ||
#endif | ||
|
||
private func ensureTransactionExists() -> SentryTracer? { | ||
guard SentryPerformanceTracker.shared.activeSpanId() == nil else { return nil } | ||
|
||
let transactionId = SentryPerformanceTracker.shared.startSpan( | ||
withName: name, | ||
nameSource: nameSource, | ||
operation: "ui.load", | ||
origin: traceOrigin | ||
) | ||
SentryPerformanceTracker.shared.pushActiveSpan(transactionId) | ||
|
||
//According to Apple's documentation, the call to body needs to be fast | ||
//and can be made many times in one frame. Therefore they don't use async code to process the view. | ||
//Scheduling to finish the transaction at the end of the main loop seems the least hack solution right now. | ||
//'onAppear' is not a suitable place to do this because it may happen before other view body property get called. | ||
DispatchQueue.main.async { | ||
self.finishSpan(transactionId) | ||
} | ||
|
||
return SentryPerformanceTracker.shared.getSpan(transactionId) as? SentryTracer | ||
} | ||
|
||
private func createAndPushBodySpan(transactionCreated: Bool) -> SpanId { | ||
let spanName = transactionCreated ? "\(name) - body" : name | ||
let spanId = SentryPerformanceTracker.shared.startSpan( | ||
withName: spanName, | ||
nameSource: nameSource, | ||
operation: "ui.load", | ||
origin: traceOrigin | ||
) | ||
SentryPerformanceTracker.shared.pushActiveSpan(spanId) | ||
return spanId | ||
} | ||
|
||
private func finishSpan(_ spanId: SpanId) { | ||
SentryPerformanceTracker.shared.popActiveSpan() | ||
SentryPerformanceTracker.shared.finishSpan(spanId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m
: There is so much logic in this code in here. I would appreciate it if we could extract the logic into an extra testable component and/or write tests for all the different types of edge cases. Currently, I don't know how I can trust this code without having a good test suite covering multiple edge cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m
: I think we must add to the code docs of the option enableTimeToFullDisplayTracing
that this also has an impact on the SentryTracedView
.
Almost LGTM.
/// Creates a view that measures the performance of its `content`. | ||
/// | ||
/// - Parameter viewName: The name that will be used for the span, if nil we try to get the name of the content class. | ||
/// - Parameter waitForFullDisplay: Indicates whether this view transaction should wait for `SentrySDK.reportFullyDisplayed()` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m
: I think we must document how this works in combination with the enableTimeToFullDisplayTracing
option.
self.nameSource = viewName == nil ? .component : .custom | ||
let name = viewName ?? SentryTracedView.extractName(content: Content.self) | ||
let nameSource = viewName == nil ? SentryTransactionNameSource.component : SentryTransactionNameSource.custom | ||
let waitforFullDisplay = waitForFullDisplay ?? SentrySDK.options?.enableTimeToFullDisplayTracing ?? false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m
: It would be great to add a test validating that we pick up the value from the options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. The tests related to TTID are missing. Going to add it
|
||
if let transactionId = transactionId { | ||
self.finishSpan(transactionId) | ||
SentryPerformanceTracker.shared.popActiveSpan() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m
: Why do we also need to call popActiveSpan()
here? We already call it in finishSpan
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to pop the root transaction, but not always. There is a bug in here 🤦🏻
📜 Description
Track time for initial display and time for full display in SwiftUI
💚 How did you test it?
UI Test and sample
📝 Checklist
You have to check all boxes before merging:
sendDefaultPII
is enabled.🔮 Next steps