From 3dbeb18fc28cc2e8769f67925447ca7ab9a24fb6 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Tue, 15 Oct 2024 09:52:12 +0200 Subject: [PATCH 1/9] Choose qos --- .../SessionReplay/SentrySessionReplay.swift | 2 +- .../SentrySessionReplayTests.swift | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Sources/Swift/Integrations/SessionReplay/SentrySessionReplay.swift b/Sources/Swift/Integrations/SessionReplay/SentrySessionReplay.swift index 3b8b60497b..9e7bd70a65 100644 --- a/Sources/Swift/Integrations/SessionReplay/SentrySessionReplay.swift +++ b/Sources/Swift/Integrations/SessionReplay/SentrySessionReplay.swift @@ -225,7 +225,7 @@ class SentrySessionReplay: NSObject { //Creating a video is heavy and blocks the thread //Since this function is always called in the main thread //we dispatch it to a background thread. - dispatchQueue.dispatchAsync { + dispatchQueue.queue.async(qos: .utility) { do { let videos = try self.replayMaker.createVideoWith(beginning: startedAt, end: self.dateProvider.date()) for video in videos { diff --git a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift index b9b3e02e98..61e20b148c 100644 --- a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift +++ b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift @@ -17,6 +17,8 @@ class SentrySessionReplayTests: XCTestCase { private class TestReplayMaker: NSObject, SentryReplayVideoMaker { var screens = [String]() + var createVideoCallBack: ((SentryVideoInfo) -> Void)? + struct CreateVideoCall { var beginning: Date var end: Date @@ -30,6 +32,7 @@ class SentrySessionReplayTests: XCTestCase { try? "Video Data".write(to: outputFileURL, atomically: true, encoding: .utf8) let videoInfo = SentryVideoInfo(path: outputFileURL, height: 1_024, width: 480, duration: end.timeIntervalSince(beginning), frameCount: 5, frameRate: 1, start: beginning, end: end, fileSize: 10, screens: screens) + createVideoCallBack?(videoInfo) return [videoInfo] } @@ -148,6 +151,25 @@ class SentrySessionReplayTests: XCTestCase { assertFullSession(sut, expected: true) } + func testMakeReplayQueueQos() { + let fixture = Fixture() + + let sut = fixture.getSut(options: SentryReplayOptions(sessionSampleRate: 1, onErrorSampleRate: 1)) + sut.start(rootView: fixture.rootView, fullSession: true) + + let expect = expectation(description: "create video called") + fixture.replayMaker.createVideoCallBack = { _ in + let current = qos_class_self() + XCTAssertEqual(current, QOS_CLASS_UTILITY) + expect.fulfill() + } + + fixture.dateProvider.advance(by: 5) + Dynamic(sut).newFrame(nil) + + wait(for: [expect], timeout: 1) + } + func testReplayScreenNames() throws { let fixture = Fixture() let sut = fixture.getSut(options: SentryReplayOptions(sessionSampleRate: 1, onErrorSampleRate: 1)) From 5f4b1c13ca7072f055c30419c18155d7586aa904 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Tue, 15 Oct 2024 09:53:13 +0200 Subject: [PATCH 2/9] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e0f5af0db..a8b8b55fdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ via the option `swizzleClassNameExclude`. - Finish TTID correctly when viewWillAppear is skipped (#4417) - Swizzling RootUIViewController if ignored by `swizzleClassNameExclude` (#4407) - Data race in SentrySwizzleInfo.originalCalled (#4434) +- Thread running at User-initiated quality-of-service for session replay () ### Improvements From 766b088adc86f1eed6579eb299f66b3b37368d04 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Tue, 15 Oct 2024 09:58:46 +0200 Subject: [PATCH 3/9] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8b8b55fdc..40f65a8322 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ via the option `swizzleClassNameExclude`. - Finish TTID correctly when viewWillAppear is skipped (#4417) - Swizzling RootUIViewController if ignored by `swizzleClassNameExclude` (#4407) - Data race in SentrySwizzleInfo.originalCalled (#4434) -- Thread running at User-initiated quality-of-service for session replay () +- Thread running at User-initiated quality-of-service for session replay (#4439) ### Improvements From ac69f7b0f777015e180148ea0516ab3a7c5baacf Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Tue, 15 Oct 2024 11:18:18 +0200 Subject: [PATCH 4/9] wip --- Sources/Sentry/SentrySessionReplayIntegration.m | 6 +++++- .../Integrations/SessionReplay/SentrySessionReplay.swift | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Sources/Sentry/SentrySessionReplayIntegration.m b/Sources/Sentry/SentrySessionReplayIntegration.m index e2db6fc3c8..de44b3b932 100644 --- a/Sources/Sentry/SentrySessionReplayIntegration.m +++ b/Sources/Sentry/SentrySessionReplayIntegration.m @@ -281,6 +281,10 @@ - (void)startWithOptions:(SentryReplayOptions *)replayOptions = (NSInteger)(shouldReplayFullSession ? replayOptions.sessionSegmentDuration + 1 : replayOptions.errorReplayDuration + 1); + + dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class( DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_PRIORITY_LOW, 0); + SentryDispatchQueueWrapper* dispatchQueue = [[SentryDispatchQueueWrapper alloc] initWithName:"Sentry Session Replay" attributes:attributes]; + self.sessionReplay = [[SentrySessionReplay alloc] initWithReplayOptions:replayOptions replayFolderPath:docs @@ -290,7 +294,7 @@ - (void)startWithOptions:(SentryReplayOptions *)replayOptions touchTracker:_touchTracker dateProvider:SentryDependencyContainer.sharedInstance.dateProvider delegate:self - dispatchQueue:[[SentryDispatchQueueWrapper alloc] init] + dispatchQueue:dispatchQueue displayLinkWrapper:[[SentryDisplayLinkWrapper alloc] init]]; [self.sessionReplay diff --git a/Sources/Swift/Integrations/SessionReplay/SentrySessionReplay.swift b/Sources/Swift/Integrations/SessionReplay/SentrySessionReplay.swift index 9e7bd70a65..3b8b60497b 100644 --- a/Sources/Swift/Integrations/SessionReplay/SentrySessionReplay.swift +++ b/Sources/Swift/Integrations/SessionReplay/SentrySessionReplay.swift @@ -225,7 +225,7 @@ class SentrySessionReplay: NSObject { //Creating a video is heavy and blocks the thread //Since this function is always called in the main thread //we dispatch it to a background thread. - dispatchQueue.queue.async(qos: .utility) { + dispatchQueue.dispatchAsync { do { let videos = try self.replayMaker.createVideoWith(beginning: startedAt, end: self.dateProvider.date()) for video in videos { From d84115243f4b5cf9efd6b0d1b6fce4750b913e0b Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Tue, 15 Oct 2024 11:28:29 +0200 Subject: [PATCH 5/9] Update SentrySessionReplayTests.swift --- .../Integrations/SessionReplay/SentrySessionReplayTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift index 61e20b148c..dfcb3a1000 100644 --- a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift +++ b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift @@ -66,7 +66,7 @@ class SentrySessionReplayTests: XCTestCase { var lastReplayId: SentryId? var currentScreen: String? - func getSut(options: SentryReplayOptions = .init(sessionSampleRate: 0, onErrorSampleRate: 0) ) -> SentrySessionReplay { + func getSut(options: SentryReplayOptions = .init(sessionSampleRate: 0, onErrorSampleRate: 0), dispatchQueue: SentryDispatchQueueWrapper = TestSentryDispatchQueueWrapper() ) -> SentrySessionReplay { return SentrySessionReplay(replayOptions: options, replayFolderPath: cacheFolder, screenshotProvider: screenshotProvider, @@ -75,7 +75,7 @@ class SentrySessionReplayTests: XCTestCase { touchTracker: SentryTouchTracker(dateProvider: dateProvider, scale: 0), dateProvider: dateProvider, delegate: self, - dispatchQueue: TestSentryDispatchQueueWrapper(), + dispatchQueue: dispatchQueue, displayLinkWrapper: displayLink) } From 7f3556849fc39f4cb4cd7fa20293333993b1b793 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Tue, 15 Oct 2024 13:37:34 +0200 Subject: [PATCH 6/9] Update SentrySessionReplayTests.swift --- .../SentrySessionReplayTests.swift | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift index dfcb3a1000..d2622b661a 100644 --- a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift +++ b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayTests.swift @@ -150,26 +150,7 @@ class SentrySessionReplayTests: XCTestCase { XCTAssertNotNil(fixture.lastReplayRecording) assertFullSession(sut, expected: true) } - - func testMakeReplayQueueQos() { - let fixture = Fixture() - - let sut = fixture.getSut(options: SentryReplayOptions(sessionSampleRate: 1, onErrorSampleRate: 1)) - sut.start(rootView: fixture.rootView, fullSession: true) - - let expect = expectation(description: "create video called") - fixture.replayMaker.createVideoCallBack = { _ in - let current = qos_class_self() - XCTAssertEqual(current, QOS_CLASS_UTILITY) - expect.fulfill() - } - - fixture.dateProvider.advance(by: 5) - Dynamic(sut).newFrame(nil) - - wait(for: [expect], timeout: 1) - } - + func testReplayScreenNames() throws { let fixture = Fixture() let sut = fixture.getSut(options: SentryReplayOptions(sessionSampleRate: 1, onErrorSampleRate: 1)) From 57e6146018e2f259f3b86344ab2f1eb41e21d185 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Tue, 15 Oct 2024 12:15:08 +0000 Subject: [PATCH 7/9] Format code --- Sources/Sentry/SentrySessionReplayIntegration.m | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Sources/Sentry/SentrySessionReplayIntegration.m b/Sources/Sentry/SentrySessionReplayIntegration.m index de44b3b932..0cb801025f 100644 --- a/Sources/Sentry/SentrySessionReplayIntegration.m +++ b/Sources/Sentry/SentrySessionReplayIntegration.m @@ -281,10 +281,12 @@ - (void)startWithOptions:(SentryReplayOptions *)replayOptions = (NSInteger)(shouldReplayFullSession ? replayOptions.sessionSegmentDuration + 1 : replayOptions.errorReplayDuration + 1); - - dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class( DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_PRIORITY_LOW, 0); - SentryDispatchQueueWrapper* dispatchQueue = [[SentryDispatchQueueWrapper alloc] initWithName:"Sentry Session Replay" attributes:attributes]; - + dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class( + DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_PRIORITY_LOW, 0); + SentryDispatchQueueWrapper *dispatchQueue = + [[SentryDispatchQueueWrapper alloc] initWithName:"Sentry Session Replay" + attributes:attributes]; + self.sessionReplay = [[SentrySessionReplay alloc] initWithReplayOptions:replayOptions replayFolderPath:docs From b76b34a24a714d624d18d054a68d64d50b9c9d32 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Tue, 15 Oct 2024 14:26:43 +0200 Subject: [PATCH 8/9] Update CHANGELOG.md Co-authored-by: Philipp Hofmann --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40f65a8322..8b3ddf794b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ via the option `swizzleClassNameExclude`. - Finish TTID correctly when viewWillAppear is skipped (#4417) - Swizzling RootUIViewController if ignored by `swizzleClassNameExclude` (#4407) - Data race in SentrySwizzleInfo.originalCalled (#4434) -- Thread running at User-initiated quality-of-service for session replay (#4439) +- Thread running at user-initiated quality-of-service for session replay (#4439) ### Improvements From aea5aab93e25bfc900dea7d8e528f4872893b55d Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Tue, 15 Oct 2024 14:27:26 +0200 Subject: [PATCH 9/9] Update Sources/Sentry/SentrySessionReplayIntegration.m --- Sources/Sentry/SentrySessionReplayIntegration.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Sentry/SentrySessionReplayIntegration.m b/Sources/Sentry/SentrySessionReplayIntegration.m index 0cb801025f..3ecd0e1972 100644 --- a/Sources/Sentry/SentrySessionReplayIntegration.m +++ b/Sources/Sentry/SentrySessionReplayIntegration.m @@ -284,7 +284,7 @@ - (void)startWithOptions:(SentryReplayOptions *)replayOptions dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class( DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_PRIORITY_LOW, 0); SentryDispatchQueueWrapper *dispatchQueue = - [[SentryDispatchQueueWrapper alloc] initWithName:"Sentry Session Replay" + [[SentryDispatchQueueWrapper alloc] initWithName:"io.sentry.session-replay" attributes:attributes]; self.sessionReplay = [[SentrySessionReplay alloc]