Download Sequoia++ User Manual
Transcript
run on two arrays, storing the result in the second array argument. The final result is stored back at the parent memroy level. The reducearg need not be an entire array. In the example the reducearg shown above reduces the entire matrix c into the final matrix c. The reduction also can be done on independent sub-blocks of the matrix c by using array blocking to specify sub-blocks of the matrix. Array blocking is described in Section 5.6. 5.5 Task Calls There are a few rules of thumb for getting the best performance and portability from tasks: • The best performance is achieved if only task calls are placed in the parallel control constructs. • For maximum portability task calls should be generic: they should not name which variant of the task is to be called. The variant is specified in the mapping file. • Tasks should be designed to break big problems into smaller problems recursively if that is appropriate to the problem being solved. Thus the inner task variant will typically call the same task (with no variant specified). This recursive structure will be mapped by the compiler on to the memory hierarchy of the machine, with as many instances of the inner task as needed to cover the number of levels of the target machine. Note that tasks can only be called after they have been declared; forward declarations can be used if necessary. 5.5.1 Entrypoints and Callsites If a task is called from outside of Sequoia (for example calling a task from main() in a C program), that instance of the task must be labelled with an entrypoint. The entrypoint construct is described in Section 8.3. When a task calls another task an entrypoint is not used, instead one defines a callsite inside the control block of the instance of the calling task (see Section 8.2). 5.6 Array Blocking Array blocking allows the programmer to partition an array into smaller arrays. In combination with one of the Sequoia control constructs a programmer can pass the different parts of the array to different task instances. Consider again the matrix multiplication example: // a, b, and c are two dimensional arrays mappar( int i = 0 : M/mBlock , int j = 0 : N/nBlock ) mapseq( int k = 0 : P/pBlock ) matrixmult(a[i*mBlock;mBlock][k*pBlock;pBlock], b[k*pBlock;pBlock][j*nBlock;nBlock], c[i*mBlock;mBlock][j*nBlock;nBlock]); Each task is passed a portion of each of arrays a, b, and c. The task either recursively subdivides its portions of the arrays in further task calls (for an inner task call) or performs an actual matrix multiplication (in a leaf task call). Notice that each dimension of the array has its own pair of brackets [...]. Arrays must always be fully indexed, meaning that a n-dimensional array must always be used with all n dimensions. Array blocking has two arguments per dimension. The first argument describes the index where the block begins, and the second argument specifies the number of elements. For example, for the a matrix in the x dimension, the partition passed to the i-th task consists of mBlock elements beginning at index i ∗ mBlock. For the y dimension pBlock elements are taken beginning at k ∗ pBlock. Note that many different parallel tasks (all with different values of j) are passed the same sub-array of a. Because a is declared to be an in (read-only) parameter it presents no problem for multiple tasks to share the same portion of a. However, any argument annotated out or inout can only be passed to a single parallel task as it is undefined what occurs if multiple parallel tasks attempt to write the same output location. As discussed previously, this requirement is not currently checked by the Sequoia compiler. 13