data#
- group Data abstractions and allocators
Defines
-
LEGATE_TRUE_WHEN_DEBUG#
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 aLegion::DeferredBuffer
is deallocated automatically by Legion once all the kernels launched in the task are complete. However, aLegion::DeferredBuffer
can also be deallocated immediately usingLegion::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 TaskContext::get_task_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 TaskContext::get_task_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.
-
Scalar null()#
Creates a null
Scalar
Null scalars hold a copy of the singleton “Null”
Type
but hold no physical data or allocation. TheirType
may be queried, but they have zero size, and returnnullptr
whenScalar::ptr()
is called on them. They are useful as tombstone values, or to represent invalid data.- Returns:
A null
Scalar
- inline InlineAllocation(
- void *ptr_,
- std::vector<std::size_t> strides_,
- mapping::StoreTarget target_
Variables
-
std::size_t DEFAULT_ALIGNMENT = 16#
The default alignment for memory allocations.
-
class ScopedAllocator
- #include <legate/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:
kind –
Memory::Kind
of the memory on which the Buffer should be createdscoped – 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
- Throws:
std::domain_error – If
alignment
is 0, or not a power of 2.
-
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. If
bytes
is0
, returnsnullptr
.See also
- 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. Ifptr
isnullptr
, this call does nothing.See also
- Parameters:
ptr – Pointer to the allocation to deallocate
- Throws:
std::invalid_argument – If
ptr
was not allocated by this allocator.
-
class Impl
-
class TaskLocalBuffer
- #include <legate/data/buffer.h>
A task-local temporary buffer.
A
TaskLocalBuffer
is, as the name implies, “local” to a task. Its lifetime is bound to that of the task. When the task ends, the buffer is destroyed. It is most commonly used as temporary scratch-space within tasks for that reason.The buffer is allocated immediately at the point when
TaskLocalBuffer
is created, so it is safe to use it immediately, even if it used asynchronously (for example, in GPU kernel launches) after the fact.Public Functions
- TaskLocalBuffer(
- const Legion::UntypedDeferredBuffer<> &buf,
- const Type &type,
- const Domain &bounds
Construct a
TaskLocalBuffer
.- Parameters:
buf – The Legion buffer from which to construct this buffer.
type – The type to interpret
buf
as.bounds – The extent of the buffer.
- TaskLocalBuffer(
- const Type &type,
- Span<const std::uint64_t> bounds,
- std::optional<mapping::StoreTarget> mem_kind = std::nullopt
Construct a
TaskLocalBuffer
.If
mem_kind
is not given, the memory kind is automatically deduced based on the type of processor executing the task. For example, GPU tasks will allocate GPU memory (pure GPU memory that is, not zero-copy), while CPU tasks will allocate regular system memory.- Parameters:
type – The type of the buffer.
bounds – The extents of the buffer.
mem_kind – The kind of memory to allocate.
-
template<typename T, std::int32_t DIM>
TaskLocalBuffer(
) Construct a
TaskLocalBuffer
.If this kind of constructor is used, the user should almost always prefer the
type
-less version of this ctor. That constructor will deduce theType
based onT
. The point of this ctor is to provide the ability to type-pun theBuffer
with an equivalent type.- Parameters:
buf – The typed Legion buffer from which to construct this buffer from.
type – The type to interpret
buf
as.
- Throws:
std::invalid_argument – If
sizeof(T)
is not the same as the type size.std::invalid_argument – If
alignof(T)
is not the same as the type alignment.
-
template<typename T, std::int32_t DIM>
explicit TaskLocalBuffer(
) Construct a
TaskLocalBuffer
.The type of the buffer is deduced from
T
.- Parameters:
buf – The typed Legion buffer from which to construct this buffer from.
-
Type type() const
- Returns:
The type of the buffer.
-
std::int32_t dim() const
- Returns:
The dimension of the buffer
-
const Domain &domain() const
- Returns:
The shape of the buffer.
-
mapping::StoreTarget memory_kind() const
- Returns:
The memory kind of the buffer.
-
template<typename T, std::int32_t DIM>
explicit operator Buffer<T, DIM>( Convert this object to a typed
Buffer
.Since
TaskLocalBuffer
is type-erased, there is not a whole lot you can do with it normally. Access to the underlying data (and ability to create accessors) is only possible with a typed buffer.- Returns:
The typed buffer.
-
InlineAllocation get_inline_allocation() const
Get the
InlineAllocation
for the buffer.This routine constructs a fresh
InlineAllocation
for each call. This process may not be cheap, so the user is encouraged to call this sparingly.- Returns:
The inline allocation object.
-
class ExternalAllocation
- #include <legate/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 existing allocations external to Legate. (See two overloads ofRuntime::create_store()
that takeExternalAllocation
s.)ExternalAllocation
s can be tagged either read-only or mutable.If the allocation is read-only, the calling code must not mutate the contents of the allocation until it is detached. Doing so will result in undefined behavior. Legate will not make any updates of its own to a read-only allocation.
If the allocation is mutable, Legate guarantees that any updates to the store to which the allocation is attached are eagerly written-through to the attached allocation, at the expense of block-waiting on tasks updating the store. The calling code is free to make updates to the allocation in-between tasks.
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. 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 deallocates the allocation. Thedetach()
call makes sure that all outstanding operations on the store complete (seeLogicalStore::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 = std::function<void(void*)>
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 nullstd::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 nullstd::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 nullstd::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 nullstd::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 <legate/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 byte-offsets into
ptr
.The offsets are given in bytes, and represent the number of bytes needed to jump to the next array element in the corresponding dimension. For example:
#. For an array whose entries are 4 bytes long, and whose shape is
(1,)
,strides
would be[4]
(entryi
given by4*i
). #. For an array whose entries are 8 bytes long, and whose shape is(1, 2,)
,strides
would be[16, 8]
(entry(i, j)
given by16*i + 8*j
). #. For an array whose entries are 8 bytes long, and whose shape is(1, 2, 3)
, strideswould be
[48, 24, 8](entry
(i, j, k)given by
48*i + 24*j + 8*k`).
-
mapping::StoreTarget target = {}
The type of memory that
ptr
resides in.
-
void *ptr = {}
-
class LogicalArray
- #include <legate/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
-
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
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 namestd::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 orindex
is out of boundsstd::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
sl – Slice descriptor
- Throws:
std::invalid_argument – If
dim
is not a valid dimension namestd::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 inaxes
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
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 orsizes
does not preserve the extent of the chosen dimensionstd::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 null_mask() const
Returns the null mask of this array.
- Returns:
-
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:
- PhysicalArray get_physical_array(
- std::optional<mapping::StoreTarget> target = std::nullopt
Creates a
PhysicalArray
for thisLogicalArray
This call blocks the client’s control flow and fetches the data for the whole array to the current node.
When the target is
StoreTarget::FBMEM
, the data will be consolidated in the framebuffer of the first GPU available in the scope.If no
target
is given, the runtime usesStoreTarget::SOCKETMEM
if it exists andStoreTarget::SYSMEM
otherwise.If there already exists a physical array for a different memory target, that physical array will be unmapped from memory and become invalid to access.
- Parameters:
target – The type of memory in which the physical array would be created.
- Throws:
std::invalid_argument – If no memory of the chosen type is available
- Returns:
A
PhysicalArray
of theLogicalArray
-
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
-
void offload_to(mapping::StoreTarget target_mem) const
Offload array to specified target memory.
Copies the array to the specified memory, if necessary, and marks it as the most up-to-date copy, allowing the runtime to discard any copies in other memories.
Main usage is to free up space in one kind of memory by offloading resident arrays and stores to another kind of memory. For example, after a GPU task that reads or writes to an array, users can manually free up Legate’s GPU memory by offloading the array to host memory.
All the stores that comprise the array are offloaded, i.e., the data store, the null mask, and child arrays, etc.
Currently, the runtime does not validate if the target memory has enough capacity or free space at the point of launching or executing the offload operation. The program will most likely crash if there isn’t enough space in the target memory. The user is therefore encouraged to offload to a memory type that is likely to have sufficient space.
This should not be treated as a prefetch call as it offers little benefit to that end. The runtime will ensure that data for a task is resident in the required memory before the task begins executing.
If this array is backed by another array, e.g., if this array is a slice or some other transform of another array, then both the arrays will be offloaded due to being backed by the same memory.
// This snippet launches two GPU tasks that manipulate two different stores, // where each store occupies more than 50% of GPU memory. Runtime can map and // schedule both the tasks at the same time. Without offloading the first store, // mapping will fail for the second task. Therefore, we insert an `offload_to` // call for the first store after submitting the first task and before submitting // the second task. { auto task1 = runtime->create_task(library, GPUonlyTask::TASK_CONFIG.task_id()); task1.add_output(store1); runtime->submit(std::move(task1)); } store1.offload_to(legate::mapping::StoreTarget::SYSMEM); { auto task2 = runtime->create_task(library, GPUonlyTask::TASK_CONFIG.task_id()); task2.add_output(store2); runtime->submit(std::move(task2)); }
- Parameters:
target_mem – The target memory.
- Throws:
std::invalid_argument – If Legate was not configured to support
target_mem
.
-
class Impl
-
std::uint32_t dim() const
-
class ListLogicalArray : public legate::LogicalArray
- #include <legate/data/logical_array.h>
Represents a logical array of variable-length lists.
Each element of the array is itself a list, potentially of different length. For example, a ListLogicalArray may represent:
[[a, b], [c], [d, e, f]]
This is stored using two arrays:
A descriptor array that defines the start and end indices of each sublist within the value data array. The descriptor array is stored as a series of
Rect<1>
s, wherelo
andhi
members indicate the start and end of each range.A value data array (
vardata
) containing all list elements in a flattened form.
For example:
descriptor: [ (0, 1), (2, 2), (3, 5) ] vardata: [ a, b, c, d, e, f ]
Where the mapping of
descriptor
tovardata
follows:descriptor vardata ---------- -------------------- (0, 1) ---> [ a, b ] (2, 2) ---> [ c ] (3, 5) ---> [ d, e, f ]
Note
The user can achieve the same effects of a
ListLogicalArray
themselves by applying an image constraint (image(Variable, Variable, ImageComputationHint)
) to twoLogicalArray
s when passing them to a task. In that casedescriptor
would bevar_function
whilevardata
would bevar_range
.Public Functions
-
LogicalArray descriptor() const
Returns the sub-array for descriptors. Each element is a
Rect<1>
of start and end indices for each subregion invardata
.- 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 <legate/data/logical_array.h>
A multi-dimensional array representing a collection of strings.
This class is essentially a
ListLogicalArray
specialized for lists-of-strings data. The member functionsoffsets()
andchars()
are directly analogous toListLogicalArray::descriptor()
andListLogicalArray::vardata()
.The strings are stored in a compact form, accessible through
chars()
, whileoffsets()
gives the start and end indices for each sub-string.See also
Public Functions
-
LogicalArray offsets() const
Returns the sub-array for offsets giving the bounds of each string.
- Returns:
LogicalArray
of offsets into this array.
-
LogicalArray chars() const
Returns the sub-array for characters of the strings.
- Returns:
LogicalArray
representing the characters of the strings.
-
LogicalArray offsets() const
-
class LogicalStore
- #include <legate/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 callingLogicalStore::get_physical_store()
, which gives the client a handle to the physical allocation (seePhysicalStore
for details about physical stores).Normally, a
LogicalStore
gets a fixedShape
upon creation. However, there is a special type of logical stores called “unbound” stores whose shapes are unknown at creation time. (seeRuntime
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, theLogicalStore
becomes a normal store. Passing an unbound store as a read-only argument or requesting aPhysicalStore
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
whoseShape
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 theLogicalStore
.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
-
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 reinterpret_as(const Type &type) const
Reinterpret the underlying data of a
LogicalStore
byte-for-byte as another type.The size and alignment of the new type must match that of the existing type.
The reinterpreted store will share the same underlying storage as the original, and therefore any writes to one will also be reflected in the other. No type conversions of any kind are performed across the stores, the bytes are interpreted as-is. In effect, if one were to model a
LogicalStore
as a pointer to an array, then this routine is equivalent toreinterpret_cast
-ing the pointer.Example:
// Create a store of some shape filled with int32 data. constexpr std::int32_t minus_one = -1; const auto store = runtime->create_store(shape, legate::int32()); runtime->issue_fill(store, legate::Scalar{minus_one}); // Reinterpret the underlying data as unsigned 32-bit integers. auto reinterp_store = store.reinterpret_as(legate::uint32()); // Our new store should have the same type as it was reinterpreted to. ASSERT_EQ(reinterp_store.type(), legate::uint32()); // Our old store still has the same type though. ASSERT_EQ(store.type(), legate::int32()); // Both stores should refer to the same underlying storage. ASSERT_TRUE(store.equal_storage(reinterp_store)); const auto phys_store = reinterp_store.get_physical_store(); const auto acc = phys_store.read_accessor<std::uint32_t, 1>(); std::uint32_t interp_value; // Need to memcpy here in order to do a "true" bitcast. A reinterpret_cast() may or may not // result in the compilers generating the conversion, since type-punning with // reinterpret_cast is UB. std::memcpy(&interp_value, &minus_one, sizeof(minus_one)); for (auto it = legate::PointInRectIterator<1>{phys_store.shape<1>()}; it.valid(); ++it) { ASSERT_EQ(acc[*it], interp_value); }
- Parameters:
type – The new type to interpret the data as.
- Returns:
The reinterpreted store.
- Throws:
std::invalid_argument – If the size (in bytes) of the new type does not match that of the old type.
std::invalid_argument – If the alignment of the new type does not match that of the old type.
- LogicalStore promote(
- std::int32_t extra_dim,
- std::size_t dim_size
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]
, whereasA.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 orindex
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
sl –
Slice
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})
andA.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 inaxes
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
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 ofsizes
. 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 orsizes
does not preserve the extent of the chosen dimension- Returns:
A new store with the chosen dimension delinearized
- LogicalStorePartition partition_by_tiling(
- std::vector<std::uint64_t> tile_shape
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(
- std::optional<mapping::StoreTarget> target = std::nullopt
Creates a
PhysicalStore
for thisLogicalStore
This call blocks the client’s control flow and fetches the data for the whole store to the current node.
When the target is
StoreTarget::FBMEM
, the data will be consolidated in the framebuffer of the first GPU available in the scope.If no
target
is given, the runtime usesStoreTarget::SOCKETMEM
if it exists andStoreTarget::SYSMEM
otherwise.If there already exists a physical store for a different memory target, that physical store will be unmapped from memory and become invalid to access.
- Parameters:
target – The type of memory in which the physical store would be created.
- Throws:
std::invalid_argument – If no memory of the chosen type is available
- Returns:
A
PhysicalStore
of theLogicalStore
-
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.
-
void offload_to(mapping::StoreTarget target_mem)
Offload store to specified target memory.
See also
- Parameters:
target_mem – The target memory.
-
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
orother
.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. ASSERT_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 ASSERT_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 Impl
-
std::uint32_t dim() const
-
class LogicalStorePartition
-
class Impl
-
class Impl
-
class PhysicalArray
- #include <legate/data/physical_array.h>
A multi-dimensional array abstraction for fixed- or variable-size elements.
PhysicalArray
s can be backed by one or morePhysicalStore
s, 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
-
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 null_mask() const
Returns the store containing the array’s null mask.
- Throws:
std::invalid_argument – If the array is not nullable
- Returns:
-
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
-
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
-
bool nullable() const noexcept
-
class ListPhysicalArray : public legate::PhysicalArray
- #include <legate/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
-
PhysicalArray descriptor() const
-
class StringPhysicalArray : public legate::PhysicalArray
- #include <legate/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.
-
PhysicalArray ranges() const
-
class PhysicalStore
- #include <legate/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_TRUE_WHEN_DEBUG>
mdspan_type<const T, DIM> span_read_accessor( Returns a read-only mdspan to the store over its entire domain. Equivalent to
span_read_accessor<T, DIM>(shape<DIM>())
.Note
This API is experimental. It will eventually replace the Legion accessor interface, but we are seeking user feedback on it before such time. If you encounter issues, and/or have suggestions for improvements, please file a bug at nv-legate/legate#issues.
- Template Parameters:
T – The element type of the mdspan.
DIM – The rank of the mdspan.
VALIDATE_TYPE – If
true
(default), checks that the type and rank of the mdspan match that of thePhysicalStore
.
- Returns:
The read-only mdspan accessor.
-
template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_TRUE_WHEN_DEBUG>
mdspan_type<T, DIM> span_write_accessor( Returns a write-only mdspan to the store over its entire domain. Equivalent to
span_write_accessor<T, DIM>(shape<DIM>())
.The user may read from a write-only accessor, but must write to the read-from location first, otherwise the returned values are undefined:
auto acc = store.span_write_accessor<float, 2>(); v = acc(0, 0); // Note: undefined value acc(0, 0) = 42.0; v = acc(0, 0); // OK, value will be 42.0
Note
This API is experimental. It will eventually replace the Legion accessor interface, but we are seeking user feedback on it before such time. If you encounter issues, and/or have suggestions for improvements, please file a bug at nv-legate/legate#issues.
- Template Parameters:
T – The element type of the mdspan.
DIM – The rank of the mdspan.
VALIDATE_TYPE – If
true
(default on debug builds), checks that the type and rank of the mdspan match that of thePhysicalStore
.
- Returns:
The mdspan accessor.
-
template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_TRUE_WHEN_DEBUG>
mdspan_type<T, DIM> span_read_write_accessor( Returns a read-write mdspan to the store over its entire domain. Equivalent to
span_read_write_accessor<T, DIM>(shape<DIM>())
.Note
This API is experimental. It will eventually replace the Legion accessor interface, but we are seeking user feedback on it before such time. If you encounter issues, and/or have suggestions for improvements, please file a bug at nv-legate/legate#issues.
- Template Parameters:
T – The element type of the mdspan.
DIM – The rank of the mdspan.
VALIDATE_TYPE – If
true
(default on debug builds), checks that the type and rank of the mdspan match that of thePhysicalStore
.
- Returns:
The mdspan accessor.
-
template<typename Redop, bool EXCLUSIVE, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_TRUE_WHEN_DEBUG>
mdspan_type<typename Redop::LHS, DIM, detail::ReductionAccessor<Redop, EXCLUSIVE>> span_reduce_accessor( Returns a reduction mdspan to the store over its entire domain. Equivalent to
span_reduce_accessor<Redop, EXCLUSIVE, DIM>(shape<DIM>())
.Note
This API is experimental. It will eventually replace the Legion accessor interface, but we are seeking user feedback on it before such time. If you encounter issues, and/or have suggestions for improvements, please file a bug at nv-legate/legate#issues.
- Template Parameters:
Redop – The reduction operator (e.g.
SumReduction
).EXCLUSIVE – Whether the reduction accessor has exclusive access to the buffer.
DIM – The rank of the mdspan.
VALIDATE_TYPE – If
true
(default on debug builds), checks that the type and rank of the mdspan match that of thePhysicalStore
.
- Returns:
The mdspan accessor.
-
template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_TRUE_WHEN_DEBUG>
mdspan_type<const T, DIM> span_read_accessor(
) const Returns a read-only mdspan to the store over the selected domain.
Note
This API is experimental. It will eventually replace the Legion accessor interface, but we are seeking user feedback on it before such time. If you encounter issues, and/or have suggestions for improvements, please file a bug at nv-legate/legate#issues.
Note
If
bounds
is empty then the strides of the returnedmdspan
will be all 0 instead of what it might normally be. The object is still perfectly usable as normal but the strides will not be correct.- Template Parameters:
T – The element type of the mdspan.
DIM – The rank of the mdspan.
VALIDATE_TYPE – If
true
(default on debug builds), checks that the type and rank of the mdspan match that of thePhysicalStore
.
- Parameters:
bounds – The (sub-)domain over which to access the store.
- Returns:
The mdspan accessor.
-
template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_TRUE_WHEN_DEBUG>
mdspan_type<T, DIM> span_write_accessor(
) Returns a write-only mdspan to the store over the selected domain.
The user may read from a write-only accessor, but must write to the read-from location first, otherwise the returned values are undefined:
auto acc = store.span_write_accessor<float, 2>(bounds); v = acc(0, 0); // Note: undefined value acc(0, 0) = 42.0; v = acc(0, 0); // OK, value will be 42.0
Note
This API is experimental. It will eventually replace the Legion accessor interface, but we are seeking user feedback on it before such time. If you encounter issues, and/or have suggestions for improvements, please file a bug at nv-legate/legate#issues.
Note
If
bounds
is empty then the strides of the returnedmdspan
will be all 0 instead of what it might normally be. The object is still perfectly usable as normal but the strides will not be correct.- Template Parameters:
T – The element type of the mdspan.
DIM – The rank of the mdspan.
VALIDATE_TYPE – If
true
(default on debug builds), checks that the type and rank of the mdspan match that of thePhysicalStore
.
- Parameters:
bounds – The (sub-)domain over which to access the store.
- Returns:
The mdspan accessor.
-
template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_TRUE_WHEN_DEBUG>
mdspan_type<T, DIM> span_read_write_accessor(
) Returns a read-write mdspan to the store over the selected domain.
Note
This API is experimental. It will eventually replace the Legion accessor interface, but we are seeking user feedback on it before such time. If you encounter issues, and/or have suggestions for improvements, please file a bug at nv-legate/legate#issues.
Note
If
bounds
is empty then the strides of the returnedmdspan
will be all 0 instead of what it might normally be. The object is still perfectly usable as normal but the strides will not be correct.- Template Parameters:
T – The element type of the mdspan.
DIM – The rank of the mdspan.
VALIDATE_TYPE – If
true
(default on debug builds), checks that the type and rank of the mdspan match that of thePhysicalStore
.
- Parameters:
bounds – The (sub-)domain over which to access the store.
- Returns:
The mdspan accessor.
-
template<typename Redop, bool EXCLUSIVE, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_TRUE_WHEN_DEBUG>
mdspan_type<typename Redop::LHS, DIM, detail::ReductionAccessor<Redop, EXCLUSIVE>> span_reduce_accessor(
) Returns a reduction mdspan to the store over the selected domain.
Note
This API is experimental. It will eventually replace the Legion accessor interface, but we are seeking user feedback on it before such time. If you encounter issues, and/or have suggestions for improvements, please file a bug at nv-legate/legate#issues.
Note
If
bounds
is empty then the strides of the returnedmdspan
will be all 0 instead of what it might normally be. The object is still perfectly usable as normal but the strides will not be correct.- Template Parameters:
Redop – The reduction operator (e.g.
SumReduction
).EXCLUSIVE – Whether the reduction accessor has exclusive access to the buffer.
DIM – The rank of the mdspan.
VALIDATE_TYPE – If
true
(default on debug builds), checks that the type and rank of the mdspan match that of thePhysicalStore
.
- Parameters:
bounds – The (sub-)domain over which to access the store.
- Returns:
The mdspan accessor.
-
template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_TRUE_WHEN_DEBUG>
AccessorRO<T, DIM> read_accessor( 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_TRUE_WHEN_DEBUG>
AccessorWO<T, DIM> write_accessor( 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_TRUE_WHEN_DEBUG>
AccessorRW<T, DIM> read_write_accessor( 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_TRUE_WHEN_DEBUG>
AccessorRD<OP, EXCLUSIVE, DIM> reduce_accessor( Returns a reduction accessor to the store for the entire domain.
- Template Parameters:
OP – Reduction operator class.
EXCLUSIVE – Indicates whether reductions can be performed in exclusive mode. If
EXCLUSIVE
isfalse
, 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_TRUE_WHEN_DEBUG>
AccessorRO<T, DIM> read_accessor(
) 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_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
- 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_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
- 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_TRUE_WHEN_DEBUG>
AccessorRD<OP, EXCLUSIVE, DIM> reduce_accessor(
) const Returns a reduction accessor to the store for the entire domain.
- Template Parameters:
OP – Reduction operator class.
EXCLUSIVE – Indicates whether reductions can be performed in exclusive mode. If
EXCLUSIVE
isfalse
, 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:
VAL – Type 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 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.
- TaskLocalBuffer create_output_buffer(
- const DomainPoint &extents,
- bool bind_buffer = false
Creates a
TaskLocalBuffer
of specified extents for the unbound store.The returned
TaskLocalBuffer
is always consistent with the mapping policy for the store. Can be invoked multiple times unlessbind_buffer
is true.- Parameters:
extents – Extents of the
TaskLocalBuffer
bind_buffer – If the value is
true
, the createdTaskLocalBuffer
will be bound to the store upon return.
- Returns:
A
TaskLocalBuffer
in which to write the output to.
-
template<typename T, std::int32_t DIM>
void bind_data(
) 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.
- void bind_data(
- const TaskLocalBuffer &buffer,
- const DomainPoint &extents,
- bool check_type = false
Binds a
TaskLocalBuffer
to the store.Valid only when the store is unbound and has not yet been bound to another
TaskLocalBuffer
. TheTaskLocalBuffer
must be consistent with the mapping policy for the store. Recommend that theTaskLocalBuffer
be created by acreate_output_buffer()
call.Passing
extents
that are smaller than the actual extents of theTaskLocalBuffer
is legal; the runtime uses the passed extents as the extents of this store.If
check_type
istrue
, thenbuffer
must have the same type as thePhysicalStore
.- Parameters:
buffer –
TaskLocalBuffer
to bind to the store.extents – Extents of the
TaskLocalBuffer
.check_type – Whether to check the type of the buffer against the type of this store for validity.
- Throws:
std::invalid_argument – If the type of
buffer
is not compatible with the type of the store (only thrown ifcheck_type
istrue
).
- void bind_untyped_data( ) 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(); constexpr auto UNTYPEED_DATA_DIM = 1; auto buffer = legate::create_buffer<std::int8_t, UNTYPEED_DATA_DIM>(num_elements * element_size_in_bytes); store.bind_untyped_data(buffer, legate::Point<UNTYPEED_DATA_DIM>{num_elements});
-
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
-
template<typename TYPE_CODE = Type::Code>
inline TYPE_CODE code( 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
-
bool is_partitioned() const
Indicates whether the store is partitioned.
Tasks sometimes need to know whether a given
PhysicalStore
is partitioned, i.e., corresponds to a subset of the (global)LogicalStore
passed at the launch site. Unless the task explicitly requests broadcasting on theLogicalStore
, the partitioning decision on the store is at the whim of the runtime. In this case, the task can use theis_partitioned()
function to retrieve that information.- Returns:
true
if the store is partitioned,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
-
template<typename T, std::int32_t DIM, bool VALIDATE_TYPE = LEGATE_TRUE_WHEN_DEBUG>
-
class Scalar
- #include <legate/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 aScalar
is shared, it does not own the allocation and any of its copies are also shared. If aScalar
is owned, it owns the backing allocation and releases it upon destruction. Any copy of an ownedScalar
is owned as well.Public Functions
-
Scalar()
Creates a null scalar.
See also
-
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:
type –
Type
of the scalardata – 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>, InternalSharedPtr<detail::Scalar>>>>
explicit Scalar( - const 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(const T &value, const Type &type) Creates an owned
Scalar
of a specified type from a scalar value.
-
explicit Scalar(std::string_view string)
Creates an owned
Scalar
from astd::string_view
. The value from the original string will be copied.- Parameters:
string – The
std::string_view
to create aScalar
with
-
template<typename T>
explicit Scalar(const std::vector<T> &values) Creates an owned
Scalar
from astd::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 atuple
of scalars. The values in the inputtuple
will be copied.- Parameters:
values – Values to create a
Scalar
with in atuple
-
explicit Scalar(const std::vector<bool> &values)
Creates an owned
Scalar
from astd::vector<bool>
. The values in the input vector will be copied.Like most things with
std::vector<bool>
, this construction is not particularly efficient. In order to be copied into theScalar
, the vector will first be “expanded” into a temporarystd::vector<std::uint8_t>
, resulting in multiple copies being performed.The user is therefore highly encouraged to use
std::vector<std::uint8_t>
directly instead ofstd::vector<bool>
(if possible), especially if such vectors are commonly passed to tasks.- Parameters:
values – The values with which to create the
Scalar
.
-
template<std::int32_t DIM>
explicit Scalar(
) Creates a point
Scalar
-
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 butVAL
isn’tstd:string
orstd:string_view
, or 3) the inverse; i.e.,VAL
isstd:string
orstd:string_view
but the scalar’s type isn’t string
-
template<typename VAL>
Span<const VAL> values() const Returns values stored in the
Scalar
. If theScalar
does not have a fixed array type, a unit span will be returned.1) the scalar has a fixed array type whose element type has a different size from
VAL
, 2) the scalar holds a string and size ofVAL
isn’t 1 byte, 3) the scalar’s type isn’t a fixed array type and the size is different from size ofVAL
- 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
-
Scalar()
-
class Shape
- #include <legate/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 theShape
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 readyEquivalent to
Shape({})
-
Shape(tuple<std::uint64_t> extents)
Constructs a
Shape
from atuple
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 astd::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 astd::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
-
std::size_t volume() const
Returns the
Shape
’s volume.Equivalent to
extents().volume()
. If theShape
is of an unbound array or store, the call blocks until theShape
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 theShape
becomes ready. UnlikeShape::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 theShape
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::string
generated from theShape
-
inline Shape()
-
class Slice
- #include <legate/data/slice.h>
A slice descriptor.
Slice
behaves similarly to how the slice in Python does, and has different semantics fromstd::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 notSlice::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 <legate/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
-
template<typename C, typename = std::enable_if_t<detail::is_container_v<C> && !std::is_same_v<C, std::initializer_list<T>>>>
constexpr Span( - C &container
Construct a span from a container-like object.
This overload only participates in overload resolution if C satisfies ContainerLike. It must have a valid overload of
std::data()
andstd::size()
which refer to a contiguous buffer of data and its size respectively.- Parameters:
container – The container-like object.
-
constexpr Span(std::initializer_list<T> il)
Construct a span from an initializer list of items directly.
This overload is relatively dangerous insofar that the span can very easily outlive the initializer list. It is generally only preferred to target this overload when taking a
Span
as a function argument where the ability to simply dofoo({1, 2, 3, 4})
is preferred.- Parameters:
il – The initializer list.
-
constexpr Span(T *data, size_type 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
-
size_type size() const
Returns the number of elements.
- Returns:
The number of elements
-
const_iterator begin() const
Returns the pointer to the first element.
- Returns:
Pointer to the first element
-
const_iterator end() const
Returns the pointer to the end of allocation.
- Returns:
Pointer to the end of allocation
-
iterator begin()
Returns the pointer to the first element.
- Returns:
Pointer to the first element
-
iterator end()
Returns the pointer to the end of allocation.
- Returns:
Pointer to the end of allocation
-
reverse_const_iterator rbegin() const
- Returns:
An iterator to the last element.
-
reverse_const_iterator rend() const
- Returns:
An iterator one past the first element.
-
reverse_iterator rbegin()
- Returns:
An iterator to the last element.
-
reverse_iterator rend()
- Returns:
An iterator one past the first element.
-
reference front() const
- Returns:
A reference to the first element in the span.
-
reference back() const
- Returns:
A reference to the last element in the span.
-
Span subspan(size_type off)
Slices off the first
off
elements. Passing anoff
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_pointer ptr() const
Returns a
const
pointer to the data.- Returns:
Pointer to the data
-
pointer data() const
Returns a pointer to the data.
- Returns:
Pointer to the data.
-
template<typename C, typename = std::enable_if_t<detail::is_container_v<C> && !std::is_same_v<C, std::initializer_list<T>>>>
-
LEGATE_TRUE_WHEN_DEBUG#