This document is relevant for: Inf2, Trn1, Trn2, Trn3
Neuron device memory#
Neuron Runtime allocates device memory (HBM) for several distinct purposes:
your input and output tensors, compiled model constants and code, scratchpad
space for intermediate results, DMA rings, profiling buffers, and
collective-communication overhead. This page describes each category, the
tools that report memory usage (neuron-top and sysfs), how to read an
out-of-memory (OOM) report, and how to reduce consumption — with the most
detail on scratchpad, which is often the largest adjustable category.
Overview#
The Neuron Runtime’s memory usage falls into the following categories:
tensors: input and output tensors allocated by your applicationmodel constants: compiled constants used by a NEFF programmodel code: the executable instructions for the Neuron Core. This also includes a micro-code overhead of 96MB per physical Neuron Core (this overhead is subject to future improvements)profile buffers: buffers used to store profiling eventsscratchpadandshared scratchpad: additional space used to store intermediary SBUF and other computations. See Scratchpad for details.dma rings: data transfer instructions describing data movements during NEFF execution.collectives: memory overhead used to orchestrate collective communication
You can adjust these categories as follows:
You control
model constantsandtensorsentirely. Adjust them as you would on other XLA devices, through matrix dimensions, batch sizes, and so on.scratchpadandshared scratchpaddepend on model size, model type, and tiling strategy. See Scratchpad.dma ringsusage is not easily actionable. You can reduce it by using DGE where possible, or by changing the model to reduce data movements such as transfers between HBM and SBUF.Neuron Runtime allocates
profile bufferswhen you enable profiling. You can influence these allocations by disabling profiling or adjusting the buffers manually. See Profile buffers.model codeusage is not actionable. If you observe significant usage, contact AWS Neuron support.
Logical Neuron Cores#
Starting with trn2, multiple physical Neuron Cores are grouped into a
single Logical Neuron Core. For details, see the Logical NeuronCore
configuration guide.
Note
On trn2, the default configuration is LNC2. With LNC1 (NEURON_LOGICAL_NC_CONFIG=1), two neighboring Neuron Cores share an HBM, as shown in the following diagram (two vertically neighboring NeuronCore-V3s share an HBM).
As a result, you can hit noisy-neighbor problems and see out-of-memory (OOM) errors earlier than expected, depending on what is loaded on the neighboring core.
Debugging tools#
neuron-top#
neuron-top shows current memory usage per core. For details, see the
neuron-top user guide.
sysfs#
You can also find the same information through sysfs. For details, see the Neuron sysfs user guide.
Out-of-memory (OOM) errors#
When an OOM occurs, Neuron Runtime dumps a breakdown of memory usage by type for each NEFF. For example:
2025-May-15 20:58:33.895937 224822:224822 ERROR TDRV:print_lnc_hbm_details LNC size is 1. Neuron Cores using this HBM: NC 4 and NC 5
2025-May-15 20:58:33.897479 224822:224822 ERROR TDRV:log_dev_mem Failed to allocate 4.000GB (alignment: none, usage: tensors) on ND 0:NC 4
2025-May-15 20:58:33.899416 224822:224822 ERROR TDRV:log_dev_mem_usage_table Displaying Current Memory Utilization:
(NOTE: the lines are LONG, and NEFF id to name mapping is printed after)
| | Model | Model | | Shared | | |DMA Rings |DMA Rings | DMA Rings |DMA Rings | | | Profiler |
| TOTAL | Code |Constants | Tensors |Scratchpad|Scratchpad| Runtime | IO | Spill |Collectives| Runtime |Collectives| XT CC | Buffers |
ND 0 Overall | 20.188GB |192.102MB | 82.344KB | 20.000GB | 0.000B | 0.000B |350.125KB |179.000KB | 64.000KB | 0.000B | 68.000KB | 0.000B | 0.000B | 0.000B |
\_NC 4 | 20.094GB | 96.065MB | 58.344KB | 20.000GB | 0.000B | 0.000B |229.062KB |118.000KB | 48.000KB | 0.000B | 36.000KB | 0.000B | 0.000B | 0.000B |
\_NEFF 1001 |263.906KB | 28.562KB | 34.344KB | n/a | n/a | 0.000B |108.000KB | 57.000KB | 32.000KB | 0.000B | 4.000KB | 0.000B | n/a | n/a |
\_NEFF 1002 |244.875KB | 31.875KB | 24.000KB | n/a | n/a | 0.000B |108.000KB | 61.000KB | 16.000KB | 0.000B | 4.000KB | 0.000B | n/a | n/a |
\_NC 5 | 96.285MB | 96.037MB | 24.000KB | 0.000B | 0.000B | 0.000B |121.062KB | 61.000KB | 16.000KB | 0.000B | 32.000KB | 0.000B | 0.000B | 0.000B |
\_NEFF 1003 |244.875KB | 31.875KB | 24.000KB | n/a | n/a | 0.000B |108.000KB | 61.000KB | 16.000KB | 0.000B | 4.000KB | 0.000B | n/a | n/a |
NEFF id to name mapping:
1001: "1.0.41235.0+df4a714bb-/local/out-test0_meta_dense"
1002: "1.0.41235.0+df4a714bb-/local/out-test0_meta_concat3"
1003: "1.0.41235.0+df4a714bb-/local/out-test0_meta_concat3"
If this OOM message is truncated, the same information is available at
/tmp/neuron_mem_table_device_<device_id>_hbm_<hbm_idx>.log.
Per-NEFF INFO logs#
A NEFF’s memory usage is also available as INFO-level logs during model
load. Set NEURON_RT_LOG_LEVEL_TDRV=info to see a log like the following:
2025-May-15 07:41:15.014997 2198754:2198754 INFO TDRV:dml_log_dev_neff_mem
[ND 0:NC 0] Current Usage Total: 96.543MB
shared scratchpad: 0.000B
Per NEFF memory usage breakdown for [out-test0_meta_concat3]:
Total: 230.562KB
* model code: 30.562KB
* model constants: 24.000KB
* scratchpad: 0.000B
* runtime: 95.000KB
* dma rings io: 61.000KB
* dma rings spill: 16.000KB
* dma rings collectives: 0.000B
* dma rings runtime: 4.000KB
* collectives: 0.000B
Profile buffers#
When you use NRT’s profiling APIs and neuron-profiler capture, Runtime
allocates buffers to store the profiling events. These buffers default to about
64 or 128 MB each, so expect around 2 GB of overhead (subject to future
changes).
You can adjust these buffer sizes with the
NEURON_RT_PROFILE_BUF_<buffer type>_MB flags — for example,
NEURON_RT_PROFILE_BUF_DMA_MB=512. The adjustable buffers are EVENT,
DMA, H2D_DMA, THROTTLE, CC_CORE_INSTRUCTION, and
CC_CORE_EVENT. H2D_DMA records host-device DMA events; setting
NEURON_RT_PROFILE_BUF_H2D_DMA_MB=0 turns off host-device DMA capture.
Note
Adjusting the buffer sizes manually is not recommended: buffers that are too small cause the profiler to lose events. Profile one NEFF at a time, and adjust buffer sizes only when profiling a single NEFF still runs out of memory.
To reduce memory usage further while profiling, use --single-io. This
option creates one IO tensor the size of the largest IO tensor in the model;
the other IO tensors point to slices of it during execution. The output is no
longer correct, but the profile still captures performance realistically.
--single-io is only available in neuron-profile.
neuron-profile capture -n file.neff --single-io
Note
Only device profiles require extra device memory; system profiles do not. If you only need a high-level view of kernel execution latency and time spent in Neuron Runtime APIs, capture a system profile with the nrt_sys_trace_fetch_events or NEURON_RT_INSPECT_ENABLE APIs. System profiles use a host-side, per-NeuronCore event buffer, which can overflow and drop events on long or high-throughput runs. See Handling dropped events and partial profiles to detect and control this.
Scratchpad#
Aside from inputs and outputs, a NEFF execution needs additional HBM space for temporary spills out of the state buffer (the cache), because a program’s working set can be arbitrarily large and may not fit in the state buffer. This space is the scratchpad.
The compiler specifies a NEFF’s scratchpad size entirely. It depends on kernel size, kernel type, and tiling strategy. For a training workload, scratchpad usage is usually determined by the size of the activation between the forward and backward layer; for an inference kernel, by the size of the hidden states. Optimal tiling and fusion of collective and compute operations can reduce scratchpad usage substantially.
A NEFF’s def.json records how much scratchpad space the NEFF requires.
Runtime allocates scratchpad memory on the HBM, per NeuronCore, and uses it only
while a NEFF is running. Because of this, Runtime shares the memory among all
loaded NEFFs to reduce the overall footprint: it allocates a shared
scratchpad used by all NEFFs loaded on a given NeuronCore. The shared
scratchpad’s size equals the size of the largest scratchpad among the loaded
NEFFs. In some cases a variable cannot go in the shared scratchpad and is placed
in a non-shared scratchpad specific to a NEFF (see Scratchpad variables).
Scratchpad variables#
The compiler fully manages the scratchpad space. A NEFF defines scratchpad variables and their size and offset within that space. Runtime maps every variable to the scratchpad space it allocates on the HBM. Some variables overlap, because not all variables are “live” at the same time during NEFF execution.
Runtime iterates through all scratchpad variables in def.json and computes
the MAX of offset + size across them. That value is the shared
scratchpad space the NEFF requires.
Appendix: NEFF format for scratchpad variables#
If you unpack a NEFF (using neuron-packager) and inspect sg00/def.json
(and sg01/def.json for NEFFs generated for the Trn2 LNC size 2
configuration), you see variable entries like these:
"var": {
"some_variable_name": {
"backing_variable_off": 17108992,
"ops": [],
"size": 131072,
"type": "virtual",
"var_id": 2349
},
...
}
A type of “virtual” indicates a scratchpad variable. The
backing_variable_off field is the offset inside the shared scratchpad space
Runtime allocates, and the size field is the size of the variable.
DMA rings#
DMA rings are buffers that store DMA descriptors; each descriptor describes a data movement that the DMA engines can execute.
DGE generates descriptors dynamically during NEFF execution, so a NEFF that uses DGE for a given DMA needs no HBM allocation for those descriptors.
For DMAs that do not use DGE, Runtime allocates the DMA rings on HBM and builds
the descriptors before execution. The NEFF encodes the details for building
these descriptors in def.json and <engine>.json, where <engine> is
the TPB engine that triggers the DMA operation.
Reducing DMA ring usage requires changes in the NEFF itself; the most effective change is using DGE for DMAs where supported.
In OOM reports, DMA rings are further categorized as:
IO — descriptors whose source or destination is an I/O tensor.
Spill — descriptors that move data between NEFF variables/tensors, excluding I/O tensors.
Collectives — descriptors that move data for collective operations between ranks on the same node.
Runtime — descriptors that do not correspond to explicit DMAs in the NEFF but are needed to support NEFF execution. Examples: loading DVE and activation tables, and instruction-fetch DMAs for TPB engines.
This document is relevant for: Inf2, Trn1, Trn2, Trn3