This example shows how you can use the task context to keep the partial computing results for each task instance and then combine these partial results into the final result.
The example finds the minimum and maximum values in a large data set. The sequential code is a very simple textbook style implementation, it is a linear search across the whole data set, which compares and updates the best known values with each step.
You can use ALF framework to convert the sequential code into a parallel algorithm. The data set must be partitioned into smaller work blocks. These work blocks are then assigned to the different task instances running on the accelerators. Each invocation of a computational kernel on a task instance is to find the maximum or minimum value in the work block assigned to it. After all the work blocks are processed, you have multiple intermediate best values in the context of each task instance. The ALF runtime then calls the context merge function on accelerators to reduce the intermediate results into the final results.
/* ---------------------------------------------- */ /* the accelerator side code */ /* ---------------------------------------------- */ /* the computation kernel function */ int comp_kernel(void *p_task_context, void *p_parm_ctx_buffer, void *p_input_buffer, void *p_output_buffer, void *p_inout_buffer, unsigned int current_count, unsigned int total_count) { my_task_context_t *p_ctx = (my_task_context_t *) p_task_context; my_wb_parms_t *p_parm = (my_wb_parms_t *) p_parm_ctx_buffer; alf_data_int32_t *a = (alf_data_int32_t *)p_input_buffer; unsigned int size = p_parm->num_data; unsigned int i; /* update the best known values in context buffer */ for(i=0;i<size;i++) { if(a[i]>p_ctx->max) p_ctx->max = a[i]; else if(a[i]<p_ctx->min) p_ctx->min = a[i]; } return 0; }
The following code segment shows the context_merge function for this application. This function is automatically invoked by the ALF runtime after all the task instances have finished processing all the work blocks. The final minimum and maximum values stored in the task context per task instance are merged through this function.
/* the context merge function */ int ctx_merge(void* p_task_context_to_be_merged, void* p_task_context) { my_task_context_t *p_ctx = (my_task_context_t *) p_task_context; my_task_context_t *p_mgr_ctx = (my_task_context_t *) p_task_context_to_be_merged; if(p_mgr_ctx->max > p_ctx->max) p_ctx->max = p_mgr_ctx->max; if(p_mgr_ctx->min < p_ctx->min) p_ctx->min = p_mgr_ctx->min; return 0; }