Skip to content

[Performance]Implement timers storage #824

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

Conversation

ipavlidakis
Copy link
Contributor

@ipavlidakis ipavlidakis commented May 27, 2025

🎯 Goal

Reduce the number of Timers during runtime.

📝 Summary

🔥 Known Issues or Risks

Main Thread Saturation (if scheduled on RunLoop.main):

By default, Timer runs on the main run loop. A large number of timers firing frequently can block the main thread, degrading UI performance and responsiveness.

Retain Cycles / Memory Leaks:

Timers strongly retain their target unless you invalidate them or use a weak reference. This is a common source of memory leaks.

Battery and CPU Usage:

Timers that fire often (e.g., every 10ms or 100ms) and in large numbers increase CPU wakeups and can significantly drain battery and impact thermal state.

Accuracy / Jitter:

The more timers you have, the more the system may coalesce them, or introduce jitter, especially in low power states.

RunLoop Overhead:

Too many timers can lead to excessive overhead in RunLoop management, especially if their firing schedules are not aligned or if timers are added/removed frequently.

🛠 Implementation

We implement a centralised storage for Timers. We then use the storage to access timers rather than creating them. The storage keeps reference to TimerPublishers. The benefits of TimerPublisher can be found below:

A Timer.TimerPublisher is a cold publisher, meaning:
- It does nothing until someone subscribes.
- It starts the underlying timer only when at least one subscriber is attached.
- Once the last subscriber is cancelled or deallocated, the timer automatically stops.

🧪 Manual Testing Notes

Given When Then
🟠 In a call alone I enable the camera The camera has a flipping animation
🟠 In a call I rotate the device The app freezes and then kills the phone
🟠 In a call I set a background filter My video track gets stuck and I get disconnected, but UI is frozen
🟠 In a call with 4+ participants I raise a hand It does not show for me, but it does for web participants
🟠 In a call with >2 participants I move app to background and then foreground All video tracks appear frozen
🟠 In a call with >2 participants I move app to background and then foreground Camera and mic buttons do not work

✅ Call Test Summary

Scenario

1:1 call for 10 minutes

  • noise-cancellation: active
  • background-filter: inactive
  • profiler: connected
  • debugger: disconnected

🧵 Tasks

Created Average Active Average Alive
59,367 6 13,000

🌡️ Thermal State Degradation

Start End Thermal State
00:00.000 00:35.706 Nominal thermal state
00:35.706 01:00.708 Fair thermal state
01:00.708 10:41.067 Serious thermal state

☑️ Contributor Checklist

  • I have signed the Stream CLA (required)
  • This change follows zero ⚠️ policy (required)
  • This change should receive manual QA
  • Changelog is updated with client-facing changes
  • New code is covered by unit tests
  • Comparison screenshots added for visual changes
  • Affected documentation updated (tutorial, CMS)

@ipavlidakis ipavlidakis self-assigned this May 27, 2025
@ipavlidakis ipavlidakis requested a review from a team as a code owner May 27, 2025 16:46
@ipavlidakis ipavlidakis added the enhancement New feature or request label May 27, 2025
Copy link

Public Interface

+ public protocol TimerProviding

+ public final class ScreenPropertiesAdapter: @unchecked Sendable  
+ 
+   public private var preferredFramesPerSecond: Int
+   public private var refreshRate: TimeInterval
+   public private var scale: CGFloat

+ extension ScreenPropertiesAdapter: InjectionKey  
+ 
+   public nonisolated static var currentValue: ScreenPropertiesAdapter



@ipavlidakis ipavlidakis force-pushed the fix/performance-improvements-subtasks/timers branch from 0087093 to fda6598 Compare May 27, 2025 16:47
@ipavlidakis ipavlidakis mentioned this pull request May 27, 2025
12 tasks
@Stream-SDK-Bot
Copy link
Collaborator

Stream-SDK-Bot commented May 27, 2025

SDK Size

title develop branch diff status
StreamVideo 7.54 MB 7.56 MB +20 KB 🟢
StreamVideoSwiftUI 2.26 MB 2.26 MB +1 KB 🟢
StreamVideoUIKit 2.38 MB 2.38 MB 0 KB 🟢
StreamWebRTC 9.85 MB 9.85 MB 0 KB 🟢

Copy link

Public Interface

+ public final class ScreenPropertiesAdapter: @unchecked Sendable  
+ 
+   public private var preferredFramesPerSecond: Int
+   public private var refreshRate: TimeInterval
+   public private var scale: CGFloat

+ extension ScreenPropertiesAdapter: InjectionKey  
+ 
+   public nonisolated static var currentValue: ScreenPropertiesAdapter

+ public protocol TimerProviding



Copy link

@ipavlidakis ipavlidakis merged commit 0f4a92a into fix/performance-improvements May 27, 2025
12 checks passed
@ipavlidakis ipavlidakis deleted the fix/performance-improvements-subtasks/timers branch May 27, 2025 17:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants