[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9. `TOP-C' Raw Interface for Parallelizing Sequential Code

There are instances when tasks are most naturally generated deep inside nested loops. Often, this occurs in parallelizing existing sequential applications. In such circumstances, it may be difficult to re-write the code to create a function GenerateTaskInput(), since that would require turning the loops inside out. (If you don't know what this refers to, then you probably don't need the raw interface.)

On a first reading, you may wish to first look at the example for either a `for' loop or `while' loop, depending on the type of loop that you are parallelizing. Then return to the formal descriptions of the `TOP-C' raw functions. This chapter assumes familiarity with the basic concepts of 3. Overview of `TOP-C/C++' and 4. Writing `TOP-C' Applications.

9.1 `TOP-C' raw functions  
9.2 Parallelizing `for' Loops  
9.3 Parallelizing `while' Loops  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.1 `TOP-C' raw functions

Function: void TOPC_raw_begin_master_slave
(do_task, check_task_result, update_shared_data)
Function: void TOPC_raw_end_master_slave ()
This behaves like master_slave, with TOPC_raw_submit_task_input(input) serving the role of GenerateTaskInput(). The slave blocks inside TOPC_raw_begin_master_slave() and executes `do_task()' and `update_shared_data()' until the master executes TOPC_raw_end_master_slave(). At that time, the slave unblocks. The slave does nothing inside TOPC_raw_end_master_slave().

Function: void TOPC_raw_submit_task_input ( TOPC_BUF input )
Invoked by master between TOPC_raw_begin_master_slave() and TOPC_raw_end_master_slave(); Typical usage is:
 
     TOPC_raw_submit_task_input(TOPC_MSG(&input_data,
                                         sizeof(input_data)) );
The argument, input, corresponds to what would be returned by GenerateTaskInput() in the routine TOPC_master_slave(). input will be processed by DoTask() and its siblings, just as in TOPC_master_slave()). There can be multiple occurrences of TOPC_raw_submit_task_input().

Function: TOPC_BOOL TOPC_raw_wait_for_task_result ()
Invoked by master between TOPC_raw_begin_master_slave() and TOPC_raw_end_master_slave(); If no tasks are outstanding, returns false immediately. Otherwise, it blocks until a task does return. It calls application callback, CheckTaskResult(), and then returns true.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.2 Parallelizing `for' Loops

Assume that we are parallelizing a code fragment of the following form. The variables i and j will be the input to DoTask(), and any data structures indexed by i and j (for example array in array[i][j]) will be part of the shared data.
 
  float array[ROWS][COLS];
  ...
    for ( i = 0; i < 10; i++ ) {
      for ( j = 0; j < 10; j++ ) {
        /* do_task: */ ...
        /* update:  */ array[i][j] = ...;
      }
    }

Assume that the labels do_task and update above correspond to the callback functions DoTask() and UpdateSharedData(). Then the code is parallelized below.

 
  float array[ROWS][COLS];
  typedef struct {int i_val; int j_val;} input_t;
  void *DoTask(input_t *buf) {
    int i = (*buf).i_val, j = (*buf).j_val;
    /* do_task: */ ...
  }
  void *CheckTaskResult(input_t *buf, output_t *buf2) {
    /* update:  */ array[i][j] = ...;
    return NO_ACTION;
  }
  main(int argc, char **argv) {
    TOPC_init( &argc, &argv );
    TOPC_raw_begin_master_slave(DoTask, CheckTaskResult,
                                UpdateSharedData);
    if (TOPC_is_master()) {
      for ( i = 0; i < 10; i++ ) {
        for ( j = 0; j < 10; j++ ) {
          input_t input;
          input.i_val = i; input.j_val = j;
          TOPC_raw_submit_task_input( TOPC_MSG(&input, sizeof(input)) );
        }
      }
    } TOPC_raw_end_master_slave();
    TOPC_finalize();
  }


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.3 Parallelizing `while' Loops

Assume that we are parallelizing a code fragment of the following form and input is a pointer.
 
  while ( (input = next_input()) != NULL ) {
    /* do_task: */ ...
    /* update:  */ ...
  }

Assume that the labels do_task and update above correspond to the callback functions DoTask() and UpdateSharedData(). Then the code is parallelized below, where input_size must be specified by the application before it is used.

 
  TOPC_init( &argc, &argv );
  TOPC_raw_begin_master_slave(DoTask, CheckTaskResult,
                              UpdateSharedData);
  if (TOPC_is_master()) {
    while ( (input = next_input()) != NULL
            || TOPC_raw_wait_for_task_result() ) {
      TOPC_raw_submit_task_input( TOPC_MSG(input, input_size) );
    }
  } TOPC_raw_end_master_slave();
  TOPC_finalize();

Note that the code inside the raw begin/end block is executed only by the master in the code above.

If the buffer, input, contains pointers to other data, then you will need to marshal the data before calling TOPC_MSG(). See section Marshaling and Heterogeneous Architectures.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Gene Cooperman on October, 6 2004 using texi2html