Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
841414e
Add RMM User Guide (draft from docs-overhaul branch)
bdice Apr 2, 2026
2a1f4b8
Fix user guide C++ examples to use modern resource_ref API
bdice Apr 2, 2026
0466c81
Remove autodoc section for deleted rmm.pylibrmm.cuda_stream module
bdice Apr 2, 2026
5a2bbaa
Align user guide with 26.06 migration: compiled lib, stream args, val…
bdice Apr 3, 2026
b8d0e98
Revise choosing_memory_resources page for performance-first framing
bdice Apr 3, 2026
c00a8c8
Replace incomplete Available Resources table with links to choosing g…
bdice Apr 3, 2026
91fb555
Add Python API reference link to Available Resources section
bdice Apr 3, 2026
03de6a4
Merge Per-Device Resources into Multi-Device Usage, add Python API link
bdice Apr 3, 2026
4b7edb6
Replace hardcoded system requirements with link to RAPIDS Platform Su…
bdice Apr 3, 2026
6ea60a8
Consolidate duplicate conda environment setup in build-from-source in…
bdice Apr 3, 2026
fc681f1
Use 26.06
bdice Apr 3, 2026
d4d8ea6
Match scope of C++/Python basic examples, add allocation to CuPy inte…
bdice Apr 3, 2026
5a51696
Rename base to base_mr in logging.md examples
bdice Apr 3, 2026
db54ca6
Merge branch 'staging' into docs-overhaul
bdice Apr 6, 2026
c44bbbf
Delete pool_allocators.md, add pool-doesn't-shrink note to choosing g…
bdice Apr 11, 2026
5c9afd8
Fix CudaAsyncMR description and multi-library claims in choosing guide
bdice Apr 12, 2026
32aefaa
Fix Python stream API: use rmm.pylibrmm.stream.Stream, remove context…
bdice Apr 12, 2026
e97b713
Fix stream-ordered allocation factual errors: pointer validity, resou…
bdice Apr 12, 2026
b999401
Rework guide.md examples to use explicit resource passing
bdice Apr 12, 2026
f767142
Restructure logging.md with tabbed code blocks and explicit resource …
bdice Apr 12, 2026
66296b4
Reduce managed_memory.md: remove CUDA-general content, explicit resou…
bdice Apr 12, 2026
4f14530
Reduce stream_ordered_allocation.md: explicit resources, cross-stream…
bdice Apr 12, 2026
704cb53
Polish introduction.md: reduce bold, fix CCCL statement, explicit res…
bdice Apr 13, 2026
0a634e0
Add Sphinx cross-references, explicit resource passing, and minor fix…
bdice Apr 13, 2026
2f9d48c
Extract user guide code examples into runnable source files with lite…
bdice Apr 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2020-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0

# Configuration file for the Sphinx documentation builder.
Expand Down Expand Up @@ -57,6 +57,7 @@
"sphinx.ext.intersphinx",
"sphinx_copybutton",
"sphinx_markdown_tables",
"sphinx_tabs.tabs",
"sphinxcontrib.jquery",
]

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ RMM (RAPIDS Memory Manager) is a library for allocating and managing GPU memory
:maxdepth: 2
:caption: Contents

user_guide/guide
user_guide/index
cpp/index
python/index
```
305 changes: 305 additions & 0 deletions docs/user_guide/choosing_memory_resources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
# Choosing a Memory Resource

One of the most common questions when using RMM is: "Which memory resource should I use?"

This guide provides recommendations for selecting the appropriate memory resource based on your application's needs.

## Recommended Defaults

For most applications, use the CUDA async memory pool.

`````{tabs}
````{code-tab} c++
#include <rmm/mr/cuda_async_memory_resource.hpp>
#include <rmm/mr/per_device_resource.hpp>

rmm::mr::cuda_async_memory_resource mr;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Should we be recommending the "default" async pool, rather than this one that makes its own mempool?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. We need the custom mempool to enable Blackwell decompression engine support and a custom release threshold. We don’t want to alter the flags on the default mempool.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, we should explain this, because this is a trade-off.

rmm::mr::set_current_device_resource_ref(mr);
````
````{code-tab} python
import rmm

mr = rmm.mr.CudaAsyncMemoryResource()
rmm.mr.set_current_device_resource(mr)
````
`````
Comment on lines +11 to +32

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid pushing the set_current_device_resource model in our examples? As we're seeing in all the libraries we have, it is best to manage resources explicitly (not for lifetime reasons, now we have any_resource ownership).


For applications exceeding GPU memory limits, use a pooled managed memory resource with prefetching. Note: managed memory is not supported on WSL2 systems.

`````{tabs}
````{code-tab} c++
#include <rmm/mr/managed_memory_resource.hpp>
#include <rmm/mr/pool_memory_resource.hpp>
#include <rmm/mr/prefetch_resource_adaptor.hpp>
#include <rmm/mr/per_device_resource.hpp>
#include <rmm/cuda_device.hpp>

// Use 80% of GPU memory, rounded down to nearest 256 bytes
auto [free_memory, total_memory] = rmm::available_device_memory();
std::size_t pool_size = (static_cast<std::size_t>(total_memory * 0.8) / 256) * 256;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rmm::align_down is a public function.


rmm::mr::managed_memory_resource managed_mr;
rmm::mr::pool_memory_resource pool_mr{managed_mr, pool_size};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Should we not be recommending cuda_async_managed_memory_resouce (at least on cuda-13)?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That feature is currently experimental. I am seeing mixed results on performance, and addressing those with the CUDA memory team. Long term this should be the preferred direction.

rmm::mr::prefetch_resource_adaptor prefetch_mr{pool_mr};
rmm::mr::set_current_device_resource_ref(prefetch_mr);
````
````{code-tab} python
import rmm

# Use 80% of GPU memory, rounded down to nearest 256 bytes
free_memory, total_memory = rmm.mr.available_device_memory()
pool_size = int(total_memory * 0.8) // 256 * 256

mr = rmm.mr.PrefetchResourceAdaptor(
rmm.mr.PoolMemoryResource(
rmm.mr.ManagedMemoryResource(),
initial_pool_size=pool_size,
)
)
rmm.mr.set_current_device_resource(mr)
````
`````

## Memory Resource Considerations

It is usually best to use resources that allow the CUDA driver to manage pool suballocation via `cudaMallocFromPoolAsync`.

### CudaAsyncMemoryResource

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throughout: All of these need cross-links to the API docs.

We also need a rosetta stone to translate from the Python names (here) to the C++ names, I expect.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree on the Rosetta stone aspect. That is one of my goals in writing a user guide that is separate from the API docs.


The `CudaAsyncMemoryResource` uses CUDA's driver-managed memory pool (via `cudaMallocAsync`). This is the **recommended default** for most applications.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a correct, but misleading, statement.

It use a driver-managed pool. But, crucially, does not use the default mempool for the device.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can clarify that.


**Advantages:**
- **Driver-managed pool**: Uses efficient suballocation with virtual addressing to avoid fragmentation
- **Cross-library sharing**: The pool can be shared across multiple applications and libraries, even those not using RMM directly
- **Stream-ordered semantics**: Allocations and deallocations are stream-ordered by default
- **Performance**: Similar or better performance compared to RMM's pool implementations

**When to use:**
- Default choice for GPU-accelerated applications
- Multi-stream or multi-threaded applications
- Applications using multiple GPU libraries (e.g., cuDF + PyTorch)
- Most production workloads

### CudaMemoryResource

The `CudaMemoryResource` uses `cudaMalloc` directly for each allocation, with no pooling.

**Advantages:**
- Simple and predictable
- No fragmentation concerns
- Memory is immediately returned to the system on deallocation

**Disadvantages:**
- Slower than pooled allocators due to synchronization overhead

**Example:**
```python
import rmm

rmm.mr.set_current_device_resource(rmm.mr.CudaMemoryResource())
```

**When to use:**
- Simple applications with infrequent allocations
- Debugging memory issues
- Testing or benchmarking baseline performance

### PoolMemoryResource

The `PoolMemoryResource` maintains a pool of memory allocated from an upstream resource.

**Advantages:**
- Fast suballocation from pre-allocated pool
- Configurable initial and maximum pool sizes

**Disadvantages:**
- Can suffer from fragmentation (unlike async MR)
Comment thread
bdice marked this conversation as resolved.
Outdated
- Pool is not shared across applications
- Requires careful tuning of pool sizes

**Example:**
```python
import rmm

pool = rmm.mr.PoolMemoryResource(
rmm.mr.CudaMemoryResource(), # upstream resource
initial_pool_size=2**30, # 1 GiB
maximum_pool_size=2**32 # 4 GiB
)
rmm.mr.set_current_device_resource(pool)
```

**When to use:**
- Legacy applications (prefer `CudaAsyncMemoryResource` for new code)
- Specific tuning requirements not met by async MR
- Wrapping non-CUDA memory sources

**Important**: If using `PoolMemoryResource`, prefer wrapping `CudaAsyncMemoryResource` as the upstream rather than `CudaMemoryResource`:

```python
# Better: Pool wrapping async MR
pool = rmm.mr.PoolMemoryResource(
rmm.mr.CudaAsyncMemoryResource(),
initial_pool_size=2**30
)
```

This combines the benefits of both: fast suballocation from RMM's pool and the driver's virtual addressing capabilities.

### ManagedMemoryResource

The `ManagedMemoryResource` uses CUDA unified memory (via `cudaMallocManaged`), allowing memory to be accessible from both CPU and GPU.

**Advantages:**
- Enables working with datasets larger than GPU memory
- Automatic page migration between CPU and GPU
- Simplifies memory management for host/device code

**Disadvantages:**
- Performance overhead due to page faults and migration
- Requires careful prefetching for optimal performance

**Example:**
```python
import rmm

# Always combine managed memory with prefetching for acceptable performance.
# Without prefetching, page faults cause significant overhead, especially
# in multi-stream workloads.
base = rmm.mr.ManagedMemoryResource()
prefetch_mr = rmm.mr.PrefetchResourceAdaptor(base)
rmm.mr.set_current_device_resource(prefetch_mr)
```

**When to use:**
- Datasets larger than available GPU memory
- Always combine with prefetching strategies (see [Managed Memory guide](managed_memory.md))

### ArenaMemoryResource

The `ArenaMemoryResource` divides a large allocation into size-binned arenas, reducing fragmentation.

**Advantages:**
- Better fragmentation characteristics than basic pool
- Good for mixed allocation sizes
- Predictable performance

**Disadvantages:**
- More complex configuration
- May waste memory if bin sizes don't match allocation patterns

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be contrasted with the (recommended) async pool as well.


**Example:**
```python
import rmm

arena = rmm.mr.ArenaMemoryResource(
rmm.mr.CudaMemoryResource(),
arena_size=2**28 # 256 MiB arenas
)
rmm.mr.set_current_device_resource(arena)
```

**When to use:**
- Applications with diverse allocation sizes
- Long-running services with complex allocation patterns
- When fragmentation is observed with pool allocators

## Composing Memory Resources

Memory resources can be composed (wrapped) to combine their properties. The general pattern is:

```python
# Adaptor wrapping a base resource
adaptor = rmm.mr.SomeAdaptor(base_resource)
```

### Common Compositions

**Prefetching with managed memory:**
```python
import rmm

# Prefetch adaptor wrapping managed memory pool
base = rmm.mr.ManagedMemoryResource()
pool = rmm.mr.PoolMemoryResource(base, initial_pool_size=2**30)
prefetch = rmm.mr.PrefetchResourceAdaptor(pool)
rmm.mr.set_current_device_resource(prefetch)
```

**Statistics tracking:**
```python
import rmm

# Track allocation statistics
base = rmm.mr.CudaAsyncMemoryResource()
stats = rmm.mr.StatisticsResourceAdaptor(base)
rmm.mr.set_current_device_resource(stats)
```

## Multi-Library Applications

When using RMM with multiple GPU libraries (e.g., cuDF, PyTorch, CuPy), `CudaAsyncMemoryResource` is especially important because:

1. The driver-managed pool is shared automatically across all libraries

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cudaasyncmemoryresource doesn't use the default mempool, so this is not true.

Additionally, even when using the default mempool this sharing doesn't happen by magic: all participating libraries must have somehow decided to use cudamallocasync with the default mempool.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2. You don't need to configure every library to use RMM

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example literally requires configuration of pytorch to use RMM.

3. Memory is not artificially partitioned between libraries

**Example: RMM + PyTorch**
```python
import rmm
import torch
from rmm.allocators.torch import rmm_torch_allocator

# Use async MR as the base
rmm.mr.set_current_device_resource(rmm.mr.CudaAsyncMemoryResource())

# Configure PyTorch to use RMM
torch.cuda.memory.change_current_allocator(rmm_torch_allocator)
```

With this setup, both PyTorch and any other RMM-using code (like cuDF) will share the same driver-managed pool.

## Performance Considerations

### Async MR vs. Pool MR

In most cases, `CudaAsyncMemoryResource` provides similar or better performance than `PoolMemoryResource`:

- Both use pooling for fast suballocation
- Async MR uses virtual addressing to avoid fragmentation
- Async MR shares memory across applications

**When Pool MR might be faster:**
- Very specific allocation patterns that align well with pool design
- Custom upstream resources (not CUDA memory)

### Multi-stream Applications

For applications using multiple CUDA streams or threads:

- `CudaAsyncMemoryResource` is **strongly recommended**
- Pool allocators can create "pipeline bubbles" where streams wait for allocations
- The async MR handles stream synchronization efficiently

## Best Practices

1. **Set the memory resource before any allocations**: Once memory is allocated, changing the resource can lead to crashes

```python
import rmm

# Do this first, before any GPU allocations
rmm.mr.set_current_device_resource(rmm.mr.CudaAsyncMemoryResource())
```

2. **Prefer async MR by default**: Unless you have specific requirements, start with `CudaAsyncMemoryResource`

3. **Use statistics for tuning**: If you need to understand allocation patterns, wrap with `StatisticsResourceAdaptor`

4. **Don't over-engineer**: Start simple, profile, and optimize only if needed

## See Also

- [Pool Allocators](pool_allocators.md) - Detailed guide on pool and arena allocators
- [Managed Memory](managed_memory.md) - Guide to using managed memory and prefetching
- [Stream-Ordered Allocation](stream_ordered_allocation.md) - Understanding stream-ordered semantics
Loading
Loading