Data#

group data

Typedefs

template<typename VAL, std::int32_t DIM = 1>
using Buffer = Legion::DeferredBuffer<VAL, DIM>#

A typed buffer class for intra-task temporary allocations.

Values in a buffer can be accessed by index expressions with Point objects, or via a raw pointer to the underlying allocation, which can be queried with the Buffer::ptr() method.

Buffer is an alias to Legion::DeferredBuffer.

Note on using temporary buffers in CUDA tasks:

We use Legion::DeferredBuffer, whose lifetime is not connected with the CUDA stream(s) used to launch kernels. The buffer is allocated immediately at the point when create_buffer() is called, whereas the kernel that uses it is placed on a stream, and may run at a later point. Normally a Legion::DeferredBuffer is deallocated automatically by Legion once all the kernels launched in the task are complete. However, a Legion::DeferredBuffer can also be deallocated immediately using Legion::DeferredBuffer::destroy(), which is useful for operations that want to deallocate intermediate memory as soon as possible. This deallocation is not synchronized with the task stream, i.e. it may happen before a kernel which uses the buffer has actually completed. This is safe as long as we use the same stream on all GPU tasks running on the same device (which is guaranteed by the current implementation of legate::cuda::StreamPool::get_stream()), because then all the actual uses of the buffer are done in order on the one stream. It is important that all library CUDA code uses legate::cuda::StreamPool::get_stream(), and all CUDA operations (including library calls) are enqueued on that stream exclusively. This analysis additionally assumes that no code outside of Legate is concurrently allocating from the eager pool, and that it’s OK for kernels to access a buffer even after it’s technically been deallocated.

Functions

template<typename VAL, std::int32_t DIM>
Buffer<VAL, DIM> create_buffer(const Point<DIM> &extents, Memory::Kind kind = Memory::Kind::NO_MEMKIND, std::size_t alignment = DEFAULT_ALIGNMENT)#

Creates a Buffer of specific extents.

Parameters:
  • extents – Extents of the buffer

  • kind – Kind of the target memory (optional). If not given, the runtime will pick automatically based on the executing processor

  • alignment – Alignment for the memory allocation (optional)

Returns:

A Buffer object

template<typename VAL>
Buffer<VAL> create_buffer(std::size_t size, Memory::Kind kind = Memory::Kind::NO_MEMKIND, std::size_t alignment = DEFAULT_ALIGNMENT)#

Creates a Buffer of a specific size. Always returns a 1D Buffer.

Parameters:
  • size – Size of the Buffer

  • kindMemory::Kind of the target memory (optional). If not given, the runtime will pick automatically based on the executing processor

  • alignment – Alignment for the memory allocation (optional)

Returns:

A 1D Buffer object

class ScopedAllocator#
#include <core/data/allocator.h>

A simple allocator backed by Buffer objects.

For each allocation request, this allocator creates a 1D Buffer of std::int8_t and returns the raw pointer to it. By default, all allocations are deallocated when the allocator is destroyed, and can optionally be made alive until the task finishes by making the allocator unscoped.

Public Functions

explicit ScopedAllocator(Memory::Kind kind, bool scoped = true, std::size_t alignment = DEFAULT_ALIGNMENT)#

Create a ScopedAllocator for a specific memory kind.

Parameters:
  • kindMemory::Kind of the memory on which the Buffer should be created

  • scoped – If true, the allocator is scoped; i.e., lifetimes of allocations are tied to the allocator’s lifetime. Otherwise, the allocations are alive until the task finishes (and unless explicitly deallocated).

  • alignment – Alignment for the allocations

void *allocate(std::size_t bytes)#

Allocates a contiguous buffer of the given Memory::Kind

When the allocator runs out of memory, the runtime will fail with an error message. Otherwise, the function returns a valid pointer.

See also

deallocate

Parameters:

bytes – Size of the allocation in bytes

Returns:

A raw pointer to the allocation

void deallocate(void *ptr)#

Deallocates an allocation. The input pointer must be one that was previously returned by an allocate() call, otherwise the code will fail with an error message.

See also

allocate

Parameters:

ptr – Pointer to the allocation to deallocate

class Impl#
class ExternalAllocation#
#include <core/data/external_allocation.h>

Descriptor for external allocations.

An ExternalAllocation is a handle to a memory allocation outside Legate’s memory management. ExternalAllocation objects are used when users want to create Legate stores from the existing allocations external to Legate. (See two overloads of Runtime::create_store() that take ExternalAllocations.)

ExternalAllocations can be tagged either read-only or mutable. In case of the latter, Legate guarantees that any updates to the store to which the allocation is attached are also visible via the allocation, wherever the updates are made, at the expense of block-waiting on tasks updating the store. No such propagation of changes happens for read-only external allocations.

The client code that creates an external allocation and attaches it to a Legate store must guarantee that the allocation stays alive until all the tasks accessing the store are finished. If the attached allocation was read-only, the code must not mutate the contents of the allocation while the tasks are still running. An external allocation attached to a store can be safely deallocated in two ways:

1) The client code calls the detach() method on the store before it dellocate the allocation. The detach() call makes sure that all outstanding operations on the store complete (see LogicalStore::detach()). 2) The client code can optionally pass in a deleter for the allocation, which will be invoked once the store is destroyed and the allocation is no longer in use.

Deleters don’t need to be idempotent; Legate makes sure that they will be invoked only once on the allocations. Deleters must not throw exceptions (throwable deleters are disallowed by the type system). Deleters need not handle null pointers correctly, as external allocations are not allowed to be created on null pointers. Each deleter is responsible for deallocating only the allocation it is associated with and no other allocations.

Public Types

using Deleter = void (*)(void*) noexcept#

Signature for user-supplied deletion function.

Public Functions

bool read_only() const#

Indicates if the allocation is read-only.

Returns:

true If the allocation is read-only

Returns:

false Otherwise

mapping::StoreTarget target() const#

Returns the kind of memory to which the allocation belongs.

Returns:

Memory kind in a mapping::StoreTarget

void *ptr() const#

Returns the beginning address of the allocation.

Returns:

Address to the allocation

std::size_t size() const#

Returns the allocation size in bytes.

Returns:

Allocation size in bytes

Public Static Functions

static ExternalAllocation create_sysmem(void *ptr, std::size_t size, bool read_only = true, std::optional<Deleter> deleter = std::nullopt)#

Creates an external allocation for a system memory.

Parameters:
  • ptr – Pointer to the allocation

  • size – Size of the allocation in bytes

  • read_only – Indicates if the allocation is read-only

  • deleter – Optional deleter for the passed allocation. If none is given, the user is responsible for the deallocation.

Throws:

std::invalid_argument – If the ptr is null

Returns:

An external allocation

static ExternalAllocation create_sysmem(const void *ptr, std::size_t size, std::optional<Deleter> deleter = std::nullopt)#

Creates a read-only external allocation for a system memory.

Parameters:
  • ptr – Pointer to the allocation

  • size – Size of the allocation in bytes

  • deleter – Optional deleter for the passed allocation. Passing a deleter means that the ownership of the allocation is transferred to the Legate runtime. If none is given, the user is responsible for the deallocation.

Throws:

std::invalid_argument – If the ptr is null

Returns:

An external allocation

static ExternalAllocation create_zcmem(void *ptr, std::size_t size, bool read_only = true, std::optional<Deleter> deleter = std::nullopt)#

Creates an external allocation for a zero-copy memory.

Parameters:
  • ptr – Pointer to the allocation

  • size – Size of the allocation in bytes

  • read_only – Indicates if the allocation is read-only

  • deleter – Optional deleter for the passed allocation. Passing a deleter means that the ownership of the allocation is transferred to the Legate runtime. If none is given, the user is responsible for the deallocation.

Throws:
  • std::invalid_argument – If the ptr is null

  • std::runtime_error – If Legate is not configured with CUDA support enabled

Returns:

An external allocation

static ExternalAllocation create_zcmem(const void *ptr, std::size_t size, std::optional<Deleter> deleter = std::nullopt)#

Creates a read-only external allocation for a zero-copy memory.

Parameters:
  • ptr – Pointer to the allocation

  • size – Size of the allocation in bytes

  • deleter – Optional deleter for the passed allocation. Passing a deleter means that the ownership of the allocation is transferred to the Legate runtime. If none is given, the user is responsible for the deallocation.

Throws:
  • std::invalid_argument – If the ptr is null

  • std::runtime_error – If Legate is not configured with CUDA support enabled

Returns:

An external allocation

static ExternalAllocation create_fbmem(std::uint32_t local_device_id, void *ptr, std::size_t size, bool read_only = true, std::optional<Deleter> deleter = std::nullopt)#

Creates an external allocation for a framebuffer memory.

Parameters:
  • local_device_id – Local device ID

  • ptr – Pointer to the allocation

  • size – Size of the allocation in bytes

  • read_only – Indicates if the allocation is read-only

  • deleter – Optional deleter for the passed allocation. Passing a deleter means that the ownership of the allocation is transferred to the Legate runtime. If none is given, the user is responsible for the deallocation.

Throws:
  • std::invalid_argument – If the ptr is null

  • std::runtime_error – If Legate is not configured with CUDA support enabled

  • std::out_of_range – If the local device ID is invalid

Returns:

An external allocation

static ExternalAllocation create_fbmem(std::uint32_t local_device_id, const void *ptr, std::size_t size, std::optional<Deleter> deleter = std::nullopt)#

Creates a read-only external allocation for a framebuffer memory.

Parameters:
  • local_device_id – Local device ID

  • ptr – Pointer to the allocation

  • size – Size of the allocation in bytes

  • deleter – Optional deleter for the passed allocation. Passing a deleter means that the ownership of the allocation is transferred to the Legate runtime. If none is given, the user is responsible for the deallocation.

Throws:
  • std::invalid_argument – If the ptr is null

  • std::runtime_error – If Legate is not configured with CUDA support enabled

  • std::out_of_range – If the local device ID is invalid

Returns:

An external allocation

class InlineAllocation#
#include <core/data/inline_allocation.h>

An object representing the raw memory and strides held by a PhysicalStore

Public Members

void *ptr = {}#

pointer to the start of the allocation

std::vector<std::size_t> strides = {}#

vector of offsets into the buffer

class LogicalArray#
#include <core/data/logical_array.h>

A multi-dimensional array.

Subclassed by legate::ListLogicalArray, legate::StringLogicalArray

Public Functions

std::uint32_t dim() const#

Returns the number of dimensions of the array.

Returns:

The number of dimensions

Type type() const#

Returns the element type of the array.

Returns:

Type of elements in the store

Shape shape() const#

Returns the Shape of the array.

Returns:

The store’s Shape

inline const tuple<std::uint64_t> &extents() const#

Returns the extents of the array.

The call can block if the array is unbound

Returns:

The store’s extents

std::size_t volume() const#

Returns the number of elements in the array.

The call can block if the array is unbound

Returns:

The number of elements in the store

bool unbound() const#

Indicates whether the array is unbound.

Returns:

true if the array is unbound, false if it is normal

bool nullable() const#

Indicates whether the array is nullable.

Returns:

true if the array is nullable, false otherwise

bool nested() const#

Indicates whether the array has child arrays.

Returns:

true if the array has child arrays, false otherwise

std::uint32_t num_children() const#

Returns the number of child sub-arrays.

Returns:

Number of child sub-arrays

LogicalArray promote(std::int32_t extra_dim, std::size_t dim_size) const#

Adds an extra dimension to the array.

The call can block if the array is unbound

Parameters:
  • extra_dim – Position for a new dimension

  • dim_size – Extent of the new dimension

Throws:
  • std::invalid_argument – When extra_dim is not a valid dimension name

  • std::runtime_error – If the array or any of the sub-arrays is a list array

Returns:

A new array with an extra dimension

LogicalArray project(std::int32_t dim, std::int64_t index) const#

Projects out a dimension of the array.

The call can block if the array is unbound

Parameters:
  • dim – Dimension to project out

  • index – Index on the chosen dimension

Throws:
  • std::invalid_argument – If dim is not a valid dimension name or index is out of bounds

  • std::runtime_error – If the array or any of the sub-arrays is a list array

Returns:

A new array with one fewer dimension

LogicalArray slice(std::int32_t dim, Slice sl) const#

Slices a contiguous sub-section of the array.

The call can block if the array is unbound

Parameters:
  • dim – Dimension to slice

  • slSlice descriptor

Throws:
  • std::invalid_argument – If dim is not a valid dimension name

  • std::runtime_error – If the array or any of the sub-arrays is a list array

Returns:

A new array that corresponds to the sliced section

LogicalArray transpose(const std::vector<std::int32_t> &axes) const#

Reorders dimensions of the array.

The call can block if the array is unbound

Parameters:

axes – Mapping from dimensions of the resulting array to those of the input

Throws:
  • std::invalid_argument – If any of the following happens: 1) The length of axes doesn’t match the array’s dimension; 2) axes has duplicates; 3) Any axis in axes is an invalid axis name.

  • std::runtime_error – If the array or any of the sub-arrays is a list array

Returns:

A new array with the dimensions transposed

LogicalArray delinearize(std::int32_t dim, const std::vector<std::uint64_t> &sizes) const#

Delinearizes a dimension into multiple dimensions.

The call can block if the array is unbound

Parameters:
  • dim – Dimension to delinearize

  • sizes – Extents for the resulting dimensions

Throws:
  • std::invalid_argument – If dim is invalid for the array or sizes does not preserve the extent of the chosen dimenison

  • std::runtime_error – If the array or any of the sub-arrays is a list array

Returns:

A new array with the chosen dimension delinearized

LogicalStore data() const#

Returns the store of this array.

Returns:

LogicalStore

LogicalStore null_mask() const#

Returns the null mask of this array.

Returns:

LogicalStore

LogicalArray child(std::uint32_t index) const#

Returns the sub-array of a given index.

Parameters:

index – Sub-array index

Throws:
  • std::invalid_argument – If the array has no child arrays, or the array is an unbound struct array

  • std::out_of_range – If the index is out of range

Returns:

LogicalArray

PhysicalArray get_physical_array() const#

Creates a PhysicalArray for this LogicalArray

This call blocks the client’s control flow and fetches the data for the whole array to the current node

Returns:

A PhysicalArray of the LogicalArray

ListLogicalArray as_list_array() const#

Casts this array as a ListLogicalArray

Throws:

std::invalid_argument – If the array is not a list array

Returns:

The array as a ListLogicalArray

StringLogicalArray as_string_array() const#

Casts this array as a StringLogicalArray

Throws:

std::invalid_argument – If the array is not a string array

Returns:

The array as a StringLogicalArray

class ListLogicalArray : public legate::LogicalArray#
#include <core/data/logical_array.h>

A multi-dimensional array representing a list of values.

Public Functions

LogicalArray descriptor() const#

Returns the sub-array for descriptors.

Returns:

Sub-array’s for descriptors

LogicalArray vardata() const#

Returns the sub-array for variable size data.

Returns:

LogicalArray of variable sized data

class StringLogicalArray : public legate::LogicalArray#
#include <core/data/logical_array.h>

A multi-dimensional array representing a string.

Public Functions

LogicalArray offsets() const#

Returns the sub-array for offsets.

Returns:

LogicalArray of offsets into this array

LogicalArray chars() const#

Returns the sub-array for characters.

Returns:

LogicalArray representing the characters of the string

class LogicalStore#
#include <core/data/logical_store.h>

A multi-dimensional data container.

LogicalStore is a multi-dimensional data container for fixed-size elements. Stores are internally partitioned and distributed across the system. By default, Legate clients need not create nor maintain the partitions explicitly, and the Legate runtime is responsible for managing them. Legate clients can control how stores should be partitioned for a given task by attaching partitioning constraints to the task (see the constraint module for partitioning constraint APIs).

Each LogicalStore object is a logical handle to the data and is not immediately associated with a physical allocation. To access the data, a client must “map” the store to a physical store (PhysicalStore). A client can map a store by passing it to a task, in which case the task body can see the allocation, or calling LogicalStore::get_physical_store(), which gives the client a handle to the physical allocation (see PhysicalStore for details about physical stores).

Normally, a LogicalStore gets a fixed Shape upon creation. However, there is a special type of logical stores called “unbound” stores whose shapes are unknown at creation time. (see Runtime for the logical store creation API.) The shape of an unbound store is determined by a task that first updates the store; upon the submission of the task, the LogicalStore becomes a normal store. Passing an unbound store as a read-only argument or requesting a PhysicalStore of an unbound store are invalid.

One consequence due to the nature of unbound stores is that querying the shape of a previously unbound store can block the client’s control flow for an obvious reason; to know the shape of the LogicalStore whose Shape was unknown at creation time, the client must wait until the updater task to finish. However, passing a previously unbound store to a downstream operation can be non-blocking, as long as the operation requires no changes in the partitioning and mapping for the LogicalStore.

Public Functions

std::uint32_t dim() const#

Returns the number of dimensions of the store.

Returns:

The number of dimensions

bool has_scalar_storage() const#

Indicates whether the store’s storage is optimized for scalars.

Returns:

true The store is backed by a scalar storage

Returns:

false The store is a backed by a normal region storage

bool overlaps(const LogicalStore &other) const#

Indicates whether this store overlaps with a given store.

Returns:

true The stores overlap

Returns:

false The stores are disjoint

Type type() const#

Returns the element type of the store.

Returns:

Type of elements in the store

Shape shape() const#

Returns the shape of the array.

Returns:

The store’s Shape

inline const tuple<std::uint64_t> &extents() const#

Returns the extents of the store.

The call can block if the store is unbound

Returns:

The store’s extents

std::size_t volume() const#

Returns the number of elements in the store.

The call can block if the store is unbound

Returns:

The number of elements in the store

bool unbound() const#

Indicates whether the store is unbound.

Returns:

true if the store is unbound, false otherwise

bool transformed() const#

Indicates whether the store is transformed.

Returns:

true if the store is transformed, false otherwise

LogicalStore promote(std::int32_t extra_dim, std::size_t dim_size) const#

Adds an extra dimension to the store.

Value of extra_dim decides where a new dimension should be added, and each dimension \(i\), where \(i\) >= extra_dim, is mapped to dimension \(i+1\) in a returned store. A returned store provides a view to the input store where the values are broadcasted along the new dimension.

For example, for a 1D store A contains [1, 2, 3], A.promote(0, 2) yields a store equivalent to:

[[1, 2, 3],
 [1, 2, 3]]

whereas A.promote(1, 2) yields:

[[1, 1],
 [2, 2],
 [3, 3]]

The call can block if the store is unbound

Parameters:
  • extra_dim – Position for a new dimension

  • dim_size – Extent of the new dimension

Throws:

std::invalid_argument – When extra_dim is not a valid dimension name

Returns:

A new store with an extra dimension

LogicalStore project(std::int32_t dim, std::int64_t index) const#

Projects out a dimension of the store.

Each dimension \(i\), where \(i\) > dim, is mapped to dimension \(i-1\) in a returned store. A returned store provides a view to the input store where the values are on hyperplane \(x_\mathtt{dim} = \mathtt{index}\).

For example, if a 2D store A contains [[1, 2], [3, 4]], A.project(0, 1) yields a store equivalent to [3, 4], whereas A.project(1, 0) yields [1, 3].

The call can block if the store is unbound

Parameters:
  • dim – Dimension to project out

  • index – Index on the chosen dimension

Throws:

std::invalid_argument – If dim is not a valid dimension name or index is out of bounds

Returns:

A new store with one fewer dimension

LogicalStore slice(std::int32_t dim, Slice sl) const#

Slices a contiguous sub-section of the store.

For example, consider a 2D store A:

[[1, 2, 3],
 [4, 5, 6],
 [7, 8, 9]]

A slicing A.slice(0, legate::Slice{1}) yields

[[4, 5, 6],
 [7, 8, 9]]

The result store will look like this on a different slicing call A.slice(1, legate::Slice{legate::Slice::OPEN, 2}):

[[1, 2],
 [4, 5],
 [7, 8]]

Finally, chained slicing calls

A.slice(0, legate::Slice{1})
 .slice(1, legate::Slice{legate::Slice::OPEN, 2})

results in:

[[4, 5],
 [7, 8]]

The call can block if the store is unbound

Parameters:
  • dim – Dimension to slice

  • slSlice descriptor

Throws:

std::invalid_argument – If dim is not a valid dimension name

Returns:

A new store that corresponds to the sliced section

LogicalStore transpose(std::vector<std::int32_t> &&axes) const#

Reorders dimensions of the store.

Dimension \(i\)i of the resulting store is mapped to dimension axes[i] of the input store.

For example, for a 3D store A

[[[1, 2],
  [3, 4]],
 [[5, 6],
  [7, 8]]]

transpose calls A.transpose({1, 2, 0}) and A.transpose({2, 1, 0}) yield the following stores, respectively:

[[[1, 5],
  [2, 6]],
 [[3, 7],
  [4, 8]]]
[[[1, 5],
 [3, 7]],

 [[2, 6],
  [4, 8]]]

The call can block if the store is unbound

Parameters:

axes – Mapping from dimensions of the resulting store to those of the input

Throws:

std::invalid_argument – If any of the following happens: 1) The length of axes doesn’t match the store’s dimension; 2) axes has duplicates; 3) Any axis in axes is an invalid axis name.

Returns:

A new store with the dimensions transposed

LogicalStore delinearize(std::int32_t dim, std::vector<std::uint64_t> sizes) const#

Delinearizes a dimension into multiple dimensions.

Each dimension \(i\) of the store, where \(i >\) dim, will be mapped to dimension \(i+N\) of the resulting store, where \(N\) is the length of sizes. A delinearization that does not preserve the size of the store is invalid.

For example, consider a 2D store A

[[1, 2, 3, 4],
 [5, 6, 7, 8]]

A delinearizing call A.delinearize(1, {2, 2})) yields:

[[[1, 2],
  [3, 4]],

 [[5, 6],
  [7, 8]]]

Unlike other transformations, delinearization is not an affine transformation. Due to this nature, delinearized stores can raise legate::NonInvertibleTransformation in places where they cannot be used.

The call can block if the store is unbound

Parameters:
  • dim – Dimension to delinearize

  • sizes – Extents for the resulting dimensions

Throws:

std::invalid_argument – If dim is invalid for the store or sizes does not preserve the extent of the chosen dimenison

Returns:

A new store with the chosen dimension delinearized

LogicalStorePartition partition_by_tiling(std::vector<std::uint64_t> tile_shape) const#

Creates a tiled partition of the store.

The call can block if the store is unbound

Parameters:

tile_shape – Shape of tiles

Returns:

A store partition

PhysicalStore get_physical_store() const#

Creates a PhysicalStore for this LogicalStore

This call blocks the client’s control flow and fetches the data for the whole store to the current node

Returns:

A PhysicalStore of the LogicalStore

void detach()#

Detach a store from its attached memory.

This call will wait for all operations that use the store (or any sub-store) to complete.

After this call returns, it is safe to deallocate the attached external allocation. If the allocation was mutable, the contents would be up-to-date upon the return. The contents of the store are invalid after that point.

bool equal_storage(const LogicalStore &other) const#

Determine whether two stores refer to the same memory.

This routine can be used to determine whether two seemingly unrelated stores refer to the same logical memory region, including through possible transformations in either this or other.

The user should note that some transformations do modify the underlying storage. For example, the store produced by slicing will not share the same storage as its parent, and this routine will return false for it:

  const auto store       = runtime->create_store(legate::Shape{4, 3}, legate::int64());
  const auto transformed = store.slice(1, legate::Slice{-2, -1});

  // Slices partition a store into a parent and sub-store which both cover distinct regions,
  // and hence don't share storage.
  EXPECT_FALSE(store.equal_storage(transformed));

Transposed stores, on the other hand, still share the same storage, and hence this routine will return true for them:

  const auto store       = runtime->create_store(legate::Shape{4, 3}, legate::int64());
  const auto transformed = store.transpose({1, 0});

  // Transposing a store doesn't modify the storage
  EXPECT_TRUE(store.equal_storage(transformed));
Parameters:

other – The LogicalStore to compare with.

Returns:

true if two stores cover the same underlying memory region, false otherwise.

class PhysicalArray#
#include <core/data/physical_array.h>

A multi-dimensional array abstraction for fixed- or variable-size elements.

PhysicalArrays can be backed by one or more PhysicalStores, depending on their types.

Subclassed by legate::ListPhysicalArray, legate::StringPhysicalArray

Public Functions

bool nullable() const noexcept#

Indicates if the array is nullable.

Returns:

true if the array is nullable, false otherwise

std::int32_t dim() const noexcept#

Returns the dimension of the array.

Returns:

Array’s dimension

Type type() const noexcept#

Returns the array’s Type

Returns:

Type

bool nested() const noexcept#

Indicates if the array has child arrays.

Returns:

true if the array has child arrays, false otherwise

PhysicalStore data() const#

Returns the store containing the array’s data.

Throws:

std::invalid_argument – If the array is not a base array

Returns:

PhysicalStore

PhysicalStore null_mask() const#

Returns the store containing the array’s null mask.

Throws:

std::invalid_argument – If the array is not nullable

Returns:

PhysicalStore

PhysicalArray child(std::uint32_t index) const#

Returns the sub-array of a given index.

Parameters:

index – Sub-array index

Throws:
  • std::invalid_argument – If the array has no child arrays

  • std::out_of_range – If the index is out of range

Returns:

Sub-PhysicalArray at the given index

template<std::int32_t DIM>
Rect<DIM> shape() const#

Returns the array’s shape.

Returns:

Array’s shape

Domain domain() const#

Returns the array’s Domain.

Returns:

Array’s Domain

ListPhysicalArray as_list_array() const#

Casts this array as a ListPhysicalArray

Throws:

std::invalid_argument – If the array is not a list array

Returns:

This array as a ListPhysicalArray

StringPhysicalArray as_string_array() const#

Casts this array as a StringPhysicalArray

Throws:

std::invalid_argument – If the array is not a string array

Returns:

This array as a StringPhysicalArray

class ListPhysicalArray : public legate::PhysicalArray#
#include <core/data/physical_array.h>

A multi-dimensional array abstraction for variable-size list of elements.

Public Functions

PhysicalArray descriptor() const#

Returns the sub-array for descriptors.

Returns:

PhysicalArray of descriptors

PhysicalArray vardata() const#

Returns the sub-array for variable size data.

Returns:

PhysicalArray of variable sized data

class StringPhysicalArray : public legate::PhysicalArray#
#include <core/data/physical_array.h>

A multi-dimensional array abstraction representing a string.

Public Functions

PhysicalArray ranges() const#

Returns the sub-array for ranges.

Returns:

PhysicalArray of ranges

PhysicalArray chars() const#

Returns the sub-array for characters.

Returns:

PhysicalArray of the characters in the string.

class PhysicalStore#
#include <core/data/physical_store.h>

A multi-dimensional data container storing task data.

Public Functions

template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_CORE_TRUE_WHEN_DEBUG>
AccessorRO<T, DIM> read_accessor() const#

Returns a read-only accessor to the store for the entire domain.

Template Parameters:
  • T – Element type

  • DIM – Number of dimensions

  • VALIDATE_TYPE – If true (default), validates type and number of dimensions

Returns:

A read-only accessor to the store

template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_CORE_TRUE_WHEN_DEBUG>
AccessorWO<T, DIM> write_accessor() const#

Returns a write-only accessor to the store for the entire domain.

Template Parameters:
  • T – Element type

  • DIM – Number of dimensions

  • VALIDATE_TYPE – If true (default), validates type and number of dimensions

Returns:

A write-only accessor to the store

template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_CORE_TRUE_WHEN_DEBUG>
AccessorRW<T, DIM> read_write_accessor() const#

Returns a read-write accessor to the store for the entire domain.

Template Parameters:
  • T – Element type

  • DIM – Number of dimensions

  • VALIDATE_TYPE – If true (default), validates type and number of dimensions

Returns:

A read-write accessor to the store

template<typename OP, bool EXCLUSIVE, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_CORE_TRUE_WHEN_DEBUG>
AccessorRD<OP, EXCLUSIVE, DIM> reduce_accessor() const#

Returns a reduction accessor to the store for the entire domain.

See also

Library::register_reduction_operator()

Template Parameters:
  • OP – Reduction operator class.

  • EXCLUSIVE – Indicates whether reductions can be performed in exclusive mode. If EXCLUSIVE is false, every reduction via the accessor is performed atomically.

  • DIM – Number of dimensions

  • VALIDATE_TYPE – If true (default), validates type and number of dimensions

Returns:

A reduction accessor to the store

template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_CORE_TRUE_WHEN_DEBUG>
AccessorRO<T, DIM> read_accessor(const Rect<DIM> &bounds) const#

Returns a read-only accessor to the store for specific bounds.

Template Parameters:
  • T – Element type

  • DIM – Number of dimensions

  • VALIDATE_TYPE – If true (default), validates type and number of dimensions

Parameters:

bounds – Domain within which accesses should be allowed. The actual bounds for valid access are determined by an intersection between the store’s domain and the bounds.

Returns:

A read-only accessor to the store

template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_CORE_TRUE_WHEN_DEBUG>
AccessorWO<T, DIM> write_accessor(const Rect<DIM> &bounds) const#

Returns a write-only accessor to the store for the entire domain.

Template Parameters:
  • T – Element type

  • DIM – Number of dimensions

  • VALIDATE_TYPE – If true (default), validates type and number of dimensions

Parameters:

bounds – Domain within which accesses should be allowed. The actual bounds for valid access are determined by an intersection between the store’s domain and the bounds.

Returns:

A write-only accessor to the store

template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_CORE_TRUE_WHEN_DEBUG>
AccessorRW<T, DIM> read_write_accessor(const Rect<DIM> &bounds) const#

Returns a read-write accessor to the store for the entire domain.

Template Parameters:
  • T – Element type

  • DIM – Number of dimensions

  • VALIDATE_TYPE – If true (default), validates type and number of dimensions

Parameters:

bounds – Domain within which accesses should be allowed. The actual bounds for valid access are determined by an intersection between the store’s domain and the bounds.

Returns:

A read-write accessor to the store

template<typename OP, bool EXCLUSIVE, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_CORE_TRUE_WHEN_DEBUG>
AccessorRD<OP, EXCLUSIVE, DIM> reduce_accessor(const Rect<DIM> &bounds) const#

Returns a reduction accessor to the store for the entire domain.

See also

Library::register_reduction_operator()

Template Parameters:
  • OP – Reduction operator class.

  • EXCLUSIVE – Indicates whether reductions can be performed in exclusive mode. If EXCLUSIVE is false, every reduction via the accessor is performed atomically.

  • DIM – Number of dimensions

  • VALIDATE_TYPE – If true (default), validates type and number of dimensions

Parameters:

bounds – Domain within which accesses should be allowed. The actual bounds for valid access are determined by an intersection between the store’s domain and the bounds.

Returns:

A reduction accessor to the store

template<typename VAL>
VAL scalar() const#

Returns the scalar value stored in the store.

The requested type must match with the store’s data type. If the store is not backed by the future, the runtime will fail with an error message.

Template Parameters:

VALType of the scalar value

Returns:

The scalar value stored in the store

template<typename T, std::int32_t DIM>
Buffer<T, DIM> create_output_buffer(const Point<DIM> &extents, bool bind_buffer = false) const#

Creates a Buffer of specified extents for the unbound store.

The returned Buffer is always consistent with the mapping policy for the store. Can be invoked multiple times unless bind_buffer is true.

Parameters:
  • extents – Extents of the Buffer

  • bind_buffer – If the value is true, the created Buffer will be bound to the store upon return

Returns:

A Buffer in which to write the output to.

template<typename T, std::int32_t DIM>
void bind_data(Buffer<T, DIM> &buffer, const Point<DIM> &extents) const#

Binds a Buffer to the store.

Valid only when the store is unbound and has not yet been bound to another Buffer. The Buffer must be consistent with the mapping policy for the store. Recommend that the Buffer be created by a create_output_buffer() call.

Parameters:
  • bufferBuffer to bind to the store

  • extents – Extents of the Buffer. Passing extents smaller than the actual extents of the Buffer is legal; the runtime uses the passed extents as the extents of this store.

void bind_untyped_data(Buffer<std::int8_t, 1> &buffer, const Point<1> &extents) const#

Binds a 1D Buffer of byte-size elements to the store in an untyped manner.

Values in the Buffer are reinterpreted based on the store’s actual type. The Buffer must have enough bytes to be aligned on the store’s element boundary. For example, a 1D Buffer of size 4 wouldn’t be valid if the store had the int64 type, whereas it would be if the store’s element type is int32.

Like the typed counterpart (i.e., bind_data()), the operation is legal only when the store is unbound and has not yet been bound to another buffer. The memory in which the buffer is created must be the same as the mapping decision of this store.

Can be used only with 1D unbound stores.

        constexpr auto num_elements      = 9;
        const auto element_size_in_bytes = store.type().size();
        auto buffer = legate::create_buffer<int8_t, 1>(num_elements * element_size_in_bytes);
        store.bind_untyped_data(buffer, legate::Point<1>{num_elements});

Parameters:
  • bufferBuffer to bind to the store

  • extents – Extents of the buffer. Passing extents smaller than the actual extents of the buffer is legal; the runtime uses the passed extents as the extents of this store. The size of the buffer must be at least as big as extents * type().size().

void bind_empty_data() const#

Makes the unbound store empty.

Valid only when the store is unbound and has not yet been bound to another buffer.

std::int32_t dim() const#

Returns the dimension of the store.

Returns:

The store’s dimension

Type type() const#

Returns the type metadata of the store.

Returns:

The store’s Type

template<typename TYPE_CODE = Type::Code>
inline TYPE_CODE code() const#

Returns the type code of the store.

Returns:

The store’s type code

template<std::int32_t DIM>
Rect<DIM> shape() const#

Returns the store’s domain.

Returns:

Store’s domain

Domain domain() const#

Returns the store’s Domain.

Returns:

Store’s Domain

InlineAllocation get_inline_allocation() const#

Returns a raw pointer and strides to the allocation.

Returns:

An InlineAllocation object holding a raw pointer and strides

mapping::StoreTarget target() const#

Returns the kind of memory where this PhysicalStore resides.

Throws:

std::invalid_argument – If this function is called on an unbound store

Returns:

The memory kind

bool is_readable() const#

Indicates whether the store can have a read accessor.

Returns:

true if the store can have a read accessor, false otherwise

bool is_writable() const#

Indicates whether the store can have a write accessor.

Returns:

true if the store can have a write accessor, false otherwise

bool is_reducible() const#

Indicates whether the store can have a reduction accessor.

Returns:

true if the store can have a reduction accessor, false otherwise

bool valid() const#

Indicates whether the store is valid.

A store passed to a task can be invalid only for reducer tasks for tree reduction. Otherwise, if the store is invalid, it cannot be used in any data access.

Returns:

true if the store is valid, false otherwise

bool transformed() const#

Indicates whether the store is transformed in any way.

Returns:

true if the store is transformed, false otherwise

bool is_future() const#

Indicates whether the store is backed by a future (i.e., a container for scalar value)

Returns:

true if the store is backed by a future, false otherwise

bool is_unbound_store() const#

Indicates whether the store is an unbound store.

The value DOES NOT indicate that the store has already assigned to a buffer; i.e., the store may have been assigned to a buffer even when this function returns true.

Returns:

true if the store is an unbound store, false otherwise

PhysicalStore(const PhysicalArray &array)#

Constructs a store out of an array.

Throws:

std::invalid_argument – If the array is nullable or has sub-arrays

class Scalar#
#include <core/data/scalar.h>

A type-erased container for scalars.

A Scalar can be owned or shared, depending on whether it owns the backing allocation: If a Scalar is shared, it does not own the allocation and any of its copies are also shared. If a Scalar is owned, it owns the backing allocation and releases it upon destruction. Any copy of an owned Scalar is owned as well.

Public Functions

Scalar()#

Creates a null scalar.

See also

null()

Scalar(const Type &type, const void *data, bool copy = false)#

Creates a shared Scalar with an existing allocation. The caller is responsible for passing in a sufficiently big allocation.

Parameters:
  • typeType of the scalar

  • data – Allocation containing the data.

  • copy – If true, the scalar copies the data stored in the allocation and becomes owned.

template<typename T, typename = std::enable_if_t<!std::is_convertible_v<T, std::string> && !std::is_same_v<std::decay_t<T>, Scalar>>>
explicit Scalar(T value)#

Creates an owned Scalar from a scalar value.

Template Parameters:

T – The scalar type to wrap

Parameters:

value – A scalar value to create a Scalar with

template<typename T>
Scalar(T value, const Type &type)#

Creates an owned Scalar of a specified type from a scalar value.

Template Parameters:

T – The scalar type to wrap

Parameters:
  • type – The Type of the scalar

  • value – A scalar value to create a Scalar with

explicit Scalar(std::string_view string)#

Creates an owned Scalar from a std::string_view. The value from the original string will be copied.

Parameters:

string – The std::string_view to create a Scalar with

template<typename T>
explicit Scalar(const std::vector<T> &values)#

Creates an owned Scalar from a std::vector of scalars. The values in the input vector will be copied.

Parameters:

values – Values to create a Scalar with in a vector

template<typename T>
explicit Scalar(const tuple<T> &values)#

Creates an owned Scalar from a tuple of scalars. The values in the input tuple will be copied.

Parameters:

values – Values to create a Scalar with in a tuple

template<std::int32_t DIM>
explicit Scalar(const Point<DIM> &point)#

Creates a point Scalar

Parameters:

point – A Point from which the Scalar should be constructed

template<std::int32_t DIM>
explicit Scalar(const Rect<DIM> &rect)#

Creates a Rect Scalar

Parameters:

rect – A Rect from which the Scalar should be constructed

Type type() const#

Returns the data type of the Scalar

Returns:

Data Type

std::size_t size() const#

Returns the size of allocation for the Scalar.

Returns:

The size of allocation in bytes

template<typename VAL>
VAL value() const#

Returns a copy of the value stored in this Scalar.

1) size of the scalar does not match with size of VAL, 2) the scalar holds a string but VAL isn’t std:string or std:string_view, or 3) the inverse; i.e., VAL is std:string or std:string_view but the scalar’s type isn’t string

Template Parameters:

VALType of the value to unwrap

Throws:

std::invalid_argument – If one of the following cases is encountered:

Returns:

A copy of the value stored in this Scalar

template<typename VAL>
Span<const VAL> values() const#

Returns values stored in the Scalar. If the Scalar does not have a fixed array type, a unit span will be returned.

1) the scalar has a fixed array type whose elemenet type has a different size from VAL, 2) the scalar holds a string and size of VAL isn’t 1 byte, 3) the scalar’s type isn’t a fixed array type and the size is different from size of VAL

Throws:

std::invalid_argument – If one of the following cases is encountered:

Returns:

Values stored in the Scalar

const void *ptr() const#

Returns a raw pointer to the backing allocation.

Returns:

A raw pointer to the Scalar’s data

class Shape#
#include <core/data/shape.h>

A class to express shapes of multi-dimensional entities in Legate.

Shape objects describe logical shapes, of multi-dimensional containers in Legate such as Legate arrays and Legate stores. For example, if the shape of a Legate store is (4, 2), the store is conceptually a 2D container having four rows and two columns of elements. The shape however does not entail any particular physical manifestation of the container. The aforementioned 2D store can be mapped to an allocation in which the elements of each row would be contiguously located or an allocation in which the elements of each column would be contiguously located.

A Shape object is essentially a tuple of extents, one for each dimension, and the dimensionality, i.e., the number of dimensions, is the size of this tuple. The volume of the Shape is a product of all the extents.

Since Legate allows containers’ shapes to be determined by tasks, some shapes may not be “ready” when the control code tries to introspect their extents. In this case, the control code will be blocked until the tasks updating the containers are complete. This asynchrony behind the shape objects is hidden from the control code and it’s recommended that introspection of the shapes of unbound arrays or stores should be avoided. The blocking behavior of each API call can be found in its reference (methods with no mention of blocking should exhibit no shape-related blocking).

Public Functions

inline Shape()#

Constructs a 0D Shape

The constructed Shape is immediately ready

Equivalent to Shape({})

Shape(tuple<std::uint64_t> extents)#

Constructs a Shape from a tuple of extents.

The constructed Shape is immediately ready

Parameters:

extents – Dimension extents

inline explicit Shape(std::vector<std::uint64_t> extents)#

Constructs a Shape from a std::vector of extents.

The constructed Shape is immediately ready

Parameters:

extents – Dimension extents

inline Shape(std::initializer_list<std::uint64_t> extents)#

Constructs a Shape from a std::initializer_list of extents.

The constructed Shape is immediately ready

Parameters:

extents – Dimension extents

const tuple<std::uint64_t> &extents() const#

Returns the Shape’s extents.

If the Shape is of an unbound array or store, the call blocks until the shape becomes ready.

Returns:

Dimension extents

inline std::size_t volume() const#

Returns the Shape’s volume.

Equivalent to extents().volume(). If the Shape is of an unbound array or store, the call blocks until the Shape becomes ready.

Returns:

Volume of the Shape

std::uint32_t ndim() const#

Returns the number of dimensions of this Shape

Unlike other Shape-related queries, this call is non-blocking.

Returns:

Number of dimensions

inline std::uint64_t operator[](std::uint32_t idx) const#

Returns the extent of a given dimension.

If the Shape is of an unbound array or store, the call blocks until the Shape becomes ready. Unlike Shape::at(), this method does not check the dimension index.

Parameters:

idx – Dimension index

Returns:

Extent of the chosen dimension

inline std::uint64_t at(std::uint32_t idx) const#

Returns the extent of a given dimension.

If the Shape is of an unbound array or store, the call blocks until the Shape becomes ready.

Parameters:

idx – Dimension index

Throws:

std::out_of_range – If the dimension index is invalid

Returns:

Extent of the chosen dimension

std::string to_string() const#

Generates a human-readable string from the Shape (non-blocking)

Returns:

std::tring generated from the Shape

bool operator==(const Shape &other) const#

Checks if this Shape is the same as the given Shape

The equality check can block if one of the Shapes is of an unbound array or store and the other Shape is not of the same container.

Returns:

true if the Shapes are isomorphic, false otherwise

inline bool operator!=(const Shape &other) const#

Checks if this Shape is different from the given Shape

The equality check can block if one of the Shapes is of an unbound array or store and the other Shape is not of the same container.

Returns:

true if the Shapes are different, false otherwise

class Slice#
#include <core/data/slice.h>

A slice descriptor.

Slice behaves similarly to how the slice in Python does, and has different semantics from std::slice.

Public Functions

inline Slice(std::optional<std::int64_t> _start = OPEN, std::optional<std::int64_t> _stop = OPEN)#

Constructs a Slice

If provided (and not Slice::OPEN), _start must compare less than or equal to _stop. Similarly, if provided (and not Slice::OPEN), _stop must compare greater than or equal to_start. Put simply, unless one or both of the ends are unbounded, [_start, _stop] must form a valid (possibly empty) interval.

Parameters:
  • _start – The optional begin index of the slice, or Slice::OPEN if the start of the slice is unbounded.

  • _stop – The optional stop index of the slice, or Slice::OPEN if the end of the slice if unbounded.

Public Members

std::optional<std::int64_t> start = {OPEN}#

The start index of the slice

std::optional<std::int64_t> stop = {OPEN}#

The end index of the slice

template<typename T>
class Span#
#include <core/utilities/span.h>

A simple span implementation used in Legate.

Should eventually be replaced with std::span once we bump up the C++ standard version to C++20

Public Functions

Span(T *data, std::size_t size)#

Creates a span with an existing pointer and a size.

The caller must guarantee that the allocation is big enough (i.e., bigger than or equal to sizeof(T) * size) and that the allocation is alive while the span is alive.

Parameters:
  • data – Pointer to the data

  • size – Number of elements

std::size_t size() const#

Returns the number of elements.

Returns:

The number of elements

const T *begin() const#

Returns the pointer to the first element.

Returns:

Pointer to the first element

const T *end() const#

Returns the pointer to the end of allocation.

Returns:

Pointer to the end of allocation

Span subspan(std::size_t off)#

Slices off the first off elements. Passing an off greater than the size will fail with an assertion failure.

Parameters:

off – Number of elements to skip

Returns:

A span for range [off, size())

const T *ptr() const#

Returns a const pointer to the data.

Returns:

Pointer to the data