Regent: a high-Productivity Programming Language for hpc with Logical Regions



Yüklə 254,9 Kb.
Pdf görüntüsü
səhifə4/8
tarix23.02.2018
ölçüsü254,9 Kb.
#27490
1   2   3   4   5   6   7   8

Conceptually, index launches simply represent a loop of task

launches. Listing 2 lines 16-18 shows an example of a Re-

gent loop that can be transformed into an index launch (with

corresponding C++ code in Listing 4). However, the Legion

runtime places several restrictions on index launches to en-

sure that they are well-behaved:

1. Arguments to all tasks in the index launch must be

computed outside the launch, guaranteeing that argu-

ments are available and that no arguments depend on

side-effects from tasks within the launch.

2. Futures, if any, are added to the launch as a whole,

not to individual tasks.

3. Requirements can be in one of two forms:

• Individual region requirements add a single region

to all tasks in the launch.

• Partition requirements add a subregion of the par-

tition for each task.

Legion supports user-defined projection functions to

allow the programmer to dynamically select subregions

for each type of region requirement.

4. Because an index launch implies parallel execution, all

the tasks must be non-interfering.

5. If tasks within the launch return a value, then the

launch as a whole is allowed to either return a map

with all the resulting futures, or to reduce the futures

into a single value.

When executing an index launch, the runtime still per-

forms dynamic checks to ensure that the tasks within the

launch are non-interfering. However, Legion is able to amor-

tize these checks across the entire index launch instead of

performing them individually.

3.2


Regions

Logical regions are created as the cross product of an index

space (set of indices) and a field space (set of fields). Logi-

cal regions can be compared to arrays of objects or structs,

though this analogy falls short in several ways. In particular,

as discussed previously, because a logical region may have

multiple physical instances, there is no one-to-one mapping

between a logical region and its representation in memory.

3.2.1

Physical Instances



In Legion, a logical region may, at any given point in

time, map to zero or more physical instances. Access to

each field of a physical instance is mediated through a field-

specific accessor. In the Legion C++ interface, the program-

mer must manage distinct

LogicalRegion

,

PhysicalRegion



, and

Accessor


types.

In Regent, these differences disappear because the com-

piler manages the mapping from logical to physical regions

(and physical regions to accessors) transparently for the pro-

grammer. Field spaces can be constructed concisely from

struct types, and nested structs are automatically expanded

into their component fields. Accessors are created automat-

ically for whatever fields the programmer declared in the

privileges for the task. These differences are illustrated in

the difference between Listing 1 and Listing 3. In contrast

to users of the Legion C++ API, Regent programmers can

usually pretend that regions are simply arrays of structs or

objects.

Physical instances in Legion may be stored in one of a

number of layouts. Examples of common layouts include

array-of-structs and struct-of-arrays, while more esoteric lay-

outs may include arrays blocked for vectorized CPU instruc-

tions. Legion provides explicit accessor objects in order to

constant-fold compile-time information about instance lay-

outs for efficient access, as seen in Listing 3 lines 6-17. Re-

gent manages accessors, along with instances, on behalf of

the programmer.

Regent also manages the creation of region requirements

for each task.

For each task, Regent flattens the fields,

groups them by privilege, and issues a region requirement

for each privilege and set of fields; see the correspondence

between Listing 2 line 17 and Listing 4 lines 6-22.

3.2.2

Partitions



Partitioning a region using the Legion C++ interface hap-

pens in two steps. First, the user creates an index partition

of the index space to specify how the sets of indices are sub-

divided between the spaces. Second, the user applies the

index partition to a logical region created using that same

index space to obtain a corresponding logical partition. In

Regent, these operations are combined, as the correspon-

dence between logical regions and index spaces is managed

for the programmer.

3.3


Mapping

As briefly described previously, mapping is the process of

selecting a processor to run each task and a memory (and

data layout) for each logical region. Mapping is under the

control of the application, though Regent provides a default

mapper with sensible settings to allow users to get up and

running quickly.

Legion also provides a mapping interface, but because of

the distinction between physical and logical constructs ex-

posed in Legion, this mapping process is more involved.

In Legion, logical regions must be mapped to physical

instances in a specific memory before they can be used. By

default, at the start of a task Legion automatically maps

each region used by the task, and when the task ends each

of those regions is unmapped. Before launching a subtask

a parent task must also unmap any region that the child

task needs to use. By default, the Legion runtime unmaps

all of the parent’s regions before calling a child and remaps

them when the child terminates. While this default behavior

guarantees correct execution, if the parent and child have

interfering privileges for a region (e.g., both can write the

region) then the parent will most likely block until the child

terminates, as the parent cannot remap the region until the

child unmaps it (recall the discussion in Section 3.1.2).

For higher performance, Legion programmers can explic-

itly manage region mappings themselves through explicit

map and unmap calls provided by the Legion interface. By

unmapping a region, the programmer notifies the runtime

that the data in that region is not required by the parent

task until a corresponding map call is issued. In typical us-

age, programmers unmap all regions before entering a main

loop, and remap all regions once the loop completes, which

ensures that the runtime can avoid blocking when issuing

tasks within that loop. An example of such an unmap call




Yüklə 254,9 Kb.

Dostları ilə paylaş:
1   2   3   4   5   6   7   8




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©genderi.org 2024
rəhbərliyinə müraciət

    Ana səhifə