Util#
- group Utilities
General utilities.
Defines
-
LEGATE_CONCAT_(x, ...)#
Concatenate a series of tokens without macro expansion.
This macro will NOT macro-expand any tokens passed to it. If this behavior is undesirable, and the user wishes to have all tokens expanded before concatenation, use LEGATE_CONCAT() instead. For example:
#define FOO 1 #define BAR 2 LEGATE_CONCAT(FOO, BAR) // expands to FOOBAR
See also
- Parameters:
x – The first parameter to concatenate.
... – The remaining parameters to concatenate.
-
LEGATE_CONCAT(x, ...)#
Concatenate a series of tokens.
This macro will first macro-expand any tokens passed to it. If this behavior is undesirable, use LEGATE_CONCAT_() instead. For example:
#define FOO 1 #define BAR 2 LEGATE_CONCAT(FOO, BAR) // expands to 12
See also
- Parameters:
x – The first parameter to concatenate.
... – The remaining parameters to concatenate.
-
LEGATE_STRINGIZE_(...)#
Stringize a series of tokens.
This macro will turn its arguments into compile-time constant C strings.
This macro will NOT macro-expand any tokens passed to it. If this behavior is undesirable, and the user wishes to have all tokens expanded before stringification, use LEGATE_STRINGIZE() instead. For example:
#define FOO 1 #define BAR 2 LEGATE_STRINGIZE_(FOO, BAR) // expands to "FOO, BAR" (note the "")
See also
- Parameters:
... – The tokens to stringize.
-
LEGATE_STRINGIZE(...)#
Stringize a series of tokens.
This macro will turn its arguments into compile-time constant C strings.
This macro will first macro-expand any tokens passed to it. If this behavior is undesirable, use LEGATE_STRINGIZE_() instead. For example:
#define FOO 1 #define BAR 2 LEGATE_STRINGIZE(FOO, BAR) // expands to "1, 2" (note the "")
See also
- Parameters:
... – The tokens to stringize.
-
LEGATE_DEFINED_ENABLED_FORM_1#
-
LEGATE_DEFINED_ENABLED_FORM_#
-
LEGATE_DEFINED_PRIVATE_3_(ignored, val, ...)#
-
LEGATE_DEFINED_PRIVATE_2_(args)#
-
LEGATE_DEFINED_PRIVATE_1_(...)#
-
LEGATE_DEFINED_PRIVATE(x)#
-
LEGATE_DEFINED(x)#
Determine if a preprocessor definition is positively defined.
LEGATE_DEFINED() returns 1 if and only if x expands to integer literal 1, or is defined (but empty). In all other cases, LEGATE_DEFINED() returns the integer literal 0. Therefore this macro should not be used if its argument may expand to a non-empty value other than
The only exception is if the argument is defined but expands to 0, in which case
LEGATE_DEFINED()
will also expand to 0:
#define FOO_EMPTY #define FOO_ONE 1 #define FOO_ZERO 0 // #define FOO_UNDEFINED static_assert(LEGATE_DEFINED(FOO_EMPTY) == 1); static_assert(LEGATE_DEFINED(FOO_ONE) == 1); static_assert(LEGATE_DEFINED(FOO_ZERO) == 0); static_assert(LEGATE_DEFINED(FOO_UNDEFINED) == 0);
Conceptually,
LEGATE_DEFINED()
is equivalent to#if defined(x) && (x == 1 || x == *empty*) // "return" 1 #else // "return" 0 #endif
As a result this macro works both in preprocessor statements:
#if LEGATE_DEFINED(FOO_BAR) foo_bar_is_defined(); #else foo_bar_is_not_defined(); #endif
And in regular C++ code:
if (LEGATE_DEFINED(FOO_BAR)) { foo_bar_is_defined(); } else { foo_bar_is_not_defined(); }
Note that in the C++ example above both arms of the if statement must compile. If this is not desired, then — since
LEGATE_DEFINED()
produces a compile-time constant expression — the user may use C++17’sif constexpr
to block out one of the arms:if constexpr (LEGATE_DEFINED(FOO_BAR)) { foo_bar_is_defined(); } else { foo_bar_is_not_defined(); }
See also
- Parameters:
x – The legate preprocessor definition.
- Returns:
1 if the argument is defined and true, 0 otherwise.
-
LEGATE_SCOPE_GUARD(...)#
Construct an unnamed legate::ScopeGuard from the contents of the macro arguments.
It is impossible to enable or disable the legate::ScopeGuard constructed by this macro.
This macro is useful if the user need only define some action to be executed on scope exit, but doesn’t care to name the legate::ScopeGuard and/or has no need to enable/disable it after construction.
For example:
int *mem = std::malloc(10 * sizeof(int)); LEGATE_SCOPE_GUARD(std::free(mem)); // use mem... // scope exits, and mem is free'd.
Multi-line statements are also supported:
int *mem = std::malloc(10 * sizeof(int)); LEGATE_SCOPE_GUARD( if (frobnicate()) { std::free(mem); } ); // use mem... // scope exits, and mem is free'd depending on return value of frobnicate()
If the body of the guard should only be executed on failure, use LEGATE_SCOPE_FAIL instead.
See also
ScopeGuard
See also
- Parameters:
... – The body of the constructed legate::ScopeGuard.
-
LEGATE_SCOPE_FAIL(...)#
Construct an unnamed legate::ScopeFail from the contents of the macro arguments.
This macro behaves identically to
LEGATE_SCOPE_GUARD
, except that it creates a legate::ScopeFail instead of a legate::ScopeGuard. Please refer to its documentation for further discussion.See also
ScopeFail
See also
- Parameters:
... – The body of the constructed legate::ScopeFail.
Functions
-
Time measure_microseconds()#
Returns a timestamp at the resolution of microseconds.
The returned timestamp indicates the time at which all preceding Legate operations finish. This timestamp generation is a non-blocking operation, and the blocking happens when the value wrapped within the returned
Time
object is retrieved.- Returns:
A
Time
object
-
Time measure_nanoseconds()#
Returns a timestamp at the resolution of nanoseconds.
The returned timestamp indicates the time at which all preceding Legate operations finish. This timestamp generation is a non-blocking operation, and the blocking happens when the value wrapped within the returned
Time
object is retrieved.- Returns:
A
Time
object
-
template<typename T, int DIM>
std::string print_dense_array(
)# Converts the dense array into a string.
- Parameters:
base – Array to convert
extents – Extents of the array
strides – Strides for dimensions
- Returns:
A string expressing the contents of the array
-
template<int DIM, typename ACC>
std::string print_dense_array(
)# Converts the dense array into a string using an accessor.
- Parameters:
accessor – Accessor to an array
rect – Sub-rectangle within which the elements should be retrieved
- Returns:
A string expressing the contents of the array
-
template<typename Functor, typename ...Fnargs>
decltype(auto) double_dispatch(
)# Converts the runtime dimension and type code into compile time constants and invokes the functor with them.
The functor’s
operator()
should take a dimension and a type code as template parameters.- Parameters:
dim – Dimension
code – Type code
f – Functor to dispatch
args – Extra arguments to the functor
- Returns:
The functor’s return value
-
template<typename Functor, typename ...Fnargs>
decltype(auto) double_dispatch(
)# Converts the runtime dimensions into compile time constants and invokes the functor with them.
The functor’s
operator()
should take exactly two integers as template parameters.- Parameters:
dim1 – First dimension
dim2 – Second dimension
f – Functor to dispatch
args – Extra arguments to the functor
- Returns:
The functor’s return value
-
template<typename Functor, typename ...Fnargs>
decltype(auto) dim_dispatch(
)# Converts the runtime dimension into a compile time constant and invokes the functor with it.
The functor’s
operator()
should take an integer as its sole template parameter.- Parameters:
dim – Dimension
f – Functor to dispatch
args – Extra arguments to the functor
- Returns:
The functor’s return value
-
template<typename Functor, typename ...Fnargs>
decltype(auto) type_dispatch(
)# Converts the runtime type code into a compile time constant and invokes the functor with it.
The functor’s
operator()
should take a type code as its sole template parameter.- Parameters:
code – Type code
f – Functor to dispatch
args – Extra arguments to the functor
- Returns:
The functor’s return value
-
template<typename F>
ScopeGuard<F> make_scope_guard( - F &&fn,
Create a ScopeGuard from a given functor.
See also
- Parameters:
fn – The functor to create the ScopeGuard with.
- Template Parameters:
The – type of
fn
, usually inferred from the argument itself.- Returns:
The constructed ScopeGuard
-
class Scope#
- #include <legate/runtime/scope.h>
A helper class to configure task execution.
The Scope class offers APIs to configure runtime parameters for task execution. The parameters set by a Scope object are effective only for the lifetime of the object. Currently, Scope can be used to configure the following parameters:
1) Task priority: Each task is associated with a priority value. The higher the value, the earlier among a set of ready-to-run tasks the task will get scheduled for execution. (the task with a higher priority, however, does not preempt another with a lower priority that is already running on the processor.) Task priorities are a signed 32-bit integer value. By default, all tasks get assigned to 0 for the priorities.
2) Provenance: User programs or libraries often want to attach provenance information to each of their operations and have it rendered in profiling outputs. Such information can be passed as a string via a Scope object, which then will be attached to all operations issued within the Scope’s lifetime.
3) Machine: By default, Legate operations target the entire machine available for the program. When a user program wants to assign a subset of the machine to its operations, it can subdivide the machine using the machine API (see
Machine
for details) and set a sub-machine for the scope using Scope. All operations within the lifetime of the Scope object can use only the sub-machine for their execution.Each parameter can be set only once via each Scope object. Multiple attempts to set the same parameter would raise an exception.
Public Functions
-
explicit Scope(std::int32_t priority)#
Constructs a Scope with a given task priority.
Equivalent to
auto scope = Scope(); scope.set_priority(priority);
- Parameters:
priority – Task priority to set to the scope
-
explicit Scope(ExceptionMode exception_mode)#
Constructs a Scope with a given exception mode.
Equivalent to
auto scope = Scope(); scope.set_exception_mode(exception_mode);
- Parameters:
exception_mode – Exception mode to set to the scope
-
explicit Scope(std::string provenance)#
Constructs a Scope with a given provenance string.
Equivalent to
auto scope = Scope(); scope.set_provenance(provenance);
- Parameters:
provenance – Provenance string to set to the scope
-
explicit Scope(const mapping::Machine &machine)#
Constructs a Scope with a given machine.
Equivalent to
auto scope = Scope(); scope.set_machine(machine);
The given machine is intersected with the machine from the outer scope
See also
- Parameters:
machine – Machine to use within the scope
- Throws:
std::runtime_error – If the intersected machine is empty
-
Scope &&with_priority(std::int32_t priority) &&#
Sets a given task priority to the scope.
- Parameters:
priority – Task priority to set to the scope
- Throws:
std::invalid_argument – If a task priority has already been set via this Scope object
-
Scope &&with_exception_mode(ExceptionMode exception_mode) &&#
Sets a given exception mode to the scope.
- Parameters:
exception_mode – Exception mode to set to the scope
- Throws:
std::invalid_argument – If an exception mode has already been set via this Scope object
-
Scope &&with_provenance(std::string provenance) &&#
Sets a given provenance string to the scope.
- Parameters:
provenance – Provenance string to set to the scope
- Throws:
std::invalid_argument – If a provenance string has already been set via this Scope object
-
Scope &&with_machine(const mapping::Machine &machine) &&#
Sets a given machine to the scope.
The given machine is intersected with the machine from the outer scope
See also
- Parameters:
machine – Machine to use within the scope
- Throws:
std::runtime_error – If the intersected machine is empty
std::invalid_argument – If a machine has already been set via this Scope object
-
void set_priority(std::int32_t priority)#
Sets a given task priority to the scope.
- Parameters:
priority – Task priority to set to the scope
- Throws:
std::invalid_argument – If a task priority has already been set via this Scope object
-
void set_exception_mode(ExceptionMode exception_mode)#
Sets a given exception mode to the scope.
- Parameters:
exception_mode – Exception mode to set to the scope
- Throws:
std::invalid_argument – If an exception mode has already been set via this Scope object
-
void set_provenance(std::string provenance)#
Sets a given provenance string to the scope.
- Parameters:
provenance – Provenance string to set to the scope
- Throws:
std::invalid_argument – If a provenance string has already been set via this Scope object
-
void set_machine(const mapping::Machine &machine)#
Sets a given machine to the scope.
The given machine is intersected with the machine from the outer scope, so the actual machine used in this scope will always be a subset of the outer scope’s.
For example, if the machine of the current scope has GPUs 2, 3, 4, and 5, and a new scope is created with another machine with GPUs 3, 4, 5, and 6, then only the GPUs 3, 4, and 5 will be set to the new scope.
- Parameters:
machine – Machine to use within the scope
- Throws:
std::runtime_error – If the intersected machine is empty
std::invalid_argument – If a machine has already been set via this Scope object
Public Static Functions
-
static std::int32_t priority()#
Returns the task priority of the current scope.
return Current task priority
-
static legate::ExceptionMode exception_mode()#
Returns the exception mode of the current scope.
return Current exception mode
-
static std::string_view provenance()#
Returns the provenance string of the current scope.
- Returns:
Current provenance string
-
class Impl#
-
explicit Scope(std::int32_t priority)#
-
class Time#
- #include <legate/timing/timing.h>
Deferred timestamp class.
Public Functions
-
class Impl#
-
class Impl#
-
template<typename T>
class ProcLocalStorage# - #include <legate/utilities/proc_local_storage.h>
A helper data structure to store processor-local objects.
Oftentimes, users need to create objects, usually some library handles, each of which is associated with only one processor (GPU, most likely). For those cases, users can create a
ProcLocalStorage<T>
that holds a unique singleton object of typeT
for each processor thread. The object can be retrieved simply by theget()
method and internally the calls are distinguished by IDs of the processors invoking them.Two parallel tasks running on the same processor will get the same object if they query the same
ProcLocalStorage
. Atomicity of access to the storage is guaranteed by the programming model running parallel tasks atomically on each processor; in other words, no synchronization is needed to call theget()
method on aProcLocalStorage
even when it’s shared by multiple tasks.Despite the name, the values that are stored in this storage don’t have static storage duration, but they are alive only as long as the owning
ProcLocalStorage
object is.This example uses a
ProcLocalStorage<int>
to count the number of task invocations on each processor:static void cpu_variant(legate::TaskContext context) { static legate::ProcLocalStorage<int> counter{}; if (!storage.has_value()) { // If this is the first visit, initialize the counter counter.emplace(1); } else { // Otherwise, increment the counter by 1 ++counter.get(); } }
- Template Parameters:
T – Type of values stored in this
ProcLocalStorage
.
Public Functions
-
bool has_value() const#
Checks if the value has been created for the executing processor.
- Returns:
true
if the value exists,false
otherwise.
-
template<typename ...Args>
value_type &emplace(Args&&... args)# Constructs a new value for the executing processor.
The existing value will be overwritten by the new value.
- Parameters:
args – Arguments to the constructor of type
T
.
-
value_type &get()#
Returns the value for the executing processor.
- Throws:
std::logic_error – If no value exists for this processor (i.e., if
has_value()
returnsfalse
), or if the method is invoked outside a task- Returns:
the value for the executing processor.
-
const value_type &get() const#
Returns the value for the executing processor.
- Throws:
std::logic_error – If no value exists for this processor (i.e., if
has_value()
returnsfalse
), or if the method is invoked outside a task- Returns:
the value for the executing processor
-
template<typename F>
class ScopeGuard# - #include <legate/utilities/scope_guard.h>
A simple wrapper around a callable that automatically executes the callable on exiting the scope.
- Template Parameters:
F – The type of the callable to execute.
Public Types
-
using value_type = F#
The type of callable stored within the ScopeGuard.
Public Functions
-
explicit ScopeGuard(value_type &&fn, bool enabled = true) noexcept#
Construct a ScopeGuard.
On destruction, a ScopeGuard will execute
fn
if and only if it is in the enabled state.fn
will be invoked with no arguments, and any return value discarded.fn
must be no-throw move-constructible, and must not throw any exceptions when invoked.See also
See also
See also
See also
- Parameters:
fn – The function to execute.
enabled – Whether the ScopeGuard should start in the “enabled” state.
-
ScopeGuard(ScopeGuard &&other) noexcept#
Move-construct a ScopeGuard.
other
will be left in the “disabled” state, and will not execute its held functor upon destruction. Furthermore, the held functor is moved into the receiving ScopeGuard, soother's
functor may be in an indeterminate state. It is therefore not advised to re-enableother
.- Parameters:
other – The ScopeGuard to move from.
-
ScopeGuard &operator=(ScopeGuard &&other) noexcept#
Construct a ScopeGuard via move-assignment.
This routine has no effect if
other
andthis
are the same.other
will be left in the “disabled” state, and will not execute its held functor upon destruction. Furthermore, the held functor is moved into the receiving ScopeGuard, soother's
functor may be in an indeterminate state. It is therefore not advised to re-enableother
.- Parameters:
other – The ScopeGuard to move from.
- Returns:
A reference to
this
.
-
~ScopeGuard() noexcept#
Destroy a ScopeGuard.
If the ScopeGuard is currently in the enabled state, executes the held functor, otherwise does nothing.
-
bool enabled() const#
Query a ScopeGuard’s state.
See also
See also
- Returns:
true if the ScopeGuard is enabled, false otherwise.
-
void disable()#
Disable a ScopeGuard.
This routine prevents a ScopeGuard from executing its held functor on destruction. On return, ScopeGuard::enabled() will return false.
Calling this routine on an already disabled ScopeGuard has no effect.
See also
-
void enable()#
Enable a ScopeGuard.
This routine makes a ScopeGuard execute its held functor on destruction. On return, ScopeGuard::enabled() will return true.
Calling this routine on an already enabled ScopeGuard has no effect.
See also
-
template<typename F>
class ScopeFail# - #include <legate/utilities/scope_guard.h>
Similar to ScopeGuard, except that the callable is only executed if the scope is exited due to an exception.
- Template Parameters:
F – The type of the callable to execute.
Public Functions
-
explicit ScopeFail(value_type &&fn) noexcept#
Construct a ScopeFail.
On destruction, a ScopeFail will execute
fn
if and only if the scope is being exited due to an uncaught exception. Therefore, unlike ScopeGuard, it is not possible to “disable” a ScopeFail.fn
will be invoked with no arguments, and any return value discarded.fn
must be no-throw move-constructible, and must not throw any exceptions when invoked.See also
- Parameters:
fn – The function to execute.
-
LEGATE_CONCAT_(x, ...)#