Notes on Programming in Legion
Last Modified 2022-03-15
Construct a region from an index space and a field space :
LogicalRegion rt->create_logical_region(*, IndexSpace I, FieldSpace F);
This function takes an optional argument bool task_local = false
. Setting bool task_local = true
informs Legion that the region being created will not outlive the task it is created in (i.e., it can be used by the current task and its children, but it cannot propagate up the task tree). In this case, Legion will automatically destroy the region at the end of the current task, and destroy_logical_region
must not be called on a task-local region. This is only example I know of where a create_*
call must not be paired with a corresponding destroy_*
call.
Retrieve the underlying index space and field space from a region :
IndexSpace R.get_index_space() const;
FieldSpace R.get_field_space() const;
Note that these are not runtime calls rt->...
, but rather, methods on the LogicalRegion
object R
. This is an inconsistency in the Legion API.
Retrieve the underlying index space and color space of an index partition :
IndexSpace rt->get_parent_index_space(IndexPartition P);
IndexSpace rt->get_index_partition_color_space_name(IndexPartition P);
Construct a logical partition from a logical region and an index partition :
LogicalPartition rt->get_logical_partition(LogicalRegion R, IndexPartition P);
For the purposes of Legion application development, a logical partition is simply a container that holds a logical region and an index partition , both based on the same underlying index space . The creation of a logical partition does not dynamically allocate any resources, so this function is called get_logical_partition
rather than create_logical_partition
, and there is no need for a corresponding destroy_logical_partition
call. (The function rt->destroy_logical_partition
does exist, but only for the purpose of backward compatibility; it is now a no-op.)
Retrieve the underlying field space , logical region , and index partition from a logical partition :
FieldSpace LP.get_field_space() const;
LogicalRegion rt->get_parent_logical_region(LogicalPartition LP);
IndexPartition LP.get_index_partition() const;
Note that the underlying logical region is obtained via a runtime call, while the index space and index partition are retrieved through methods on the LogicalPartition
object LP
itself. The Legion API does not provide a mechanism to directly obtain the index space or color space ; these must be retrieved through the index partition .
Reduce all the return values into a single value using the specified reduction operator into a single future value. The reduction operation must be a foldable reduction. * @param deterministic request that the reduced future value be computed * in a deterministic way (more expensive than non-deterministic)
Future execute_task(*, const TaskLauncher &launcher);
FutureMap execute_index_space(*, const IndexTaskLauncher &launcher);
Future execute_index_space(*, const IndexTaskLauncher &launcher,
ReductionOpID redop, bool deterministic = false);
* Create a new top-level index space based on the given domain bounds
* If the bounds contains a Realm index space then Legion will take ownership of any sparsity maps.
* @param bounds the bounds for the new index space
* @param type_tag optional type tag to use for the index space
IndexSpace create_index_space(*, const Domain &bounds, TypeTag type_tag = 0);
IndexSpaceT<DIM, COORD_T> create_index_space(*, const Rect<DIM, COORD_T> &bounds);
IndexSpaceT<DIM, COORD_T> create_index_space(*, const DomainT<DIM, COORD_T> &bounds);
* Create a new top-level index space from a future which contains a Domain object.
* If the Domain conaints a Realm index space then Legion will take ownership of any sparsity maps.
* @param dimensions number of dimensions for the created space
* @param future the future value containing the bounds
* @param type_tag optional type tag to use for the index space; defaults to 'coord_t'
IndexSpace create_index_space(*, size_t dimensions, const Future &f, TypeTag type_tag = 0);
IndexSpaceT<DIM,COORD_T> create_index_space(*, const Future &f);
* Create a new top-level index space from a vector of points
* @param points a vector of points to have in the index space
IndexSpace create_index_space(*, const std::vector<DomainPoint> &points);
IndexSpaceT<DIM, COORD_T> create_index_space(*, const std::vector<Point<DIM, COORD_T>> &points);
* Create a new top-level index space from a vector of rectangles
* @param rects a vector of rectangles to have in the index space
IndexSpace create_index_space(*, const std::vector<Domain> &rects);
IndexSpaceT<DIM, COORD_T> create_index_space(*, const std::vector<Rect<DIM, COORD_T>> &rects);
Resource Management
In C, every call to malloc
should be matched with a corresponding call to free
. Similarly, in Legion, every runtime call of the form create_*
should be matched with a corresponding destroy_*
call.
void rt->destroy_index_space(*, IndexSpace I);
void rt->destroy_index_partition(*, IndexPartition P);
void rt->destroy_field_space(*, FieldSpace F);
void rt->destroy_logical_region(*, LogicalRegion R);
All of the above destroy_*
methods in Legion take an optional bool unordered = false
parameter. Setting unordered = true
informs Legion that this call to destroy_*
may occur simultaneously with use of the resource being destroyed. This is necessary when the call to destroy_*
is performed by a thread other than the one using the resource being destroyed, e.g., a garbage collector. In addition, destroy_index_space
and destroy_index_partition
take another optional parameter bool recurse = true
that controls whether subspaces of the given index space (i.e., children of in the index tree) should also be destroyed.
Reference Counting
void rt->create_shared_ownership(*, IndexSpace I);
void rt->create_shared_ownership(*, IndexPartition P);
void rt->create_shared_ownership(*, FieldSpace F);
void rt->create_shared_ownership(*, LogicalRegion R);
bool rt->is_index_partition_disjoint(IndexPartition P);
bool rt->is_index_partition_complete(IndexPartition P);
bool rt->has_parent_index_partition(IndexSpace I);
size_t rt->get_field_size(FieldSpace F, FieldID fid);
void rt->get_field_space_fields(FieldSpace F, std::vector<FieldID> &fids);
void rt->get_field_space_fields(FieldSpace F, std::set<FieldID> &fids);
bool rt->has_parent_logical_partition(LogicalRegion handle);
LogicalPartition rt->get_parent_logical_partition(LogicalRegion handle);
These functions do exactly what you think they do.