You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Optimizes the change tracking mechanism used for persistent cache snapshots in turbo-tasks-backend.
Why?
The previous implementation used a FxDashMap<TaskId, ModifiedState> to track modified tasks, where ModifiedState was an enum with Modified and Snapshot(Option<Box<TaskStorage>>) variants. This had several inefficiencies:
Memory overhead: The ModifiedState enum was 16 bytes to account for the rare 'snapshot race' case
Datastructure overhead: the DashMap for the modified map was highly sharded leading to large amounts of memory overhead. Most acquisitions were extremely short lived and so this isn't necessary.
Separate task cache log: New task types were tracked in a separate TaskCacheLog structure (Sharded<ChunkedVec<...>>), requiring additional synchronization and a separate persistence path.
How?
Restructured change tracking into two separate data structures:
modified: Sharded<Vec<TaskId>> - A sharded append-only list for tracking modified task IDs. Since modifications are guarded by a transition in the any_modified flag on TaskStorage, each task is only added once, avoiding duplicates without additional synchronization.
snapshots: FxDashMap<TaskId, Option<Box<TaskStorage>>> - A small, rarely-used map for the uncommon case where a task is modified during an active snapshot operation. Uses only 16 shards since this is rare (only during dev mode idle-callback persistence races).
Unified task cache persistence:
Removed the separate TaskCacheLog and ChunkedVec infrastructure
New tasks now include their task_type directly in the SnapshotItem struct
Task cache entries are written inline with task data during persistence, simplifying the write path
Other optimizations:
SmallVec::into_boxed_slice() now called directly instead of into_vec().into_boxed_slice() (avoids intermediate allocation)
Removed swap_retain utility (no longer needed)
Simplified snapshot iteration using scope_and_block with chunked shards, this reduces the number of 'scratch buffers' allocated to 'one per chunk' instead of 'one per original shard'
Results on vercel-site
I ran a sequence of builds on vercel-site comparing canary and this branch
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Optimizes the change tracking mechanism used for persistent cache snapshots in turbo-tasks-backend.
Why?
The previous implementation used a
FxDashMap<TaskId, ModifiedState>to track modified tasks, whereModifiedStatewas an enum withModifiedandSnapshot(Option<Box<TaskStorage>>)variants. This had several inefficiencies:ModifiedStateenum was 16 bytes to account for the rare 'snapshot race' casemodifiedmap was highly sharded leading to large amounts of memory overhead. Most acquisitions were extremely short lived and so this isn't necessary.TaskCacheLogstructure (Sharded<ChunkedVec<...>>), requiring additional synchronization and a separate persistence path.How?
Restructured change tracking into two separate data structures:
modified: Sharded<Vec<TaskId>>- A sharded append-only list for tracking modified task IDs. Since modifications are guarded by a transition in theany_modifiedflag onTaskStorage, each task is only added once, avoiding duplicates without additional synchronization.snapshots: FxDashMap<TaskId, Option<Box<TaskStorage>>>- A small, rarely-used map for the uncommon case where a task is modified during an active snapshot operation. Uses only 16 shards since this is rare (only during dev mode idle-callback persistence races).Unified task cache persistence:
TaskCacheLogandChunkedVecinfrastructuretask_typedirectly in theSnapshotItemstructOther optimizations:
SmallVec::into_boxed_slice()now called directly instead ofinto_vec().into_boxed_slice()(avoids intermediate allocation)swap_retainutility (no longer needed)scope_and_blockwith chunked shards, this reduces the number of 'scratch buffers' allocated to 'one per chunk' instead of 'one per original shard'Results on vercel-site
I ran a sequence of builds on vercel-site comparing canary and this branch
Cold Cache Builds
Warm Cache Builds
The latency deltas are in the noise but there are substantial memory wins from this change