Next: Proper use of conditionals, Previous: Tips and Tricks, Up: Tips and Tricks [Contents][Index]
See Task descriptions, mentions a language feature that can substantially simplify coNCePTuaL programs: Operations involving out-of-bound task IDs are silently ignored. The beauty of this feature is that it reduces the need for special cases at network boundaries. Consider, for example, a simple pipeline pattern in which each task in turn sends a message to the subsequent task:
ALL TASKS t SEND A 64 DOUBLEWORD MESSAGE TO TASK t+1.
Because implicit receives are posted before the corresponding sends (see Sending), all tasks except task 0 start by posting a blocking receive. (No task is sending to task 0.) Task 0 is therefore free to send a message to task 1 . Receipt of that message unblocks task 1, who then sends a message to task 2, thereby unblocking task 3, and so forth. Without needing an explicit special case in the program, task ‘num_tasks-1’ receives a message from task ‘num_tasks-2’ but does not attempt to send a message to nonexistent task ‘num_tasks’, thanks to the rule that communication with nonexistent tasks turns into a no-op (i.e., is elided from the program).
As a more complex variation of the same program, consider a wavefront communication pattern that progresses from the upper-left corner of a mesh to the lower-right corner. Such a pattern can be expressed in just four lines of coNCePTuaL (receive left, receive up, send right, send down) by relying on the property that communication with a nonexistent task is simply not executed:
TASK MESH_NEIGHBOR(src, xsize, +1, ysize, 0) RECEIVES A 64 DOUBLEWORD MESSAGE FROM ALL TASKS src THEN TASK MESH_NEIGHBOR(src, xsize, 0, ysize, +1) RECEIVES A 64 DOUBLEWORD MESSAGE FROM ALL TASKS src THEN ALL TASKS src SEND A 64 DOUBLEWORD MESSAGE TO UNSUSPECTING TASK MESH_NEIGHBOR(src, xsize, +1, ysize, 0) THEN ALL TASKS src SEND A 64 DOUBLEWORD MESSAGE TO UNSUSPECTING TASK MESH_NEIGHBOR(src, xsize, 0, ysize, +1).
To understand the preceding program recall that
MESH_NEIGHBOR
returns ‘-1’ for
nonexistent neighbors. Because ‘-1’ is outside of the
range [0, num_tasks
) communication
with a nonexistent neighbor is ignored. To help the reader
understand the preceding program, we present a trace of the events
it posts as it runs with a 2 by 2 arrangement of
tasks:
[TRACE] phys: 0 | virt: 0 | action: SEND | event: 1 / 2 | lines: 3 - 3 [TRACE] phys: 1 | virt: 1 | action: RECV | event: 1 / 2 | lines: 1 - 1 [TRACE] phys: 2 | virt: 2 | action: RECV | event: 1 / 2 | lines: 2 - 2 [TRACE] phys: 3 | virt: 3 | action: RECV | event: 1 / 2 | lines: 1 - 1 [TRACE] phys: 0 | virt: 0 | action: SEND | event: 2 / 2 | lines: 4 - 4 [TRACE] phys: 1 | virt: 1 | action: SEND | event: 2 / 2 | lines: 4 - 4 [TRACE] phys: 2 | virt: 2 | action: SEND | event: 2 / 2 | lines: 3 - 3 [TRACE] phys: 3 | virt: 3 | action: RECV | event: 2 / 2 | lines: 2 - 2
The
c_trace
backend (see The c_trace
backend) was used to produce that trace. To increase clarity,
we manually added blank lines to group concurrent events (i.e.,
there is no significance to the order of the TRACE
lines within each group). The important thing to notice is that
there are exactly four receives and exactly four sends:
Because communication with nonexistent tasks is elided at
program initialization time there is no run-time cost for such
operations—as evidenced by the
c_trace
output presented above. Furthermore, there is
no reliance on the backend to drop messages from nonexistent
senders or to nonexistent receivers; it is perfectly safe to
utilize no-op’ed communcation in any coNCePTuaL program and when
using any backend.
Next: Proper use of conditionals, Previous: Tips and Tricks, Up: Tips and Tricks [Contents][Index]