Skip to content

RBLN PyTorch APIs and Supported Operations

This page is the lookup reference for RBLN PyTorch: the torch.rbln module, which is registered as the device module for the rbln backend, and the set of PyTorch operators that execute on RBLN NPUs. Most PyTorch code needs no RBLN-specific call; the torch.rbln APIs exist for device selection, synchronization, streams, memory, and diagnostics, mirroring torch.cuda where a counterpart exists.

torch.rbln module

import torch registers torch.rbln automatically. The tables below list every public symbol by group with its torch.cuda counterpart where one exists. Detailed signatures follow each table, generated from the source docstrings.

Device management

API torch.cuda counterpart Summary
torch.rbln.is_available() is_available Whether RBLN is usable as an accelerator. Never raises; False when the runtime is absent, no device is visible, or the RBLN_* device configuration is malformed.
torch.rbln.device_count() device_count Number of logical RBLN devices. Never raises; returns 0 in the same cases as above and warns on a malformed configuration.
torch.rbln.physical_device_count() — Number of physical NPUs visible to the process, regardless of RSD grouping. Does not claim a device or freeze the mapping.
torch.rbln.current_device() current_device Index of the currently selected logical device.
torch.rbln.set_device(device) set_device Select the current device. Bookkeeping only; it does not claim an NPU. Prefer the torch.rbln.device context manager.
torch.rbln.device(device) device Context manager that changes the selected device and restores it on exit.
torch.rbln.device_of(obj) device_of Context manager that selects the device of the given tensor.
torch.rbln.synchronize(device=None) synchronize Wait for the device's pending asynchronous transfers, then for every stream on it.
torch.rbln.is_initialized() is_initialized True once a device has been selected, or when there are no devices.
torch.rbln.is_dummy_device() — True when the process runs on a host-backed dummy device rather than an NPU.
torch.rbln.device_summary() — Print the logical-to-physical NPU mapping table and warnings about unused NPUs.
torch.rbln.get_device_properties(device=None) get_device_properties Properties of the NPUs behind a logical device: name, total_memory (summed over the NPUs of the logical device), npu_count, and the per-NPU num_chiplet and memory_per_chiplet. Does not allocate memory or claim the device. Raises on a dummy device.
torch.rbln.get_device_name(device=None) get_device_name NPU name behind a logical device, for example "RBLN-CA25".
torch.rbln.get_amp_supported_dtype() get_amp_supported_dtype Dtypes supported by automatic mixed precision on RBLN. Returns an empty list at this release: no autocast dtypes are registered.

Logical devices and physical NPUs differ when Rebellions Scalable Design (RSD) groups several ATOM™ NPUs into one rbln:N; a Rebel100™ card is a fixed RSD-4 group of its four chiplets and always maps 1:1. device_count() reports logical devices; physical_device_count() reports the visible physical pool. The grouping is controlled by RBLN_DEVICE_MAP and RBLN_NPUS_PER_DEVICE, described in Environment Variables. For the same reason get_device_properties() reports total_memory summed over the NPUs of the logical device but memory_per_chiplet per chiplet: a device runs out of memory on its heaviest chiplet, so size a memory pool by memory_per_chiplet.

device(device)

Context-manager that changes the selected device.

Parameters:

Name Type Description Default
device torch.device, int, str, or None

device index to select. It is a no-op if this argument is a negative integer or None.

required
Example
with torch.rbln.device(0):
    x = torch.randn(2, 2, device="rbln:0")

device_of(obj)

Context-manager that changes the current device to that of given object.

You can use both tensors and storages as arguments. If a given object is not allocated on an RBLN device, this is a no-op.

Parameters:

Name Type Description Default
obj Tensor or Storage

object allocated on the selected device.

required
Example
1
2
3
4
tensor = torch.tensor([2, 64], device="rbln:1")
with torch.rbln.device_of(tensor):
    # operations here will use the same device as tensor (rbln:1)
    new_tensor = torch.zeros(3, device="rbln")

is_available()

Check if any RBLN devices are available.

Returns:

Name Type Description
bool bool

True if at least one RBLN device is available, False otherwise.

device_count()

Get the number of available RBLN devices.

Returns:

Name Type Description
int int

The number of available RBLN devices.

physical_device_count()

Get the number of physical RBLN devices in the system.

This function returns the actual number of physical devices, regardless of whether logical device aggregation is enabled.

Returns:

Name Type Description
int int

The number of physical RBLN devices.

current_device()

Get the index of the currently selected RBLN device.

Returns:

Name Type Description
int int

The index of the currently selected RBLN device.

set_device(device)

Set the current device.

Parameters:

Name Type Description Default
device device or int or str

selected device.

required

synchronize(device=None)

Wait for all work on the given RBLN device: its pending asynchronous transfers, then every stream on it (torch.cuda.synchronize parity).

If no device is specified, the current device is used.

Parameters:

Name Type Description Default
device device or int or str

The device to synchronize. Defaults to the current device.

None
Example
cpu_tensor = rbln_tensor.to("cpu", non_blocking=True)
torch.rbln.synchronize()  # wait for the transfer to complete

is_initialized()

True once set_device() has run, or when there are no devices at all.

The no-device case is deliberate: it makes torch.distributed's init_device_mesh skip its get_rank() % device_count() auto-select, which would otherwise fail on a host with no NPU.

Note: this calls device_count(), which plans the RBLN device mapping from the current RBLN_* environment. It does not claim an NPU or freeze the mapping; both happen on first device use, so a launcher may still assign RBLN_DEVICES afterwards.

is_dummy_device()

Whether the process runs on a host-backed dummy device rather than an NPU.

is_available() is True on a dummy device too, so use this to tell a dummy device apart from real NPU availability.

Returns:

Name Type Description
bool bool

True on a dummy device, False otherwise.

device_summary()

Print a summary of the RBLN device topology showing the mapping between logical devices and physical NPU IDs.

The table shows:

  • Logical device indices (rbln:0, rbln:1, ...)
  • Physical NPU IDs mapped to each logical device
  • Status of each device (Active, Active (Aggregated), or Unused)
  • A warning about unused physical devices, if any

The device mapping is determined by the following environment variables (in order of priority):

  1. RBLN_DEVICE_MAP: explicit groups, for example "[0,1],[2,3,4,5]"
  2. RBLN_NPUS_PER_DEVICE: uniform groups of the given size, for example "2"
Example
1
2
3
import torch

torch.rbln.device_summary()
1
2
3
4
5
6
7
[RBLN] Device Topology Initialized:
+----------------+------------------+---------------------+
| Logical Device | Physical NPU IDs | Status              |
+----------------+------------------+---------------------+
| rbln:0         | [ 0, 1 ]         | Active (Aggregated) |
| rbln:1         | [ 2, 3 ]         | Active (Aggregated) |
+----------------+------------------+---------------------+

get_device_properties(device=None)

Describe the NPUs behind an RBLN logical device (torch.cuda parity).

A logical device may span several physical NPUs (RBLN_DEVICE_MAP / RBLN_NPUS_PER_DEVICE), so total_memory sums them and npu_count says how many. num_chiplet and memory_per_chiplet stay per NPU: a device runs out on its heaviest chiplet, which total_memory hides, so size a pool by memory_per_chiplet.

The query does not allocate memory or claim the device, so it is safe to call before the runtime initializes. Properties are not cached: each call queries every NPU behind the logical device.

Parameters:

Name Type Description Default
device device or int or str

The device to query. Defaults to the current device.

None

Returns:

Name Type Description
DeviceProperties DeviceProperties

An object with the read-only attributes name (the NPU name, for example "RBLN-CA25"), total_memory (bytes, summed over the NPUs of the logical device), npu_count, num_chiplet (per NPU), and memory_per_chiplet (bytes, per chiplet).

Raises:

Type Description
RuntimeError

on a dummy device (host-backed, no NPU to report on), when no NPU is mapped to the index, when the runtime cannot answer for one of them, or when the NPUs of the logical device differ in name or chiplet count.

Example
props = torch.rbln.get_device_properties(0)
props.total_memory  # 150323855360

get_device_name(device=None)

Return the NPU name behind an RBLN logical device, for example "RBLN-CA25" (torch.cuda parity).

Same as get_device_properties(device).name.

Parameters:

Name Type Description Default
device device or int or str

The device to query. Defaults to the current device.

None

Returns:

Name Type Description
str str

The NPU name.

get_amp_supported_dtype()

Get a list of data types supported by automatic mixed precision (AMP) on RBLN devices.

Returns:

Type Description
List[dtype]

List[torch.dtype]: A list of data types supported by AMP.

Note

Automatic mixed precision is not implemented for RBLN devices yet, so this currently returns an empty list. As a result, entering torch.autocast("rbln") emits a warning and leaves autocast disabled instead of raising an error.

Random number generation

These functions exist so that PyTorch utilities that save and restore the accelerator's RNG state, such as torch.random.fork_rng, work on rbln. Each rbln device has its own default generator with its own state. At this release, random number generation operators on rbln are still pinned to CPU. When called without a generator argument, they draw from the default generator of the target rbln device, not from PyTorch's default CPU generator. The state these functions save and restore therefore affects only random operators pinned to CPU. It has no effect on random state inside device kernels yet, so setting it does not make results generated on the device, such as vLLM random sampling, reproducible.

API torch.cuda counterpart Summary
torch.rbln.get_rng_state(device="rbln") get_rng_state RNG state of the device as a ByteTensor. "rbln" with no index means the current device.
torch.rbln.get_rng_state_all() get_rng_state_all RNG state of every logical device, in device-index order.
torch.rbln.set_rng_state(new_state, device="rbln") set_rng_state Restore the RNG state of the device from a state returned by get_rng_state().
torch.rbln.set_rng_state_all(new_states) set_rng_state_all Restore the RNG state of every device from states ordered like get_rng_state_all().

get_rng_state(device='rbln')

Return the random number generator state of device as a ByteTensor (torch.cuda.get_rng_state parity).

Parameters:

Name Type Description Default
device device or int or str

The device to query. Defaults to "rbln", the current device.

'rbln'

Returns:

Type Description
Tensor

torch.Tensor: The generator state.

get_rng_state_all()

Return the random number generator state of every device, in device-index order.

Returns:

Type Description
List[Tensor]

List[torch.Tensor]: One state per logical device.

set_rng_state(new_state, device='rbln')

Set the random number generator state of device.

Parameters:

Name Type Description Default
new_state Tensor

A state produced by get_rng_state().

required
device device or int or str

The device to set. Defaults to "rbln", the current device.

'rbln'

set_rng_state_all(new_states)

Set the random number generator state of every device.

Parameters:

Name Type Description Default
new_states Iterable[Tensor]

States ordered like the result of get_rng_state_all().

required

Streams and events

Streams and events mirror torch.cuda.Stream and torch.cuda.Event and are also reachable through the generic torch.Stream and torch.Event classes with device="rbln".

API torch.cuda counterpart Summary
torch.rbln.Stream(device=None, priority=0) Stream An in-order sequence of device work; order work across streams with events. At this release separate streams add no device-side parallelism (see Execution Semantics › Streams). priority is accepted for parity and ignored. Streams come from a fixed per-device pool; beyond the pool size new instances reuse earlier streams.
torch.rbln.Event(enable_timing=False, blocking=False, interprocess=False) Event A recordable marker in a stream for cross-stream ordering and completion queries. The three flags are accepted and ignored; elapsed_time() is unsupported. Cross-process sharing is unsupported: ipc_handle() and from_ipc_handle() raise NotImplementedError.
torch.rbln.current_stream(device=None) current_stream The stream currently selected on the device.
torch.rbln.default_stream(device=None) default_stream The default stream of the device.
torch.rbln.stream(stream) stream Context manager that makes stream current and restores the previous one on exit. No-op for None.
torch.rbln.set_stream(stream) set_stream Set the current stream. Prefer the stream context manager.
torch.rbln.StreamContext StreamContext The context-manager class behind stream().

Stream(device=None, priority=0)

An in-order sequence of device work on an RBLN NPU.

Work submitted to the same stream runs in order, while work on different streams may run concurrently. Use a stream to overlap a copy with compute, and an Event to order work between two streams.

Streams come from a fixed per-device pool. Once the pool is exhausted, new instances reuse earlier streams.

Parameters:

Name Type Description Default
device torch.device, int, str, or None

The device the stream belongs to. If None, uses the current device. Defaults to None.

None
priority int

Accepted for API parity and ignored, because RBLN NPUs have no stream priorities. Defaults to 0.

0
Example
1
2
3
4
s = torch.rbln.Stream()
with torch.rbln.stream(s):
    y = x * 2
s.synchronize()
query()

Check whether all work submitted to this stream has completed.

Returns:

Name Type Description
bool bool

True if the stream has no pending work.

synchronize()

Block the calling host thread until all work submitted to this stream completes.

Waits on this stream only. A pending asynchronous transfer is tracked per device, not per stream, so use torch.rbln.synchronize() to wait for those.

wait_event(event)

Make all future work submitted to this stream wait for event.

A device-side fence when event was recorded on this stream's device: the call returns without blocking the host. RBLN has no cross-device fence, so an event recorded on another device is waited on the host instead. Ordering holds either way; what changes is that the caller is serialized.

Parameters:

Name Type Description Default
event Event

The event to wait for.

required
wait_stream(stream)

Make all future work submitted to this stream wait for the work already submitted to stream.

Records an event on stream and waits for it, so the cross-device rule in wait_event() applies here too.

Parameters:

Name Type Description Default
stream Stream

The stream to synchronize with.

required
record_event(event=None)

Record an event in this stream.

Parameters:

Name Type Description Default
event Event

The event to record. A new event is created if None. Defaults to None.

None

Returns:

Name Type Description
Event Event

The recorded event.

Event(enable_timing=False, blocking=False, interprocess=False)

A marker recorded in a stream, used to order work across streams and to query completion.

RBLN NPUs do not support event timing: elapsed_time() raises a RuntimeError, and the constructor flags are accepted for API parity but ignored. Waiting on an event recorded on another device falls back to a host-side synchronize.

Cross-process event sharing is not supported: ipc_handle() and from_ipc_handle() are inherited from torch.Event and raise NotImplementedError: torch.Event ipc is not supported yet, so interprocess=True grants no capability. Both attributes are present, so a capability probe that only looks them up succeeds and the failure surfaces at the call.

Parameters:

Name Type Description Default
enable_timing bool

Accepted for API parity and ignored. Defaults to False.

False
blocking bool

Accepted for API parity and ignored. Defaults to False.

False
interprocess bool

Accepted for API parity and ignored; RBLN events cannot be shared across processes. Defaults to False.

False
Example
producer = torch.rbln.Stream()
consumer = torch.rbln.Stream()
# An asynchronous upload needs a pinned source and a destination with device memory.
host_weights = torch.randn(1024, 1024, dtype=torch.float16).pin_memory()
w = torch.empty_like(host_weights, device="rbln")
torch.rbln.bind_device_memory(w)

copy_done = torch.rbln.Event()
with torch.rbln.stream(producer):
    w.copy_(host_weights, non_blocking=True)
    copy_done.record()

consumer.wait_event(copy_done)  # work on consumer waits for the copy; the host does not block
with torch.rbln.stream(consumer):
    y = w * 2
record(stream=None)

Record the event in a stream.

Parameters:

Name Type Description Default
stream Stream

The stream to record in. If None, uses the current stream. Defaults to None.

None
wait(stream=None)

Make all future work submitted to a stream wait for this event.

Parameters:

Name Type Description Default
stream Stream

The stream that waits. If None, uses the current stream. Defaults to None.

None
query()

Check whether the work captured by this event has completed.

Returns:

Name Type Description
bool bool

True if every work item recorded before the event has completed.

synchronize()

Block the calling host thread until the work captured by this event completes.

StreamContext(stream)

Context-manager that selects a given stream, restoring the previously selected one on exit.

The stream's device is selected for the duration. Create one with stream().

Parameters:

Name Type Description Default
stream Stream or None

The stream to select. It is a no-op if None.

required

current_stream(device=None)

Return the currently selected stream for a given device.

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Name Type Description
Stream Stream

The currently selected stream.

default_stream(device=None)

Return the default stream for a given device.

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Name Type Description
Stream Stream

The default stream.

stream(stream)

Return a context manager that selects the given stream.

Parameters:

Name Type Description Default
stream Stream or None

The stream to select. It is a no-op if None.

required

Returns:

Name Type Description
StreamContext StreamContext

A context manager that restores the previously selected stream on exit.

Example
1
2
3
s = torch.rbln.Stream()
with torch.rbln.stream(s):
    y = x * 2

set_stream(stream)

Select a stream for all subsequent work, and select its device as well.

This sets the stream for the remainder of the calling thread. Prefer the stream context manager, which restores the previous stream on exit.

Parameters:

Name Type Description Default
stream Stream or None

The stream to select. It is a no-op if None.

required

Memory

Statistics APIs report device memory managed by the caching allocator. Because device allocations are lazy, a tensor created on rbln does not count until a device operation materializes it; see Execution Semantics. On Rebel100™ a card is one chip with four chiplets and the allocator tracks each chiplet separately: memory_summary() and memory_stats_per_chiplet() expose that breakdown, while the other statistics aggregate across chiplets (see Execution Semantics › Rebel100™ and ATOM™). mem_get_info() and mem_get_info_per_chiplet() are the exception: they report device memory as the kernel driver sees it, across every process, rather than what this process's allocator holds.

API torch.cuda counterpart Summary
torch.rbln.memory_allocated(device=None) memory_allocated Bytes currently occupied by tensors on the device.
torch.rbln.max_memory_allocated(device=None) max_memory_allocated Peak bytes occupied by tensors since the last peak reset.
torch.rbln.memory_reserved(device=None) memory_reserved Bytes currently managed by the caching allocator, including cached free blocks.
torch.rbln.max_memory_reserved(device=None) max_memory_reserved Peak bytes managed by the caching allocator.
torch.rbln.memory_stats(device=None) memory_stats Dictionary of allocator statistics with dotted keys such as allocated.current, allocated.peak, reserved.current, active.peak.
torch.rbln.memory_stats_per_chiplet(device=None) — The same statistics broken down per chiplet, each key prefixed with npu.<n>.chiplet.<c>.. A device runs out of memory on its heaviest chiplet, which the aggregate hides.
torch.rbln.memory_summary(device=None) memory_summary Human-readable table of the allocator statistics, one row per NPU and chiplet of the logical device.
torch.rbln.mem_get_info(device=None) mem_get_info (free, total) device memory in bytes as the driver reports it, across every process. Same figures as torch.accelerator.get_memory_info for rbln. total sits below the card's nominal memory. Raises when no RBLN device is present, on a dummy device, or when the installed driver lacks the query.
torch.rbln.mem_get_info_per_chiplet(device=None) — The driver figures per chiplet (npu.<n>.chiplet.<c>.{total,used,free,largest_free,largest_free_huge}) and per NPU (npu.<n>.{total,used,free,granularity,huge_granularity}). npu.<n> is the NPU's position in the logical device, not a physical NPU id. A contiguous buffer is bounded by one chiplet's largest_free, which the device-wide free hides.
torch.rbln.reset_peak_memory_stats(device=None) reset_peak_memory_stats Reset the peak counters.
torch.rbln.reset_accumulated_memory_stats(device=None) reset_accumulated_memory_stats Reset the accumulated (historical) counters.
torch.rbln.empty_cache(device=None) empty_cache Release unoccupied cached device memory. Also drops the compiled-program warm cache and view-recipe caches, so it releases everything the caller no longer holds.
torch.rbln.bind_device_memory(tensor) — Materialize a tensor's device allocation immediately instead of on first use. Required before handing a buffer to a consumer that reads device memory out of band, such as a collective library or direct-storage DMA. The tensor must cover its whole storage.
torch.rbln.set_device_layout_like(target, ref) — Make target adopt the device-allocation layout of the device-resident tensor ref without copying, so later device-to-device copies between them stay on the fast path. Both must be RBLN tensors of the same dtype on the same device.
torch.rbln.huge_host_empty(nbytes) — Allocate a 2 MiB-aligned, prefaulted host buffer the device can DMA into without a staging copy. Returns a zero-filled 1-D uint8 CPU tensor. Transparent huge pages are requested on a best-effort basis.
torch.rbln.offload() — Context manager that enables file offloading for host-side regions backing RBLN tensors allocated inside the block. Nested blocks are reference-counted. Offload files live under RBLN_OFFLOAD_DIR (default $HOME/.cache/rbln_cache/offload).
torch.rbln.release_offload_temp_storage() — Remove this process's offload temp files. Call on a shutdown path that may be killed before the runtime's own cleanup. Offloaded tensors must not be used afterwards. Returns the number of files removed.

memory_allocated(device=None)

Return the current device memory occupied by tensors in bytes for a given device.

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Name Type Description
int int

The current memory occupied by tensors in bytes.

Note

This function reflects device memory only. For information about lazy memory allocation, see memory_stats().

max_memory_allocated(device=None)

Return the maximum device memory occupied by tensors in bytes for a given device.

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Name Type Description
int int

The maximum memory occupied by tensors in bytes.

Note

This function reflects device memory only. For information about lazy memory allocation, see memory_stats().

memory_reserved(device=None)

Return the current device memory managed by the caching allocator in bytes for a given device.

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Name Type Description
int int

The current memory managed by the caching allocator in bytes.

Note

This function reflects device memory only. For information about lazy memory allocation, see memory_stats().

max_memory_reserved(device=None)

Return the maximum device memory managed by the caching allocator in bytes for a given device.

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Name Type Description
int int

The maximum memory managed by the caching allocator in bytes.

Note

This function reflects device memory only. For information about lazy memory allocation, see memory_stats().

memory_stats(device=None)

Return a dictionary of device memory allocator statistics for a given device.

The returned dictionary contains various memory statistics including:

  • allocated.current: Current memory occupied by tensors
  • allocated.peak: Peak memory occupied by tensors
  • allocated.total_allocated: Total memory allocated to tensors (cumulative)
  • allocated.total_freed: Total memory freed from tensors (cumulative)
  • reserved.current: Current memory managed by the caching allocator
  • reserved.peak: Peak memory managed by the caching allocator
  • reserved.total_allocated: Total memory allocated by the caching allocator (cumulative)
  • reserved.total_freed: Total memory freed by the caching allocator (cumulative)
  • active.current: Current size of blocks in use (may differ from allocated due to block granularity)
  • active.peak: Peak size of blocks in use
  • cached.current: Current size of cached blocks available for reuse
  • cached.peak: Peak size of cached blocks
  • num_alloc_retries: Number of allocation retries after cache flush
  • num_ooms: Number of out-of-memory errors
  • num_device_alloc: Number of device memory acquisitions
  • num_device_free: Number of device memory releases

Lazy Tensor Memory Allocation: All memory-related functions in this module (including memory_allocated(), memory_reserved(), max_memory_allocated(), max_memory_reserved(), and this function) reflect device memory only, not CPU memory.

RBLN tensors use lazy memory allocation for device memory. When you create a tensor on an RBLN device:

  • The tensor is initially allocated in CPU memory immediately upon creation
  • Device memory allocation is deferred until the tensor is actually needed for device operations
  • When a device operation is required, the tensor data is lazily transferred from CPU to device memory

This lazy allocation strategy means that memory statistics may be lower than expected immediately after tensor creation until the tensors are used in device computations. Device memory statistics will increase when tensors are materialized on the device during actual computation.

The statistics also include lazy tensor related metrics, which provide insights into the memory management for tensors that have not yet been materialized on the device. The specific lazy tensor statistics fields may vary depending on the implementation version.

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Type Description
Dict[str, int]

Dict[str, int]: A dictionary containing device memory statistics. Note that these statistics reflect device memory only (not CPU memory) and may not include memory for tensors that have not yet been transferred to the device.

Note

To see accurate device memory usage, check statistics after performing operations that require the tensors to be materialized on the device, as device memory is allocated lazily when needed. This applies to all memory-related functions in this module.

memory_stats_per_chiplet(device=None)

Return memory allocator statistics broken down per chiplet.

Same keys as memory_stats(), each prefixed with npu.<n>.chiplet.<c>. -- e.g. npu.0.chiplet.0.allocated.current. A device runs out on its heaviest chiplet, which the aggregate memory_stats() hides.

npu.<n> is the n-th physical NPU of this logical device (RBLN_NPUS_PER_DEVICE / RBLN_DEVICE_MAP), not a physical NPU id; a 1:1 mapping yields npu.0 only. Same scope as memory_stats().

Parameters:

Name Type Description Default
device Optional[Union[int, str, device]]

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Type Description
Dict[str, int]

Dict[str, int]: A dictionary containing per-chiplet memory statistics.

memory_summary(device=None)

Return a human-readable printout of the current memory allocator statistics.

Rows are per (NPU, chiplet), so an imbalance is visible at a glance. The scope line under the title names what the numbers cover: they are this process's allocator, not the NPU's occupancy (see memory_stats()). The npu column is the physical NPU id as torch.rbln.device_summary() prints it: relative to RBLN_VISIBLE_DEVICES, so it differs from rbln-smi when that variable is set. A logical device grouping several NPUs (RBLN_NPUS_PER_DEVICE / RBLN_DEVICE_MAP) gets one row per NPU.

Peaks are tracked per chiplet, so the peak columns of the total row bound the joint peak from above rather than reporting it. memory_stats() carries the exact joint peak.

Parameters:

Name Type Description Default
device Optional[Union[int, str, device]]

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Name Type Description
str str

The formatted table, or a short notice when no stats are available.

mem_get_info(device=None)

Return the free and total device DRAM of device in bytes, as (free, total).

Same contract as torch.cuda.mem_get_info, and what torch.accelerator.get_memory_info reports for rbln: the NPU's figures as the kernel driver sees them, across every process, not this process's caching allocator, which memory_stats() covers. total is the pool the driver can hand out, so it sits below the part's nominal DRAM. A logical device spanning several physical NPUs (RBLN_NPUS_PER_DEVICE / RBLN_DEVICE_MAP) reports their sum; one tensor still lives on one NPU. The result is a reading, not a reservation: another process may allocate right after.

Parameters:

Name Type Description Default
device Optional[Union[int, str, device]]

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Type Description
Tuple[int, int]

Tuple[int, int]: (free, total) in bytes.

Raises:

Type Description
RuntimeError

if there is no RBLN device, the device is a dummy device, or the installed driver does not provide the device memory query.

mem_get_info_per_chiplet(device=None)

Return the driver's device DRAM usage of device broken down per chiplet, in bytes.

Same figures as mem_get_info() before summation, keyed like memory_stats_per_chiplet(): npu.<n>.chiplet.<c>.{total,used,free,largest_free, largest_free_huge} for each chiplet, and npu.<n>.{total,used,free,granularity, huge_granularity} for each physical NPU of the logical device. npu.<n> is the NPU's position within the logical device, not a physical NPU id.

Each chiplet allocates from its own pool, so a physically contiguous buffer is bounded by one chiplet's largest_free (largest_free_huge for the huge granule; 0 where the part has none), which the device-wide free hides. largest_free may exceed free in the same reply: both are estimates from a lock-free walk.

Parameters:

Name Type Description Default
device Optional[Union[int, str, device]]

The device to query. If None, uses the current device. Defaults to None.

None

Returns:

Type Description
Dict[str, int]

Dict[str, int]: A map from key to bytes.

Raises:

Type Description
RuntimeError

under the same conditions as mem_get_info().

reset_peak_memory_stats(device=None)

Reset the "peak" stats tracked by the caching allocator for a given device.

This function resets the peak values to their current values for the following stats:

  • allocated.peak: Reset to allocated.current
  • reserved.peak: Reset to reserved.current
  • active.peak: Reset to active.current
  • cached.peak: Reset to cached.current

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to reset stats for. If None, uses the current device. Defaults to None.

None

reset_accumulated_memory_stats(device=None)

Reset the "accumulated" (historical) stats tracked by the caching allocator for a given device.

This function resets the following accumulated stats to zero:

  • allocated.total_allocated
  • allocated.total_freed
  • reserved.total_allocated
  • reserved.total_freed
  • num_alloc_retries
  • num_ooms
  • num_device_alloc
  • num_device_free

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to reset stats for. If None, uses the current device. Defaults to None.

None

empty_cache(device=None)

Release all unoccupied cached memory currently held by the caching allocator so that those can be used in other application.

Note that only unfragmented (non-split) blocks can be released; fragmented blocks that have been split will remain in the cache until they can be coalesced.

Parameters:

Name Type Description Default
device int, str, or torch.device

The device to empty cache for. If None, uses the current device. Defaults to None.

None

bind_device_memory(tensor)

Materialize tensor's device allocation instead of leaving it lazy.

A device allocation reserves a virtual address and materializes the physical memory behind it on first use through a torch op. A consumer that reads those physical buffers out of band, such as a collective library or direct storage (NVMe) DMA, never runs such an op, so it would find nothing there. Call this after allocating a buffer you are handing to one.

The region is laid out flat and 1:1 with no dtype transform, on the device's main node, which is what a consumer treating it as bytes expects. Use set_device_layout_like() instead when the layout has to match another tensor's. Binding an already-bound region is allowed.

Parameters:

Name Type Description Default
tensor Tensor

An RBLN tensor covering its whole storage: contiguous, with zero storage offset. A view that still spans the whole storage is fine; a slice or an interior view is not, since its address is not the allocation's.

required

Raises:

Type Description
RuntimeError

if tensor is not an RBLN tensor, does not cover its whole storage, or the runtime rejects the allocation.

Example
staging = torch.empty(nbytes, dtype=torch.uint8, device="rbln:0")
torch.rbln.bind_device_memory(staging)

set_device_layout_like(target, ref)

Configure target's device-allocation layout to match ref (no copy).

Both must be RBLN tensors with the same dtype, on the same device, and each covering its whole storage. ref must be device-resident. target adopts ref's layout and dtype while keeping its own size; no data is transferred. A subsequent device-to-device copy between target and ref then stays on the fast path.

Typical use: make a host→device staging buffer match a KV cache's layout so the bulk upload and the per-slot device-to-device scatter are both fast.

Parameters:

Name Type Description Default
target Tensor

The RBLN tensor whose device-allocation layout is configured.

required
ref Tensor

The device-resident RBLN tensor whose layout target adopts.

required

Raises:

Type Description
RuntimeError

if either tensor is not an RBLN tensor covering its whole storage, if the two are on different devices or have different dtypes, or if ref is not device-resident.

huge_host_empty(nbytes)

Allocate a host buffer the device can DMA into without a staging copy.

An ordinary CPU tensor is 64 B aligned; the runtime's copy path stages any host address that is not page aligned through a bounce buffer, and even an aligned one pays a page fault per 4 KiB the first time the runtime resolves its host addresses, a cost that lands in the transfer, not in setup. This returns 2 MiB-aligned memory instead, prefaulted, so neither happens. It also asks for transparent huge pages, but that part is best effort: with THP disabled the alignment still holds and nothing is huge-page backed.

The buffer is released when the last reference to the returned tensor (or to a view of it) goes away.

Parameters:

Name Type Description Default
nbytes int

Size of the buffer in bytes. Must be in 1..sys.maxsize.

required

Returns:

Type Description
Tensor

torch.Tensor: A zero-filled 1-D uint8 CPU tensor of nbytes bytes, sharing the buffer's memory rather than copying it.

Raises:

Type Description
TypeError

if nbytes is not an integer.

ValueError

if nbytes is outside 1..sys.maxsize.

MemoryError

if the allocation fails.

Example
slab = torch.rbln.huge_host_empty(1 << 30)
slab.view(...)  # hand to whatever consumes the host side

offload()

Context manager that enables RBLN file offloading for its scope.

Inside the with block, the process-wide file offloading switch is on, so host-side regions backing RBLN tensors allocated within the block may be paged out to disk. Use this around code paths that allocate large host-resident tensors (for example, KV-cache initialization) where host RAM pressure matters.

Nested offload blocks are tracked via a thread-safe depth counter; the switch is flipped back off only when the outermost context exits.

Example
with torch.rbln.offload():
    tensor = torch.zeros(1 << 30, device="rbln:0")  # offloaded

release_offload_temp_storage()

Remove this process's file offloading temp files and directories.

offload() writes into a per-process directory under RBLN_OFFLOAD_DIR (default $HOME/.cache/rbln_cache/offload) that the runtime removes on teardown. Call this on a shutdown path that may be killed first. Offloaded tensors must not be used afterwards.

Returns:

Name Type Description
int int

The number of temp files removed.

Explain and profiling

torch.rbln.explain() is a hidden-overhead explainer, not a timing profiler. It counts host round-trips, CPU fallbacks, and recompilations inside a region and attributes each to a cause. For wall-clock timing use torch.profiler. On Rebel100™ NPUs, with RBLN_PROFILER=1 set before the runtime starts, RBLN device activity reaches the trace through the Kineto bridge; on ATOM™ NPUs the bridge stays inactive and the trace shows host activity only (see Environment Variables › Profiling).

API Returns Summary
torch.rbln.explain(with_stack=False) RBLNExplain Context manager for a region you place. with_stack=True records the Python call site of the first fallback, recompile, or bounce per operator. trace= is a deprecated alias for with_stack=.
torch.rbln.explain_steady(fn, *, warmup=2, return_cold=False, as_diff=False, with_stack=False) RBLNExplain, (cold, warm), or RBLNDiff Calls fn once inside a region, warmup more times, then once more inside a second region, so first-call cost can be separated from steady state. Assumes fn was not run before and does the same work each call. as_diff=True returns the signal-by-signal change.
RBLNExplain.report() str Marker-first human-readable report: [clean] or [overhead: N signals], the signal table with Count, Bytes, Note, and per-signal detail blocks.
RBLNExplain.verdict() dict clean flag plus reasons; suitable for a CI gate.
RBLNExplain.dump() dict Every signal as raw numbers.
RBLNExplain.help(signal=None) str Full explanation of a signal, or of every signal that fired.
RBLNExplain.diff(other) RBLNDiff Compare two regions you placed.
RBLNExplain.start() / stop() — Manual region boundaries instead of with.
torch.rbln.profile, torch.rbln.RBLNProfile aliases Back-compatible aliases of explain and RBLNExplain.

Signals reported:

Signal Meaning Typical note
host_bounce/* A copy took a host round-trip (device → host → device) instead of a device-to-device path. Bytes is the host-path volume; the >> physical d2h line says whether bytes crossed the device boundary. make the tensor contiguous, or use a device-to-device copy path
runtime/v2v_slow A device-to-device copy used the slow path. Only observable when the loaded librbln.so exposes runtime counters. match layouts with set_device_layout_like
dispatch/cpu_fallback An operator ran on CPU, with per-operator counts and a why: line (dtype-not-fp16, nan/inf input, all-scalar inputs) and the operators that have no fast-path handler. Operators with no device kernel and operators pinned to CPU are not counted; the fallback log names them. use a supported dtype, or run under torch.compile
dispatch/recompile An operator or graph recompiled inside the region. stabilize shapes and dtypes

The report header also shows region wall time, peak reserved device memory, time spent inside the runtime by call type, and a warning when the process has more threads than CPU cores.

Three rules decide whether a report means anything:

  • One region at a time. Regions must not nest or overlap and must stay on one thread; opening a second region raises.
  • Wrap the whole step, not only the compiled forward. A compiled graph is clean by construction; the hidden work sits in the eager code around it.
  • A ! host oversubscription line means the process has more threads than cores, so host latency inside the region may be contention rather than any one operator. Fix affinity or OMP_NUM_THREADS before reading per-operator numbers. A missing runtime/v2v_slow row proves nothing when the header says runtime signals are not exposed.

RBLNExplain

A hidden-overhead explain region. Create one with explain() and use it as a context manager.

Regions must not overlap: the underlying counters and timers are process-global, so opening a nested or concurrent region raises a RuntimeError. The counters are also process-wide, meaning the values include activity from every thread that ran during the region, not only the calling thread.

report()

Render the human-readable report: a [clean] / [overhead: N signals] marker, a torch.profiler-style signal table with a Note column carrying the remedy for each actionable row, and per-signal detail blocks.

Returns:

Name Type Description
str str

The report text. Print this.

verdict()

Summarize the region as a clean flag plus the factual reasons behind it.

The result is intended for CI gating. clean states whether any hidden signal fired; it is not a severity grade.

Returns:

Type Description
Dict[str, Any]

Dict[str, Any]: A dictionary containing clean and reasons, among others.

dump()

Return every signal as raw numbers, for programmatic checks.

Returns:

Type Description
Dict[str, Any]

Dict[str, Any]: Host-bounce counts and bytes by site, dispatch counters (CPU fallbacks, recompilations, warm hits), per-operator breakdowns, runtime residency, and the region wall time.

start()

Open the region manually instead of entering with. Returns self.

stop()

Close a region opened with start(). Returns self.

help(signal=None)

Return the full remedy text for the signals that fired in the region.

Parameters:

Name Type Description Default
signal Optional[str]

A signal name, either the bare cause or the report label such as dispatch/cpu_fallback. Without it, the text covers every signal that fired. Defaults to None.

None

Returns:

Name Type Description
str str

The remedy text.

diff(other)

Compare this region with a later one, for example a first call against a steady-state call. A region records only what happened inside it, so it cannot separate one-time cost from recurring cost by itself; placing two regions is how that structure is supplied. See RBLNDiff.

Parameters:

Name Type Description Default
other RBLNExplain

The later region. The comparison runs from self to other.

required

Returns:

Name Type Description
RBLNDiff RBLNDiff

The signal-by-signal change between the two regions.

RBLNDiff(a, b)

The signal-by-signal change between two regions, from a to b.

A region records only what happened inside it, so on its own it cannot separate a one-time cost from a recurring one. Placing the two regions, for example around a first call and a later steady-state call, supplies that structure. The diff reports only what changed between the two points: a signal that is zero in b did not recur, and a signal that persists is overhead that recurs between them. It makes no claim about anything outside the two regions.

Build the diff of two closed regions a and b; RBLNExplain.diff() calls this.

dump()

Return the diff as raw numbers.

The dictionary has the following shape:

1
2
3
4
5
6
7
8
{
    "signals": {name: {"a": int, "b": int, "a_bytes": int, "b_bytes": int}},
    "persists": [name, ...],   # present in b: the recurring, actionable set
    "gone": [name, ...],       # present in a only
    "appeared": [name, ...],   # present in b only
    "persists_by_op": [{"signal": ..., "op": ..., "count": ..., "at": ...}],
    "device_memory": {...},
}

a_bytes and b_bytes are present for byte-carrying signals only, so a recurring cost can be ranked by host-traffic volume as well as by count.

Returns:

Type Description
dict[str, Any]

dict[str, Any]: The diff as a dictionary.

report()

Human-readable diff table with one row per signal and a >> persists marker on the recurring ones.

explain(with_stack=False, *, trace=None)

Return a hidden-overhead explain region, usable as a context manager.

A normal PyTorch operation can silently round-trip the host (NPU to CPU to NPU), fall back to a CPU kernel, or trigger a recompilation. None of that is visible in your Python code. explain() counts those hidden events, attributes a cause and a remedy to each, and renders a torch.profiler-style report.

This is a hidden-overhead explainer, not a timing profiler: it does not report how long a forward pass took or which layer is slow. A region with no hidden overhead can still be slow because it is device-compute bound. For wall-clock timing, use torch.profiler.

Parameters:

Name Type Description Default
with_stack bool

If True, capture the Python call site of each fallback, recompilation, and host bounce (deduplicated per operator) and show it in the report. Off by default, so a plain region adds nothing to any code path. Defaults to False.

False

Returns:

Name Type Description
RBLNExplain RBLNExplain

A region object usable as a context manager.

Example
1
2
3
4
5
6
with torch.rbln.explain() as p:
    model(x)

print(p.report())  # [clean] / [overhead] marker plus a signal table
p.verdict()        # {'clean': bool, 'reasons': [...]} for CI gating
p.dump()           # every signal as raw numbers
Note

torch.rbln.profile and torch.rbln.RBLNProfile are backward-compatible aliases of explain and RBLNExplain. The trace= keyword is a deprecated alias for with_stack=.

explain_steady(fn, *, warmup=2, return_cold=False, as_diff=False, with_stack=False, trace=None)

Place two explain regions around fn: one around the first call it makes and one around a later call after warmup more calls.

The helper only automates region placement. Its cold and warm labels mean the first call it made and a later call it made, nothing more. Reading the result as one-time versus recurring cost rests on two assumptions that the caller has to guarantee, because the helper cannot verify them:

  1. fn was not run or compiled before this call. Otherwise the one-time cost happened before the cold sample and is not captured.
  2. Every fn() call does the same work. Otherwise the recompiles in the warm sample come from different shapes, not from recurring overhead.

When both hold, cold.diff(warm) shows what changed: signals gone in the warm region did not recur across the two calls, and signals that persist are the recurring overhead. The helper is plain Python orchestration and adds nothing to the hot path.

Parameters:

Name Type Description Default
fn Callable[[], Any]

The callable to observe. It is called warmup + 2 times in total.

required
warmup int

Number of calls between the two regions. Defaults to 2.

2
return_cold bool

Return (cold, warm) instead of the warm region alone. Defaults to False.

False
as_diff bool

Return cold.diff(warm), the signal-by-signal change, instead of a region. Defaults to False.

False
with_stack bool

Record the first Python call site per operator in both regions. Defaults to False.

False
trace Optional[bool]

Deprecated alias for with_stack. Defaults to None.

None

Returns:

Type Description
RBLNExplain | tuple[RBLNExplain, RBLNExplain] | RBLNDiff

RBLNExplain | tuple[RBLNExplain, RBLNExplain] | RBLNDiff: The warm region by default; (cold, warm) with return_cold=True; the RBLNDiff with as_diff=True.

Example
d = torch.rbln.explain_steady(lambda: model(x), warmup=2, as_diff=True)
print(d.report())  # signals marked as persisting recur across the two calls

Compiled programs

torch.compile keeps the callable a backend returns inside the Dynamo code cache, so your code never receives a handle to what was compiled. torch.rbln.capture_programs() opens a scope that records every program the rbln backend builds while it is open, in build order, the way torch.profiler.profile() collects the events inside it. Each captured program describes its inputs and outputs, including the device layout of dynamic-shape tensors.

1
2
3
4
5
6
7
8
9
with torch.rbln.capture_programs() as programs:
    compiled = torch.compile(model, backend="rbln")
    compiled(*warmup_inputs)  # Dynamo builds the graphs here

for program in programs:
    print(program.name, program.device)
    for spec in program.input_specs:
        if spec.physical_placement is not None:
            print(spec.name, spec.physical_placement.shards)
API Summary
torch.rbln.capture_programs() Context manager that yields a list[CompiledProgram], filled as torch.compile invokes the backend. Nested scopes each receive every program built while they are open. The scope is thread-local: it records only compilations on the thread that opened it.
torch.rbln.CompiledProgram One compiled graph: name (the Dynamo compile id, such as "0/0"), device, runtime (the execution handle behind the callable), input_specs, and output_specs.
torch.rbln.InputSpec, torch.rbln.OutputSpec One input or output: shape, dtype, and physical_placement, plus name for inputs. Listed in the order the runtime takes and returns them.
torch.rbln.PhysicalPlacement Device layout of a dynamic-shape input or output: physical shape, dtype, and shards. None on static-shape inputs and outputs.
torch.rbln.ShardPlacement One shard of that layout: node_id, chiplet_id, and slice_shape.

These classes are implemented in the RBLN Compiler and resolve on first access, so import torch does not load the compiler. They require the rebel-compiler release paired with this torch-rbln release (see Installation).

CompiledProgram(name, device, runtime, input_specs, output_specs) dataclass

One graph the rbln backend built for torch.compile.

Attributes:

Name Type Description
name str

Dynamo's compile id for the graph ("0/0", "0/1", ...); empty if the backend ran outside a Dynamo compile.

device Optional[device]

The logical RBLN device the graph's input tensors live on, where the runtime allocates its outputs; None when no input is an RBLN tensor.

runtime Any

The execution handle behind the compiled callable.

input_specs Tuple[InputSpec, ...]

The graph's inputs, in the order the runtime takes them.

output_specs Tuple[OutputSpec, ...]

The graph's outputs, in the order the runtime returns them.

InputSpec(name, shape, dtype, physical_placement=None) dataclass

An input of a compiled program.

Attributes:

Name Type Description
name str

The input's name in the compiled model; may be empty.

shape Tuple[int, ...]

The compiled extents.

dtype dtype or dtype

The element type.

physical_placement Optional[PhysicalPlacement]

The device layout of a dynamic-shape input; None for a static one.

OutputSpec(shape, dtype, physical_placement=None) dataclass

An output of a compiled program. The fields read as in InputSpec.

Attributes:

Name Type Description
shape Tuple[int, ...]

The compiled extents.

dtype dtype or dtype

The element type.

physical_placement Optional[PhysicalPlacement]

The device layout of a dynamic-shape output; None for a static one.

PhysicalPlacement(shape, dtype, shards) dataclass

Device layout of a dynamic-shape input or output: its physical shape, dtype, and the shards it is split into.

A static dimension is a plain int. A dynamic dimension is an expression written as nested tuples: ("symbol", name) is the dynamic-shape variable name, whose value is the size of the input dimension compiled as dynamic; ("prod", e1, e2, ...) and ("sum", e1, e2, ...) are the product and sum of their operands. Binding the variables to the current input sizes gives the concrete extent: [2, ("symbol", "s0"), 8] with s0 == 4 is [2, 4, 8]. The dynamic axis is never split across shards, so it appears as the same symbol in shape and in every shard's slice_shape.

Attributes:

Name Type Description
shape tuple

The physical shape on the device.

dtype str

The element type on the device.

shards Tuple[ShardPlacement, ...]

The shards the tensor is split into.

ShardPlacement(node_id, chiplet_id, slice_shape) dataclass

One device shard of a tensor: which (node, chiplet) holds it and the extent it holds.

Attributes:

Name Type Description
node_id int

The node that holds the shard.

chiplet_id int

The chiplet that holds the shard.

slice_shape tuple

The extent of the shard, one entry per dimension. A static dimension is an int; a dynamic dimension is an expression over the model's dynamic-shape variables (see PhysicalPlacement).

capture_programs()

Context manager that records the programs the rbln backend builds inside it.

torch.compile keeps the callable a backend returns inside Dynamo's code cache, so the caller never receives a handle to what was compiled. This scope yields a list that fills, in build order, as torch.compile invokes the backend, the way torch.profiler.profile() collects the events inside it.

Every open scope receives each program, so nested scopes see the same programs; an inner scope simply sees fewer. The scope is thread-local: it records the backend calls made from the thread that opened it.

Returns:

Type Description
Iterator[List[CompiledProgram]]

Iterator[List[CompiledProgram]]: The list of captured programs, as the with target.

Example
1
2
3
4
5
6
7
8
9
with torch.rbln.capture_programs() as programs:
    compiled = torch.compile(model, backend="rbln")
    compiled(*warmup_inputs)  # Dynamo builds the graphs here

for program in programs:
    print(program.name, program.device)
    for spec in program.input_specs:
        if spec.physical_placement is not None:
            print(spec.name, spec.physical_placement.shards)

Diagnostics

Command Summary
python -m torch_rbln.diagnose Print library search paths, package locations, every librbln.so candidate with the one that loaded, and the rebel ABI verdict.

Supported operations

In eager execution, operators reach RBLN NPUs through two implementation paths. The tables below describe operator support in eager execution, where each operator is dispatched on its own. Support inside a graph compiled with torch.compile(backend="rbln") is decided by the RBLN Compiler; see Supported Ops › PyTorch

Path How it runs Source of the list
Compiled kernel The operator is compiled by the RBLN Compiler on first use for its shape and dtype, then cached. Bindings are generated at build time from aten/src/ATen/native/native_functions.yaml. native_functions.yaml (dispatch: PrivateUse1)
Native kernel A C++ kernel in libtorch_rbln.so performs the operation directly through the runtime (copies, views, indexing). No compilation. aten/src/ATen/native/RBLNRegisterOps.cpp

Dtype policy

Dtype Compiled kernels Native kernels
float16, bfloat16 Run on the device Run on the device
float32, integer, bool, others CPU fallback Run on the device (copies, views, and indexing do not depend on dtype)

Scaled dot-product attention uses the same two device dtypes. No autocast dtypes are registered at this release, so torch.autocast does not apply to rbln. Mixed-dtype inputs whose type promotion would leave the device dtype set fall back to CPU.

Compiled operators

The following operators run on NPU kernels. Input requirements and limitations are listed in the notes.

Operator Torch API Note
aten::abs torch.abs
aten::add torch.add, + alpha supported
aten::sub torch.sub, - alpha supported
aten::mul torch.mul, *
aten::div torch.div, /
aten::neg torch.neg, unary -
aten::pow torch.pow, ** Scalar exponent only; a tensor exponent or a scalar base is pinned to CPU
aten::rsqrt torch.rsqrt
aten::log torch.log
aten::ceil torch.ceil
aten::floor torch.floor
aten::clamp torch.clamp Scalar bounds; tensor bounds are pinned to CPU
aten::sigmoid torch.sigmoid
aten::silu torch.nn.functional.silu
aten::_softmax torch.softmax, torch.nn.functional.softmax
aten::mm torch.mm, @
aten::bmm torch.bmm
aten::addmm torch.addmm
aten::linear torch.nn.functional.linear, torch.nn.Linear
aten::mean torch.mean
aten::max, aten::min torch.max, torch.min Full reductions; dim reductions are pinned to CPU
aten::maximum, aten::minimum torch.maximum, torch.minimum
aten::eq, ne, lt, le, gt, ge comparison operators
aten::logical_not torch.logical_not
aten::where torch.where
aten::masked_fill_ Tensor.masked_fill_, torch.masked_fill
aten::_scaled_dot_product_fused_attention_overrideable torch.nn.functional.scaled_dot_product_attention Selected by _fused_sdp_choice for rbln tensors

Native operators

These operators have C++ kernels in libtorch_rbln.so that call the runtime directly. They run for every dtype, because they move or describe data rather than compute on it.

Group Operators
Allocation and fill empty, empty_strided, zero_, fill_ (scalar value), clone, _efficientzerotensor, arange
Copy _copy_from, _copy_from_and_resize, _foreach_copy_, resize_, set_, _local_scalar_dense (.item())
Views (metadata only, no device work) view, _unsafe_view, _reshape_alias, as_strided, alias, unfold
Concatenation and repetition cat (and stack, which decomposes to cat), repeat_interleave
Indexing index_select, index_copy, index with one integer-tensor index on one axis (other forms fall back to CPU inside the kernel)

A device-to-device copy_ from a strided view is served on the device; Execution Semantics › Views and strided copies describes the two device paths and the one case that goes through the host.

Operators pinned to CPU

The following operators are registered explicitly to the CPU fallback path. They execute on the host with a device-to-host copy before and a host-to-device copy after, are logged at INFO level like any other fallback, and are unaffected by TORCH_RBLN_DISABLE_FALLBACK=unsupported_op, which only governs operators with no registration at all.

Group Operators
Random number generation uniform_, normal_, normal, random_, randperm, native_dropout
Elementwise sin, cos, exp, trunc, sign, sgn, signbit, relu, addcmul, fmod, clamp (tensor bounds), pow (scalar base or tensor exponent), nan_to_num, isnan, isposinf, isneginf, isin, equal
Bitwise and logical bitwise_and, bitwise_or, bitwise_xor, bitwise_not, logical_and, logical_or, logical_xor
Reductions and scans sum (dim list), all, any, cumsum, count_nonzero, linalg_vector_norm, argmax, max.dim, min.dim, topk
Indexing and scatter gather, scatter, index_add, index_fill_, _index_put_impl_, put_, masked_scatter_, masked_select, nonzero, fill_ (tensor value)
Shape flip, tril, triu, view_as_real
Normalization native_batch_norm
Linear algebra _linalg_svd

A pinned operator that appears in a model's hot path is a candidate for a device kernel; report it through Issue reporting. Several of them already have host fast paths (integer elementwise, fp32 mean over the last dimension, fp32 pow(x, 2), fp32 rsqrt) that skip the generic boxed dispatcher, which is why an RMSNorm variance computed in fp32 costs less than a generic fallback.

Operators outside the tables

  • Composite operators such as torch.stack decompose to the operators above (stack → cat) and inherit their path.
  • Advanced indexing with several index tensors (t[:, idx_a, :, idx_b]) is not covered by the native index kernel and runs on CPU.
  • Non-contiguous out= tensors are staged through a contiguous buffer and copied back, which adds one device allocation and copy. Pass a contiguous out= on hot paths.
  • Custom operators under torch.ops.rbln_custom_ops (paged attention kernels) are internal to the RBLN vLLM native path and are not a public API.

See also