Unified Memory page migration
Distinguish shared addressing, coherence, synchronization, and locality across platform-specific managed-memory implementations.
On this page
The question for today
What you’ll understand
- Separate pointer accessibility from physical placement and race freedom.
- Estimate migration volume only after declaring page and movement assumptions.
- Design ownership phases and profile platform-specific fault behavior.
A managed pointer can simplify a training application’s memory management without making every CPU and GPU access equally cheap. The underlying system may migrate pages, access remote storage, or use a coherent platform-specific path. This lesson uses CUDA 12.8.1 and a Linux discrete Ampere-class context with appropriate managed-memory capabilities, while explicitly distinguishing systems with different support. A common address space is an interface property, not a promise of local placement or correct concurrent access.
Query the platform rather than infer it
CUDA exposes device attributes that describe managed-memory and concurrent-access support. Read those attributes together with the operating-system and platform requirements before choosing an access protocol. A Linux discrete GPU with supported concurrent managed access does not establish the rules for every Windows configuration, integrated GPU, or coherent CPU-GPU system. HMM and address-translation services can change how system allocations are accessed. Hardware coherence on a platform also does not make unsynchronized conflicting program accesses valid under the required memory model.
Keep four questions separate: can a processor address the allocation, where are its current data, which coherence mechanism maintains the image, and what orders a particular producer before a consumer? A kernel and CPU thread may require an event or stream synchronization even when they share a pointer. An application that relies on an unsupported concurrent CPU access can fail for reasons unrelated to bandwidth. Document the platform capabilities alongside the source-level ownership protocol rather than hiding them behind the phrase managed memory.
Movement policy changes with the access pattern
A first GPU access can trigger fault handling and data movement on a suitable demand-paged platform. Subsequent accesses may reuse resident data, but alternating CPU and GPU ownership can repeatedly move a working set. Oversubscription adds another problem: a working set larger than available local memory can cause eviction and refaulting. Fault counts alone do not completely describe performance because batching, migration size, remote accesses, and overlap matter. Use profiling evidence to distinguish one-time startup costs from repeated movement during steady-state training.
Prefetch and memory advice express documented requests or policy information; they are not blanket guarantees that every later access stays local. An asynchronous prefetch must also be ordered before the consumer if its completion is required. Organize work into phases that reuse tensors near the processor performing repeated computation, and avoid fine-grained CPU inspection that unintentionally creates frequent ownership changes. This is an optimization hypothesis, not a rule that every managed allocation should always be copied in its entirety to a GPU.
Use a trace to test the ownership hypothesis
Compare end-to-end execution with representative tensor sizes, not merely a small allocation that remains resident after warmup. Record GPU and CPU access phases, memory pressure, prefetch dependencies, and capabilities. A workload that performs CPU preprocessing once and many GPU updates has a different locality story from one that alternates each layer between processors. If results vary with memory pressure, test whether local capacity or another resource explains the change before treating migration policy as the only cause.
The cache lab illustrates the narrower idea of a repeatedly reused working set. Reset, set capacity to 4 and stride to 4, predict the result at seventeen requests, then Step once. Compare a fresh Reset with both capacity at 2 and stride at 4 before Step. The toy starts empty but initially counts sixteen requests; one Step adds the seventeenth. It models deterministic fully associative LRU, not managed pages, hardware coherence, prefetch, page faults, or CPU-GPU ownership transfers.
Work it through
Count a declared migration scenario
Assume a 4,096-page tensor, an illustrative movement granularity of four KiB per page, and complete movement of every page at each handoff. Compare twenty handoffs with two; these assumptions are not a claim about a CUDA device’s actual page size.
The tensor movement volume per full handoff is 4,096 × 4,096 bytes = 16,777,216 bytes, or 16 MiB.
Twenty full handoffs transfer 20 × 16 = 320 MiB. A phase-organized schedule with two full handoffs transfers 32 MiB under the same assumptions.
The difference is 288 MiB, or a factor of ten in this counted movement. Fault overhead, remote accesses, partial movement, and overlap could make an actual platform behave differently.
Grouping ownership phases can reduce a declared movement count without establishing an equivalent runtime speedup.
The living notebook
Explore the model
Interactive lab · cache
Working-set reuse as a limited analogy
Reset, set C = 4 and s = 4, predict hits for seventeen requests, then Step once: thirteen hits. Compare a fresh Reset with both C = 2 and s = 4 before Step: zero hits. This sixteen-address LRU toy does not simulate managed-memory pages, migration, coherence, or prefetch.
- Hits / requests
- 0 / 16
- Hit rate
- 0%
- Address-stream period
- 16 addresses
A fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forA reuse pattern can fit one capacity and thrash another; migration conclusions need platform-specific evidence.
Pause & reason
Check your understanding
Your turn
Try it yourself
An illustrative model uses 1,024 pages of 64 KiB each and six complete movements. Calculate total movement in MiB and name one platform behavior that would invalidate this count.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
One MiB is 1,024 KiB. Treat 64 KiB as a stated modeling assumption, not a universal CUDA granularity.
Compare with the solution
The working set is 1,024 × 64 KiB = 64 MiB, and six full movements total 384 MiB. Remote access without a full migration, movement of only touched ranges, a different actual granularity, or retained residency can invalidate the count. Fault handling can also add time even if the byte estimate happens to match the measured movement.
Keep the idea
Take it with you
- Managed addressing, coherence, synchronization, and locality describe different guarantees.
- Migration estimates must declare movement size and access-pattern assumptions.
- Platform queries and measured traces are necessary before generalizing a managed-memory result.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.