perf: introduce FpsScheduler for independent UI and network queues#7418
perf: introduce FpsScheduler for independent UI and network queues#7418mimecuvalo merged 5 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
4 Skipped Deployments
|
|
API Changes Check Passed Great! The PR description now includes the required "### API changes" section. This helps reviewers and SDK users understand the impact of your changes. |
|
Could you separate the "solo mode" improvements from the "120fps tick" improvements? The 120fps change is going to produce some problems across different browsers and may require us to change the way that we handle draw shapes. (Same bugs we ran into last few times we tried this, or with coalescing). But I would love to save the CPU cost of "syncing with myself" when working alone on tldraw.com. |
sounds good 👍 @MitjaBezensek @steveruizok i moved the solo mode changes into a separate PR (child branch of this PR): #7657 |
| // eslint-disable-next-line no-restricted-globals | ||
| frameRaf = requestAnimationFrame(() => { | ||
| frameRaf = undefined | ||
| tick(true) |
There was a problem hiding this comment.
Zero FPS causes infinite RAF loop and blocked queue
Medium Severity
When targetFps is 0, getTargetTimePerFrame(0) returns Infinity (from 1000/0). After the first flush sets lastFlushTime to a normal timestamp, subsequent tick() calls will always find elapsed < Infinity is true, causing an infinite requestAnimationFrame loop. Queued functions will never execute, and the scheduler will continuously consume resources. The @public class lacks validation in both the constructor and updateTargetFps to prevent zero or negative FPS values.
Additional Locations (1)
MitjaBezensek
left a comment
There was a problem hiding this comment.
Nice! Left a few smaller comments.
|
Does this mean I can unlock the 120 Hz TLdraw canvas experience? |
Yes, this will be available in the SDK in the next release. |
parent PR: #7418 this makes just the solo mode change for better network usage. ### Change type - [ ] `bugfix` - [x] `improvement` - [ ] `feature` - [ ] `api` - [ ] `other` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Optimizes network scheduling and reduces solo-mode traffic by using a dedicated FPS-based scheduler. > > - Introduces `FpsScheduler` instance in `TLSyncClient` to throttle network operations independently of UI > - Adds dynamic sync rates: `SOLO_MODE_FPS = 1`, `COLLABORATIVE_MODE_FPS = 30`; updates target FPS based on `presenceMode` > - Replaces `fpsThrottle` with `fpsScheduler.fpsThrottle` for `flushPendingPushRequests` and `scheduleRebase` > - Adds `getSyncFps()` and calls `updateTargetFps` during presence reactions; minor debug log on push send > - Removes old `fpsThrottle`-based implementations > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 2f029e7. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
once more with feeling. the previous attempts were trying to put schedule UI and network events on the same queue, which ... I don't know what we were thinking :P
Anyway, this creates a proper FpsScheduler class that can take different target rates which solves the issues we were seeing. But also, it solves the fact that even without the 120fps change, we shouldn't be combining these queues.
I recommend reviewing this PR with "hide whitespace" on. you'll note that it had less changes than you would expect. it's really more about just creating a JS class to encapsulate the throttle queue.
this lays the groundwork for the child PR here that does the network bit of this: #7657
previous PRs: #6868 to #6470
Change type
bugfiximprovementfeatureapiotherTest plan
Release notes
API changes
FpsSchedulerto be able to create a FPS-throttled queue of functions to executeNote
Introduce per-instance FPS scheduling
FpsSchedulerclass inlib/throttlewith its own queue/state and configurable target FPS; create a default 120fps instance and havefpsThrottle/throttleToNextFramedelegate to itFpsSchedulerfromutils(src/index.ts); update API report accordinglylib/throttle.test.ts) covering throttling, next-frame batching, cancelation, and real-world scenariosDefaultDebugPanelFPS readout now includesmaxKnownFps(FPS ${fps} (max: ${maxKnownFps}))Written by Cursor Bugbot for commit 871ad95. This will update automatically on new commits. Configure here.