diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fc094ff7..11ad18653 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,6 +157,8 @@ option(PARSEC_DIST_PRIORITIES "Favor the communications that unlock the most prioritary tasks" ON) option(PARSEC_DIST_COLLECTIVES "Use optimized asynchronous operations where collective communication pattern is detected" ON) +option(PARSEC_ALLOW_PARAMETRIZED_FLOWS + "Enable parametrized flows" OFF) set (PARSEC_DIST_SHORT_LIMIT 1 CACHE STRING "Use the short protocol (no flow control) for messages smaller than the limit in KB. Performs better if smaller than the MTU") @@ -689,7 +691,7 @@ int main(int argc, char *argv[]) { if (CUDAToolkit_FOUND) message(STATUS "Found CUDA ${CUDAToolkit_VERSION} in ${CUDAToolkit_LIBRARY_DIR}") CMAKE_PUSH_CHECK_STATE() - list(APPEND CMAKE_REQUIRED_LIBRARIES CUDA::cudart) + list(APPEND CMAKE_REQUIRED_LIBRARIES CUDA::cudart) # This adds the wrong version of cudart if there are multiple versions installed if(CUDAToolkit_VERSION VERSION_LESS "4.0") set(PARSEC_HAVE_PEER_DEVICE_MEMORY_ACCESS 0) else() diff --git a/parsec/CMakeLists.txt b/parsec/CMakeLists.txt index 46a815729..a3a893906 100644 --- a/parsec/CMakeLists.txt +++ b/parsec/CMakeLists.txt @@ -122,7 +122,8 @@ set(SOURCES maxheap.c hbbuffer.c datarepo.c - termdet.c) + termdet.c + task_class.c) if( PARSEC_PROF_TRACE ) list(APPEND SOURCES dictionary.c) endif( PARSEC_PROF_TRACE ) @@ -302,6 +303,7 @@ if( BUILD_PARSEC ) ${CMAKE_CURRENT_SOURCE_DIR}/bindthread.h ${CMAKE_CURRENT_SOURCE_DIR}/parsec_comm_engine.h ${CMAKE_CURRENT_SOURCE_DIR}/include/parsec/deprecated.h + ${CMAKE_CURRENT_SOURCE_DIR}/task_class.h DESTINATION ${PARSEC_INSTALL_INCLUDEDIR}/parsec) install(FILES diff --git a/parsec/data_dist/CMakeLists.txt b/parsec/data_dist/CMakeLists.txt index c28c3d4da..f77eaead6 100644 --- a/parsec/data_dist/CMakeLists.txt +++ b/parsec/data_dist/CMakeLists.txt @@ -1,5 +1,6 @@ set(sources - ${CMAKE_CURRENT_LIST_DIR}/hash_datadist.c) + ${CMAKE_CURRENT_LIST_DIR}/hash_datadist.c + ${CMAKE_CURRENT_LIST_DIR}/multidimensional_grid.c) add_subdirectory(matrix) @@ -7,5 +8,6 @@ target_sources(parsec PRIVATE ${sources}) set_property(TARGET parsec APPEND PROPERTY - PRIVATE_HEADER_H data_dist/hash_datadist.h) + PRIVATE_HEADER_H data_dist/hash_datadist.h + data_dist/multidimensional_grid.h) diff --git a/parsec/data_dist/matrix/map_operator.c b/parsec/data_dist/matrix/map_operator.c index 204763bab..3297ccd4c 100644 --- a/parsec/data_dist/matrix/map_operator.c +++ b/parsec/data_dist/matrix/map_operator.c @@ -199,7 +199,7 @@ add_task_to_list(parsec_execution_stream_t *es, static void iterate_successors(parsec_execution_stream_t *es, const parsec_task_t *this_task, - uint32_t action_mask, + parsec_dependency_t action_mask, parsec_ontask_function_t *ontask, void *ontask_arg) { @@ -245,7 +245,7 @@ static void iterate_successors(parsec_execution_stream_t *es, static int release_deps(parsec_execution_stream_t *es, parsec_task_t *this_task, - uint32_t action_mask, + parsec_dependency_t action_mask, parsec_remote_deps_t *deps) { parsec_task_t** ready_list; diff --git a/parsec/data_dist/matrix/redistribute/redistribute_wrapper.c b/parsec/data_dist/matrix/redistribute/redistribute_wrapper.c index 5b143cc62..1e5ba6cad 100644 --- a/parsec/data_dist/matrix/redistribute/redistribute_wrapper.c +++ b/parsec/data_dist/matrix/redistribute/redistribute_wrapper.c @@ -204,4 +204,3 @@ int parsec_redistribute(parsec_context_t *parsec, return PARSEC_ERR_NOT_SUPPORTED; } - diff --git a/parsec/data_dist/multidimensional_grid.c b/parsec/data_dist/multidimensional_grid.c new file mode 100644 index 000000000..5e058f0f7 --- /dev/null +++ b/parsec/data_dist/multidimensional_grid.c @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2010-2021 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + */ +/************************************************************ + *distributed multidimensional_grid generation + ************************************************************/ + +#include "parsec/parsec_config.h" +#include "parsec/parsec_internal.h" +#include "parsec/utils/debug.h" +#include "parsec/data.h" +#include "parsec/data_distribution.h" +#include "parsec/data_dist/multidimensional_grid.h" +#include "parsec/data_dist/matrix/two_dim_rectangle_cyclic.h" +#include "parsec/data_dist/matrix/sym_two_dim_rectangle_cyclic.h" +#include "parsec/data_dist/matrix/two_dim_tabular.h" + +#if defined(PARSEC_HAVE_MPI) +#include +#endif +#include + +#include "parsec/parsec_config.h" +#include "parsec/parsec_internal.h" +#include "parsec/utils/debug.h" +#include "parsec/data_dist/matrix/matrix.h" +#include "parsec/data_dist/matrix/two_dim_rectangle_cyclic.h" +#include "parsec/data_dist/matrix/matrix_internal.h" +#include "parsec/mca/device/device.h" +#include "parsec/vpmap.h" + + +static uint32_t MGRID_rank_of_coordinates(parsec_data_collection_t *desc, int tile_coordinates[((parsec_multidimensional_grid_t*)desc)->tiling_dimensions_number]); +void parsec_multidimensional_grid_key2coords(parsec_multidimensional_grid_t *dc, + parsec_data_key_t key, + int tile_coordinates[dc->tiling_dimensions_number]); + +static parsec_data_key_t grid_data_key(struct parsec_data_collection_s *desc, ...); + +static uint32_t MGRID_rank_of(parsec_data_collection_t *desc, ...); +static int32_t MGRID_vpid_of(parsec_data_collection_t* desc, ...); +static parsec_data_t* MGRID_data_of(parsec_data_collection_t* dc, ...); +static uint32_t MGRID_rank_of_key(parsec_data_collection_t* desc, parsec_data_key_t key); +static int32_t MGRID_vpid_of_key(parsec_data_collection_t* desc, parsec_data_key_t key); +static parsec_data_t* MGRID_data_of_key(parsec_data_collection_t* dc, parsec_data_key_t key); + + + + +static int MGRID_memory_register(parsec_data_collection_t* desc, parsec_device_module_t* device) +{ + parsec_multidimensional_grid_t * dc = (parsec_multidimensional_grid_t *)desc; + if( (NULL == dc->grid ) || (dc->nb_local_tiles == 0)) { + return PARSEC_SUCCESS; + } + + return device->memory_register(device, desc, + dc->grid, + ((size_t)dc->tile_number_of_values * + (size_t)parsec_datadist_getsizeoftype(dc->mtype))); +} + +static int MGRID_memory_unregister(parsec_data_collection_t* desc, parsec_device_module_t* device) +{ + parsec_multidimensional_grid_t * dc = (parsec_multidimensional_grid_t *)desc; + if( (NULL == dc->grid ) || (dc->nb_local_tiles == 0)) { + return PARSEC_SUCCESS; + } + + return device->memory_unregister(device, desc, dc->grid); +} + +void parsec_multidimensional_grid_init(parsec_multidimensional_grid_t * dc, + parsec_matrix_type_t mtype, + int nodes, int myrank, + int tiling_dimensions_number, int tile_dimensions_number, + ... + // tiling_size [tiling_dimensions_number times], + // tile_size [tile_dimensions_number times], + // mpi_stencil_size [tiling_dimensions_number times], + + + /* + int mb, int nb, // Tile size + int lm, int ln, // Global matrix size (what is stored) + int i, int j, // Staring point in the global matrix + int m, int n, // Submatrix size (the one concerned by the computation + int P, int Q, // process process grid + int kp, int kq, // k-cyclicity + int ip, int jq // starting point on the process grid + */ + ) +{ + va_list ap; + + // fill in the dc structure + dc->tiling_dimensions_number = tiling_dimensions_number; + dc->tile_dimensions_number = tile_dimensions_number; + + va_start(ap, tiling_dimensions_number); + for(int d=0;dtiling_dimensions_number;++d) + { + dc->tiling_size[d] = (int)va_arg(ap, unsigned int); + } + for(int d=0;dtile_dimensions_number;++d) + { + dc->tile_size[d] = (int)va_arg(ap, unsigned int); + } + for(int d=0;dtiling_dimensions_number;++d) + { + dc->mpi_stencil_size[d] = (int)va_arg(ap, unsigned int); + } + va_end(ap); + + dc->grid = NULL; // no data associated yet + dc->mtype = mtype; + + dc->tile_number_of_values = 1; + for(int d=0;dtile_dimensions_number;++d) + { + dc->tile_number_of_values *= dc->tile_size[d]; + } + + dc->tile_number = 1; + for(int d=0;dtiling_dimensions_number;++d) + { + dc->tile_number *= dc->tiling_size[d]; + } + + dc->nb_local_tiles = 0; + for(int t=0;ttile_number;++t) + { + int tile_coordinates[dc->tiling_dimensions_number]; + parsec_multidimensional_grid_key2coords(dc, t, tile_coordinates); + int target_rank = MGRID_rank_of_coordinates((parsec_data_collection_t*)dc, tile_coordinates); + if(target_rank == myrank) + { + ++dc->nb_local_tiles; + } + } + + dc->data_map = (parsec_data_t**)calloc(dc->nb_local_tiles, sizeof(parsec_data_t*)); + dc->bsiz = dc->tile_number_of_values * parsec_datadist_getsizeoftype(dc->mtype); + + + parsec_data_collection_t *o = &(dc->super); + + parsec_data_collection_init( o, nodes, myrank ); + + o->data_key = grid_data_key; + + /* set the methods */ + o->rank_of = MGRID_rank_of; + o->vpid_of = MGRID_vpid_of; + o->data_of = MGRID_data_of; + o->rank_of_key = MGRID_rank_of_key; + o->vpid_of_key = MGRID_vpid_of_key; + o->data_of_key = MGRID_data_of_key; + + o->register_memory = MGRID_memory_register; + o->unregister_memory = MGRID_memory_unregister; + + + /* finish to update the main object properties */ + /*o->key_to_string = tiled_matrix_key_to_string; // dont care atm YET + if( asprintf(&(o->key_dim), "(%d, %d)", tdesc->lmt, tdesc->lnt) <= 0 ) { + o->key_dim = NULL; + }*/ + + /* Define the default datatye of the datacollection */ + parsec_datatype_t elem_dt = PARSEC_DATATYPE_NULL; + ptrdiff_t extent; + parsec_translate_matrix_type( dc->mtype, &elem_dt ); + if( PARSEC_SUCCESS != parsec_matrix_define_datatype(&o->default_dtt, elem_dt, + PARSEC_MATRIX_FULL, 1 /*diag*/, + dc->tile_number_of_values, 1, dc->tile_number_of_values /*ld*/, + -1/*resized*/, &extent)){ + parsec_fatal("Unable to create a datatype for the data collection."); + } + +/* + // print the dc structure + printf("dc.tiling_dimensions_number = %d\n", dc->tiling_dimensions_number); + for(int d=0;dtiling_dimensions_number;++d) + { + printf("dc.tiling_size[%d] = %d\n", d, dc->tiling_size[d]); + } + for(int d=0;dtiling_dimensions_number;++d) + { + printf("dc.tile_size[%d] = %d\n", d, dc->tile_size[d]); + } + for(int d=0;dtiling_dimensions_number;++d) + { + printf("dc.mpi_stencil_size[%d] = %d\n", d, dc->mpi_stencil_size[d]); + } + printf("dc.tile_number_of_values = %d\n", dc->tile_number_of_values); + printf("dc.tile_number = %d\n", dc->tile_number); + printf("dc.nb_local_tiles = %d\n", dc->nb_local_tiles); +*/ + +} + +void parsec_grid_destroy_data( parsec_multidimensional_grid_t *grid ) +{ + if ( grid->data_map != NULL ) { + parsec_data_t **data = grid->data_map; + + for(int i = 0; i < grid->nb_local_tiles; i++, data++) { + if( NULL == *data ) continue; + parsec_data_destroy( *data ); + } + + free( grid->data_map ); + grid->data_map = NULL; + } +} + +void parsec_grid_destroy( parsec_multidimensional_grid_t *grid ) +{ + parsec_data_collection_t *dc = (parsec_data_collection_t*)grid; + parsec_type_free(&dc->default_dtt); + + parsec_grid_destroy_data( grid ); + parsec_data_collection_destroy( dc ); +} + +static inline int MGRID_coordinates_to_position(parsec_multidimensional_grid_t *dc, int tile_coordinates[dc->tiling_dimensions_number]) +{ + int position = 0; + int offset_multiplier = 1; + for(int d=0;dtiling_dimensions_number;++d) + { + position += tile_coordinates[d] * offset_multiplier; + offset_multiplier *= dc->tiling_size[d]; + } + + //printf("coordinates %d %d %d -> position %d\n", tile_coordinates[0], tile_coordinates[1], tile_coordinates[2], position); + + return position; +} + +/* return a unique key (unique only for the specified parsec_dc) associated to a data */ +static parsec_data_key_t grid_data_key(struct parsec_data_collection_s *desc, ...) +{ + parsec_multidimensional_grid_t *dc = (parsec_multidimensional_grid_t *)desc; + va_list ap; + + int tile_coordinates[dc->tiling_dimensions_number]; + + /* Get coordinates */ + va_start(ap, desc); + for(int d=0;dtiling_dimensions_number;++d) + { + tile_coordinates[d] = (int)va_arg(ap, unsigned int); + } + va_end(ap); + + int position = MGRID_coordinates_to_position(dc, tile_coordinates); + + return position; +} + +void parsec_multidimensional_grid_key2coords(parsec_multidimensional_grid_t *dc, + parsec_data_key_t key, + int tile_coordinates[dc->tiling_dimensions_number]) +{ + // compute the offset multiplier + int offset_multiplier = 1; + for(int d=0;dtiling_dimensions_number-1;++d) + { + offset_multiplier *= dc->tiling_size[d]; + } + + int d=dc->tiling_dimensions_number-1; + do + { + tile_coordinates[d] = (key / offset_multiplier) % dc->tiling_size[d]; + if(d <= 0) + { + break; + } + --d; + offset_multiplier /= dc->tiling_size[d]; + }while(true); +} + +/* + * + * Set of functions with no k-cyclicity support + * + */ + +static uint32_t MGRID_rank_of_coordinates(parsec_data_collection_t *desc, int tile_coordinates[((parsec_multidimensional_grid_t*)desc)->tiling_dimensions_number]) +{ + parsec_multidimensional_grid_t * dc = (parsec_multidimensional_grid_t *)desc; + + /* Assert using local info */ + for(int d=0;dtiling_dimensions_number;++d) + { + assert( tile_coordinates[d] < dc->tiling_size[d] ); + } + + int res = 0; + //int process_coordinates[dc->tiling_dimensions_number]; + int offset_multiplier = 1; + for(int d=0;dtiling_dimensions_number;++d) + { + // computes the process that should handle the tile depending on its cooresponding coordinates + + // coordinates of the tile inside the stencil + const int local_coordinates = tile_coordinates[d] % dc->mpi_stencil_size[d]; + + // coordinates of the process inside the stencil + // the pattern is the following (in 2D): + // 0 1 ... NX + // NX+1 NX+2 ... 2NX + // ... + // (NY-1)*NX (NY-1)*NX+1 ... NY*NX + res += offset_multiplier * local_coordinates; + + offset_multiplier *= dc->mpi_stencil_size[d]; + } + + return res; +} + + +static uint32_t MGRID_rank_of(parsec_data_collection_t *desc, ...) +{ + parsec_multidimensional_grid_t * dc = (parsec_multidimensional_grid_t *)desc; + int tile_coordinates[dc->tiling_dimensions_number]; + + va_list ap; + dc = (parsec_multidimensional_grid_t *)desc; + + /* Get coordinates */ + va_start(ap, desc); + for(int d=0;dtiling_dimensions_number;++d) + { + tile_coordinates[d] = (int)va_arg(ap, unsigned int); + } + va_end(ap); + + return MGRID_rank_of_coordinates(desc, tile_coordinates); +} + +static uint32_t MGRID_rank_of_key(parsec_data_collection_t *desc, parsec_data_key_t key) +{ + parsec_multidimensional_grid_t * dc = (parsec_multidimensional_grid_t *)desc; + int tile_coordinates[dc->tiling_dimensions_number]; + + parsec_multidimensional_grid_key2coords(dc, key, tile_coordinates); + + return MGRID_rank_of(desc, tile_coordinates); +} + +static int32_t MGRID_vpid_of_coordinates(parsec_data_collection_t *desc, int tile_coordinates[((parsec_multidimensional_grid_t *)desc)->tiling_dimensions_number]) +{ + + // TODO for the moment, vpid == rank + return MGRID_rank_of_coordinates(desc, tile_coordinates); +} + +static int32_t MGRID_vpid_of(parsec_data_collection_t *desc, ...) +{ + parsec_multidimensional_grid_t * dc; + va_list ap; + dc = (parsec_multidimensional_grid_t *)desc; + + int tile_coordinates[dc->tiling_dimensions_number]; + + /* Get coordinates */ + va_start(ap, desc); + for(int d=0;dtiling_dimensions_number;++d) + { + tile_coordinates[d] = (int)va_arg(ap, unsigned int); + } + va_end(ap); + + /* Assert using local info */ + for(int d=0;dtiling_dimensions_number;++d) + { + assert( tile_coordinates[d] < dc->tiling_size[d] ); + } + +#if defined(DISTRIBUTED) + assert(desc->myrank == MGRID_rank_of_coordinates(desc, tile_coordinates)); +#endif + +//printf("vpid of coordinates %d %d is %d\n", tile_coordinates[0], tile_coordinates[1], MGRID_vpid_of_coordinates(desc, tile_coordinates)); + + return MGRID_vpid_of_coordinates(desc, tile_coordinates); +} + +static int32_t MGRID_vpid_of_key(parsec_data_collection_t *desc, parsec_data_key_t key) +{ + parsec_multidimensional_grid_t *dc = (parsec_multidimensional_grid_t *)desc; + int tile_coordinates[dc->tiling_dimensions_number]; + + parsec_multidimensional_grid_key2coords(dc, key, tile_coordinates); + + return MGRID_vpid_of_coordinates(desc, tile_coordinates); +} + +static parsec_data_t* MGRID_data_of(parsec_data_collection_t *desc, ...) +{ + int position; + va_list ap; + parsec_multidimensional_grid_t * dc; + dc = (parsec_multidimensional_grid_t *)desc; + + int tile_coordinates[dc->tiling_dimensions_number]; // tile position in the whole grid + + /* Get coordinates */ + va_start(ap, desc); + for(int d=0;dtiling_dimensions_number;++d) + { + tile_coordinates[d] = (int)va_arg(ap, unsigned int); + } + va_end(ap); + + /* Assert using local info */ + for(int d=0;dtiling_dimensions_number;++d) + { + assert( tile_coordinates[d] < dc->tiling_size[d] ); + } + +#if defined(DISTRIBUTED) + assert(desc->myrank == MGRID_rank_of_coordinates(desc, tile_coordinates)); +#endif + + position = MGRID_coordinates_to_position(dc, tile_coordinates); + + int key = position; + int pos = 0; + + if(dc->grid != NULL) + { + pos = position; + } + + return parsec_data_create(dc->data_map + position, + desc, key, (char*)dc->grid + pos * dc->bsiz, + dc->bsiz, + PARSEC_DATA_FLAG_PARSEC_MANAGED); +} + +static parsec_data_t* MGRID_data_of_key(parsec_data_collection_t *desc, parsec_data_key_t key) +{ + parsec_multidimensional_grid_t *dc = (parsec_multidimensional_grid_t *)desc; + + int position = key; + int pos = 0; + + if(dc->grid != NULL) + { + pos = position; + } + + return parsec_data_create(dc->data_map + position, + desc, key, (char*)dc->grid + pos * dc->bsiz, + dc->bsiz, + PARSEC_DATA_FLAG_PARSEC_MANAGED); +} + diff --git a/parsec/data_dist/multidimensional_grid.h b/parsec/data_dist/multidimensional_grid.h new file mode 100644 index 000000000..edcbb825d --- /dev/null +++ b/parsec/data_dist/multidimensional_grid.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2010-2021 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + */ + + +#ifndef _MULTIDIMENSIONAL_GRID_H_ +#define _MULTIDIMENSIONAL_GRID_H_ + +#include "parsec/parsec_config.h" +#include +#include +#include "parsec/runtime.h" +#include "parsec/data_distribution.h" +#include "parsec/data.h" +#include "parsec/datatype.h" +#include "parsec/parsec_internal.h" +#include "parsec/data_dist/matrix/matrix.h" +#include "parsec/data_dist/matrix/grid_2Dcyclic.h" + +#define MAX_DIMENSIONS_NUMBER 8 + +BEGIN_C_DECLS + +/* +struct parsec_execution_stream_s; +struct parsec_taskpool_s; +*/ + +/* +TODO +- use bsiz for complete tile size including the overlap +- get the proper tile_coordinates in MGRID_data_of (the part with va_start(ap, desc);) (not just in MGRID_data_of...) +- init mpi_stencil_size +*/ + +typedef struct parsec_multidimensional_grid_s { + parsec_data_collection_t super; + void *grid; /**< pointer to the beginning of the grid */ + parsec_data_t** data_map; /**< map of the data */ + parsec_matrix_type_t mtype; /**< precision of the matrix */ + + size_t bsiz; + + int nb_local_tiles; /**< number of tile handled locally */ + + int tiling_dimensions_number; // Number of dimensions of the tiling + int tile_dimensions_number; // Number of dimensions of a tile + + int tiling_size[MAX_DIMENSIONS_NUMBER]; // size : [tiling_dimensions_number] // number of tiles in the grid + int tile_size[MAX_DIMENSIONS_NUMBER]; // size : [tile_dimensions_number] // size of a tile + //int grid_size[MAX_DIMENSIONS_NUMBER]; // size : [grid_dimensions_number] + int mpi_stencil_size[MAX_DIMENSIONS_NUMBER]; // size : [tiling_dimensions_number] + + int tile_number_of_values; // number of elements in a tile + int tile_number; // total number of tiles +} parsec_multidimensional_grid_t; + +// #define A(m,n) &((double*)descA.mat)[descA.bsiz*(m)+descA.bsiz*descA.lmt*(n)] + +/** + * Initialize the description of a 2-D block cyclic distributed matrix. + * @param dc matrix description structure, already allocated, that will be initialize + * @param mtype type of data used for this matrix + * @param storage type of storage of data + * @param nodes number of nodes + * @param myrank rank of the local node (as of mpi rank) + * @param mb number of row in a tile + * @param nb number of column in a tile + * @param lm number of rows of the entire matrix + * @param ln number of column of the entire matrix + * @param i starting row index for the computation on a submatrix + * @param j starting column index for the computation on a submatrix + * @param m number of rows of the entire submatrix + * @param n numbr of column of the entire submatrix + * @param p number of row of processes of the process grid the + * resulting distribution will be made so that pxq=nodes + * @param q number of col of processes of the process grid the + * resulting distribution will be made so that pxq=nodes + * @param kp number of rows of tiles for k-cyclic block distribution + * act as-if the process grid had nkp repetitions for every process row + * (see example for kq below) + * @param kq number of column of tiles for k-cyclic block distribution + * act as-if the process grid had kq repetitions for every process column + * For example, kp=1, kq=2 leads to the following pxq=2x4 process grid + * | 0 | 0 | 1 | 1 | 2 | 2 | 3 | 3 | + * | 4 | 4 | 5 | 5 | 6 | 6 | 7 | 7 | + * @param ip starting point on the process grid rows + * @param jq starting point on the process grid cols + */ +void parsec_multidimensional_grid_init(parsec_multidimensional_grid_t * dc, + parsec_matrix_type_t mtype, + int nodes, int myrank, + int tiling_dimensions_number, int tile_dimensions_number, + ... + // tiling_size [tiling_dimensions_number times], + // tile_size [tile_dimensions_number times], + // mpi_stencil_size [tiling_dimensions_number times], + + + /* + int mb, int nb, // Tile size + int lm, int ln, // Global matrix size (what is stored) + int i, int j, // Staring point in the global matrix + int m, int n, // Submatrix size (the one concerned by the computation + int P, int Q, // process process grid + int kp, int kq, // k-cyclicity + int ip, int jq // starting point on the process grid + */ + ); + +void parsec_grid_destroy( parsec_multidimensional_grid_t *grid ); + +/** + * kcyclic _view_ of the 2-D Block cyclic distributed matrix. The goal is to + * improve access locality by changing access order without incurring the cost of a physical + * redistribution of the dataset. The underlying data storage is unchanged, + * but the view provide accessors that swap lines and column blocks so that a block + * from the same processor is provided for @kp repetitions along the m direction + * (@kq along n, respectively); until such repetition is not possible anymore + * (right edge, or bottom of the matrix where not enough local tiles are available). + * + * For example, starting from a standard 2D grid PxQ=2x2 with kp=2; + * and m/mb = 6; + * rank_of(0,0) is 0; data_of(0,0) is origin (0,0) + * rank_of(1,0) is 0 (because kp=2); data_of(1,0) is origin (2,0) + * rank_of(2,0) is 1; data_of(2,0) is origin (1,0) + * rank_of(3,0) is 1 (because kp=2); data_of(3,0) is origin (3,0) + * rank_of(4,0) is 0; data_of(4,0) is origin (4,0) + * rank_of(5,0) is 1; data_of(5,0) is origin (5,0): despite kp=2, + * there are not enough local tiles on rank 0 to satisfy the view + * origin (6,0) does not exist), hence the view provides the next + * block on the m direction. + * + * Beware that using a kcyclic view is equivalent to swapping rows (or + * columns, respectively), and the algorithm operating on the data may have + * special requirements for it to be applicable. For example, a kcyclic + * view of a diagonal dominant matrix is not always diagonal dominant; and the + * result of a factorization on a kcyclic view is not a 'triangular' matrix, + * but a swap, according to the view (i.e., solving the system requires applying + * a compatible view on the right-hand side as well). + * + */ +void parsec_multidimensional_grid_kview( parsec_multidimensional_grid_t* target, + parsec_multidimensional_grid_t* origin, + int kp, int kq ); + +END_C_DECLS +#endif /* _MULTIDIMENSIONAL_GRID_H_ */ diff --git a/parsec/datarepo.c b/parsec/datarepo.c index 75b300713..d6effc334 100644 --- a/parsec/datarepo.c +++ b/parsec/datarepo.c @@ -132,7 +132,7 @@ __data_repo_entry_used_once(data_repo_t *repo, parsec_key_t key void __data_repo_entry_addto_usage_limit(data_repo_t *repo, parsec_key_t key, uint32_t usagelmt -#if defined(PARSEC_DEBUG_NOISIER) +#if defined(PARSEC_DEBUG_NOISIER) // The printfs glitch if this is enabled , const char *tablename, const char *file, int line #endif ) diff --git a/parsec/include/parsec.h b/parsec/include/parsec.h index fecf4521a..a6db5732b 100644 --- a/parsec/include/parsec.h +++ b/parsec/include/parsec.h @@ -14,6 +14,7 @@ #include "parsec/datatype.h" #include "parsec/scheduling.h" #include "parsec/utils/debug.h" +#include "parsec/task_class.h" #include "parsec/interfaces/interface.h" #include "parsec/interfaces/dtd/insert_function.h" diff --git a/parsec/include/parsec/parsec_config_bottom.h b/parsec/include/parsec/parsec_config_bottom.h index f87a74e6d..3f82fd568 100644 --- a/parsec/include/parsec/parsec_config_bottom.h +++ b/parsec/include/parsec/parsec_config_bottom.h @@ -144,23 +144,30 @@ #endif #if defined(PARSEC_SCHED_DEPS_MASK) -typedef int32_t parsec_dependency_t; +//typedef int32_t parsec_dependency_t; +typedef int64_t parsec_dependency_t; #else /** * Should be large enough to support MAX_PARAM_COUNT values. */ -typedef int32_t parsec_dependency_t; +//typedef int32_t parsec_dependency_t; +typedef uint64_t parsec_dependency_t; #endif /* * A set of constants defining the capabilities of the underlying * runtime. */ + +#define MAX_DATAFLOWS_PER_TASK 64 + #define MAX_LOCAL_COUNT 20 #define MAX_PARAM_COUNT 20 -#define MAX_DEP_IN_COUNT 10 -#define MAX_DEP_OUT_COUNT 10 +// #define MAX_DEP_IN_COUNT 21 +// #define MAX_DEP_OUT_COUNT 21 +#define MAX_DEP_IN_COUNT 52 +#define MAX_DEP_OUT_COUNT 52 #define MAX_TASK_STRLEN 128 diff --git a/parsec/include/parsec/parsec_description_structures.h b/parsec/include/parsec/parsec_description_structures.h index e25c7d46f..2fcf4e2d3 100644 --- a/parsec/include/parsec/parsec_description_structures.h +++ b/parsec/include/parsec/parsec_description_structures.h @@ -15,6 +15,9 @@ BEGIN_C_DECLS typedef struct parsec_assignment_s parsec_assignment_t; typedef struct parsec_expr_s parsec_expr_t; typedef struct parsec_flow_s parsec_flow_t; +#if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) +typedef struct parsec_parametrized_flow_s parsec_parametrized_flow_t; // to store information about parametrized flows +#endif typedef struct parsec_dep_s parsec_dep_t; typedef struct parsec_symbol_s parsec_symbol_t; @@ -96,9 +99,16 @@ struct parsec_flow_s { uint8_t flow_index; /**< The input index of the flow. This index is used * while computing the mask. */ parsec_dependency_t flow_datatype_mask; /**< The bitmask of dep_datatype_index of all deps */ - parsec_dep_t const *dep_in[MAX_DEP_IN_COUNT]; - parsec_dep_t const *dep_out[MAX_DEP_OUT_COUNT]; + + parsec_dep_t *dep_in[MAX_DEP_IN_COUNT]; + parsec_dep_t *dep_out[MAX_DEP_OUT_COUNT]; +}; + +#if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) +struct parsec_parametrized_flow_s { + int test; }; +#endif /** * Dependencies diff --git a/parsec/include/parsec/parsec_options.h.in b/parsec/include/parsec/parsec_options.h.in index efed86686..6bc324597 100644 --- a/parsec/include/parsec/parsec_options.h.in +++ b/parsec/include/parsec/parsec_options.h.in @@ -74,6 +74,7 @@ #cmakedefine PARSEC_DIST_THREAD #cmakedefine PARSEC_DIST_PRIORITIES #cmakedefine PARSEC_DIST_COLLECTIVES +#cmakedefine PARSEC_ALLOW_PARAMETRIZED_FLOWS #define PARSEC_DIST_SHORT_LIMIT @PARSEC_DIST_SHORT_LIMIT@ /* GPU Support */ diff --git a/parsec/interfaces/dtd/insert_function.c b/parsec/interfaces/dtd/insert_function.c index 3b6867f24..987c50fae 100644 --- a/parsec/interfaces/dtd/insert_function.c +++ b/parsec/interfaces/dtd/insert_function.c @@ -171,14 +171,14 @@ static int parsec_dtd_tile_new_dc_key_to_string(parsec_data_collection_t *d, par static void parsec_dtd_iterate_successors(parsec_execution_stream_t *es, const parsec_task_t *this_task, - uint32_t action_mask, + parsec_dependency_t action_mask, parsec_ontask_function_t *ontask, void *ontask_arg); static int parsec_dtd_release_deps(parsec_execution_stream_t *, parsec_task_t *, - uint32_t, parsec_remote_deps_t *); + parsec_dependency_t, parsec_remote_deps_t *); static parsec_hook_return_t @@ -1729,7 +1729,7 @@ dtd_release_dep_fct(parsec_execution_stream_t *es, static void parsec_dtd_iterate_successors(parsec_execution_stream_t *es, const parsec_task_t *this_task, - uint32_t action_mask, + parsec_dependency_t action_mask, parsec_ontask_function_t *ontask, void *ontask_arg) { @@ -1765,7 +1765,7 @@ parsec_dtd_iterate_successors(parsec_execution_stream_t *es, static int parsec_dtd_release_deps(parsec_execution_stream_t *es, parsec_task_t *this_task, - uint32_t action_mask, + parsec_dependency_t action_mask, parsec_remote_deps_t *deps) { (void)deps; diff --git a/parsec/interfaces/ptg/ptg-compiler/jdf.c b/parsec/interfaces/ptg/ptg-compiler/jdf.c index 913da894f..3f40a6bd4 100644 --- a/parsec/interfaces/ptg/ptg-compiler/jdf.c +++ b/parsec/interfaces/ptg/ptg-compiler/jdf.c @@ -1524,7 +1524,7 @@ void jdf_dump_function_flows(jdf_function_entry_t* function, int expanded) if( strlen(string_arena_get_string(sa1)) ) string_arena_add_string(sa2, "<%s>", string_arena_get_string(sa1)); - printf("%s: %6s[%1s%1s idx %d, mask 0x%x/0x%x] %2s dep_index %8d dep_dt_index %8d %p <%s %s>\n", function->fname, + printf("%s: %6s[%1s%1s idx %d, mask 0x%lx/0x%lx] %2s dep_index %8d dep_dt_index %8d %p <%s %s>\n", function->fname, flow->varname, (flow->flow_flags & JDF_FLOW_IS_IN ? "R" : " "), (flow->flow_flags & JDF_FLOW_IS_OUT ? "W" : " "), flow->flow_index, flow->flow_dep_mask_in, flow->flow_dep_mask_out, @@ -1733,7 +1733,7 @@ int jdf_function_property_is_keyword(const char *name) int jdf_assign_ldef_index(jdf_function_entry_t *f) { - int nb_ldef_for_locals, nb_ldef_for_deps, nb_ldef_for_calls = 0; + int nb_ldef_for_locals, nb_ldef_for_deps, nb_ldef_for_flows, nb_ldef_for_calls = 0; jdf_expr_t *ld; jdf_variable_list_t *vl; jdf_dataflow_t *fl; @@ -1745,6 +1745,7 @@ int jdf_assign_ldef_index(jdf_function_entry_t *f) * If they appear in the locals, they need to have a unique position * If they appear in the dataflow, each dep can re-use the locals of another dep * each call can re-use the locals of another call + * With parametrized flows, they can also appear in the dataflow. */ DO_DEBUG_VERBOSE(2, ({fprintf(stderr, "Indexing task class %s\n", f->fname);}) ); @@ -1762,9 +1763,21 @@ int jdf_assign_ldef_index(jdf_function_entry_t *f) nb_ldef_for_locals = f->nb_max_local_def; for(fl = f->dataflow; NULL != fl; fl = fl->next) { + + + nb_ldef_for_flows = nb_ldef_for_locals; + for(ld = fl->local_variables; NULL != ld; ld = ld->next) { + assert(NULL != ld->alias); + if( ld->ldef_index == -1 ) { + ld->ldef_index = nb_ldef_for_flows; + nb_ldef_for_flows++; + DO_DEBUG_VERBOSE(2, ({ fprintf(stderr, " Flow for %s, flow %p: ldef %s is at %d\n", fl->varname, fl, ld->alias, ld->ldef_index); }) ); + } + } + int depi = 0; for(dep = fl->deps; NULL != dep; dep = dep->next, depi++) { - nb_ldef_for_deps = nb_ldef_for_locals; + nb_ldef_for_deps = nb_ldef_for_flows; for(ld = dep->local_defs; NULL != ld; ld = ld->next) { assert(NULL != ld->alias); if( ld->ldef_index == -1 ) { @@ -1773,10 +1786,11 @@ int jdf_assign_ldef_index(jdf_function_entry_t *f) DO_DEBUG_VERBOSE(2, ({ fprintf(stderr, " Flow for %s, dep %d: ldef %s is at %d\n", fl->varname, depi, ld->alias, ld->ldef_index); }) ); } } + + nb_ldef_for_calls = nb_ldef_for_deps; switch( dep->guard->guard_type ) { case JDF_GUARD_UNCONDITIONAL: case JDF_GUARD_BINARY: - nb_ldef_for_calls = nb_ldef_for_deps; for(ld = dep->guard->calltrue->local_defs; NULL != ld; ld = ld->next) { assert(NULL != ld->alias); if( ld->ldef_index == -1 ) { @@ -1787,7 +1801,6 @@ int jdf_assign_ldef_index(jdf_function_entry_t *f) } break; case JDF_GUARD_TERNARY: - nb_ldef_for_calls = nb_ldef_for_deps; for(ld = dep->guard->calltrue->local_defs; NULL != ld; ld = ld->next) { assert(NULL != ld->alias); if( ld->ldef_index == -1 ) { @@ -1796,7 +1809,6 @@ int jdf_assign_ldef_index(jdf_function_entry_t *f) DO_DEBUG_VERBOSE(2, ({ fprintf(stderr, " Flow for %s, dep %d, calltrue: ldef %s is at %d\n", fl->varname, depi, ld->alias, ld->ldef_index); }) ); } } - nb_ldef_for_calls = nb_ldef_for_deps; for(ld = dep->guard->callfalse->local_defs; NULL != ld; ld = ld->next) { assert(NULL != ld->alias); if( ld->ldef_index == -1 ) { @@ -1812,6 +1824,8 @@ int jdf_assign_ldef_index(jdf_function_entry_t *f) if( nb_ldef_for_calls > f->nb_max_local_def ) f->nb_max_local_def = nb_ldef_for_calls; } + if( nb_ldef_for_flows > f->nb_max_local_def ) + f->nb_max_local_def = nb_ldef_for_flows; } return 0; } diff --git a/parsec/interfaces/ptg/ptg-compiler/jdf.h b/parsec/interfaces/ptg/ptg-compiler/jdf.h index 189d276f7..9da572d55 100644 --- a/parsec/interfaces/ptg/ptg-compiler/jdf.h +++ b/parsec/interfaces/ptg/ptg-compiler/jdf.h @@ -268,6 +268,11 @@ typedef struct jdf_def_list { struct jdf_def_list *properties; } jdf_def_list_t; +typedef struct jdf_flow_specifier { + struct jdf_object_t super; + struct jdf_expr *variables; +} jdf_flow_specifier_t; + typedef struct jdf_dataflow jdf_dataflow_t; typedef struct jdf_dep jdf_dep_t; typedef uint32_t jdf_flow_flags_t; @@ -283,11 +288,12 @@ struct jdf_dataflow { struct jdf_object_t super; jdf_flow_flags_t flow_flags; jdf_dataflow_t *next; + struct jdf_expr *local_variables; /**< flows can specify a range */ char *varname; struct jdf_dep *deps; uint8_t flow_index; - uint32_t flow_dep_mask_out; - uint32_t flow_dep_mask_in; + parsec_dependency_t flow_dep_mask_out; + parsec_dependency_t flow_dep_mask_in; }; typedef uint16_t jdf_dep_flags_t; @@ -338,6 +344,7 @@ typedef struct jdf_call { struct jdf_object_t super; struct jdf_expr *local_defs; /**< Each call can have some local indicies, allowing to define sets of deps */ char *var; /**< If func_or_mem is a function, var is the name of the flow on that function */ + struct jdf_expr *parametrized_offset; /**< Offset required if var is an array */ char *func_or_mem; /**< string of the function (task class) or data collection referred to in this call */ struct jdf_expr *parameters; /**< list of parameters for that task class / data collection */ } jdf_call_t; @@ -379,6 +386,7 @@ typedef enum { JDF_EQUAL, JDF_SHL, JDF_SHR, JDF_RANGE, + JDF_PARAMETRIZED_FLOW_RANGE, JDF_TERNARY, JDF_VAR, JDF_STRING, diff --git a/parsec/interfaces/ptg/ptg-compiler/jdf2c.c b/parsec/interfaces/ptg/ptg-compiler/jdf2c.c index ee7d0060a..5a8e09729 100644 --- a/parsec/interfaces/ptg/ptg-compiler/jdf2c.c +++ b/parsec/interfaces/ptg/ptg-compiler/jdf2c.c @@ -233,6 +233,12 @@ parsec_get_name(const jdf_t *jdf, const jdf_function_entry_t *f, char* fmt, ...) return tmp; } +static char *parsec_get_task_type_name(const jdf_t *jdf, const jdf_function_entry_t *f) +{ + //return parsec_get_name(jdf, f, TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)?"parametrized_task_t":"task_t"); + return parsec_get_name(jdf, f, "task_t"); +} + /** * Returns true if the function has any valid data output (not control). * Otherwise, returns false. @@ -579,6 +585,143 @@ char * dump_expr(void **elem, void *arg) return string_arena_get_string(sa); } +// TODO: remove, now handle automatically in the variable stack +char *dump_referrer_iterator(const jdf_function_entry_t *f, void *arg) +{ + string_arena_t *sa = arg; + + if(f == NULL ) + { + assert(0); + } + + jdf_call_t *call; + for(jdf_dataflow_t *flow = f->dataflow; NULL != flow; flow = flow->next) { + for(jdf_dep_t *dep = flow->deps; NULL != dep; dep = dep->next) { + jdf_guarded_call_t *guard = dep->guard; + switch(guard->guard_type) { + case JDF_GUARD_TERNARY: + call = guard->callfalse; + //assert( NULL != JDF_OBJECT_ONAME(call) ); + if(call->parametrized_offset) { + string_arena_add_string(sa, " int %s = locals->ldef[%d].value; (void) %s;\n", + call->parametrized_offset->alias, call->parametrized_offset->ldef_index, call->parametrized_offset->alias); + } + __attribute__ ((fallthrough)); + case JDF_GUARD_BINARY: + case JDF_GUARD_UNCONDITIONAL: + call = guard->calltrue; + //assert( NULL != JDF_OBJECT_ONAME(call) ); + if(call->parametrized_offset) { + string_arena_add_string(sa, " int %s = locals->ldef[%d].value; (void) %s;\n", + call->parametrized_offset->alias, call->parametrized_offset->ldef_index, call->parametrized_offset->alias); + } + break; + default: + assert(0); + } + } + } + + return string_arena_get_string(sa); +} + +/** + * dump_parametrized_flow_loop: + * dumps the loop preceding a block that needs an iterator for the parametrized flow + */ +void dump_parametrized_flow_loop(const jdf_dataflow_t *flow, const char *iterator_name, const char *indent, void *arg) +{ + //expr_info_t* expr_info = (expr_info_t*)arg; + jdf_dataflow_t *f = (jdf_dataflow_t*)flow; + string_arena_t *sa = arg; + + if(f == NULL ) return; + assert(FLOW_IS_PARAMETRIZED(f)); + + // Generate the ranges + jdf_expr_t *variable=f->local_variables; + if(NULL != variable) { + if(variable->op == JDF_PARAMETRIZED_FLOW_RANGE) { + expr_info_t expr_info = EMPTY_EXPR_INFO; + expr_info.sa = string_arena_new(64); + expr_info.prefix = ""; + expr_info.suffix = ""; + expr_info.assignments = "parametrized flow range"; + + jdf_expr_t *from = variable->jdf_ta1; + jdf_expr_t *to = variable->jdf_ta2; + jdf_expr_t *step = variable->jdf_ta3; + + string_arena_add_string(sa, "%s// Iterating over the parametrized flow %s\n%sfor(int %s=%s;", + indent, + f->varname, + indent, iterator_name, + dump_expr((void**)from, &expr_info)); + string_arena_add_string(sa, "%s<=%s;", + iterator_name, + dump_expr((void**)to, &expr_info)); + string_arena_add_string(sa, "%s+=%s) {\n", + iterator_name, + dump_expr((void**)step, &expr_info)); + } + else + { + jdf_fatal(JDF_OBJECT_LINENO(f), "The flow variable is not a range\n"); + } + + + if(variable->next != NULL) + { + jdf_fatal(JDF_OBJECT_LINENO(f), "Parametrized flows can not handle more than one variable\n"); + } + } + else + { + jdf_fatal(JDF_OBJECT_LINENO(f), "Parametrized flows must have a variable\n"); + } +} + +/** + * dump_parametrized_flow_loop_end: + * dumps the loop end corresponding to the loop preceding a block that needs an iterator for the parametrized flow + */ +void dump_parametrized_flow_loop_end(const jdf_dataflow_t *flow, const char *indent, void *arg) +{ + jdf_dataflow_t *f = (jdf_dataflow_t*)flow; + string_arena_t *sa = arg; + + if(f == NULL ) return; + assert(FLOW_IS_PARAMETRIZED(f)); + + string_arena_add_string(sa, "%s}\n", indent); +} + +/** + * dump_parametrized_flow_loop_if_parametrized: + * dumps the loop preceding a block that needs an iterator for the parametrized flow if the flow is parametrized + * dumps nothing otherwise + */ +void dump_parametrized_flow_loop_if_parametrized(const jdf_dataflow_t *flow, const char *indent, void *arg) +{ + if(FLOW_IS_PARAMETRIZED(flow)) { + dump_parametrized_flow_loop(flow, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(flow), indent, arg); + } +} + +/** + * dump_parametrized_flow_loop_end_if_parametrized: + * dumps the loop end corresponding to the loop preceding a block that needs an iterator for the parametrized flow if the flow is parametrized + * dumps nothing otherwise + */ +void dump_parametrized_flow_loop_end_if_parametrized(const jdf_dataflow_t *flow, const char *indent, void *arg) +{ + if(FLOW_IS_PARAMETRIZED(flow)) { + dump_parametrized_flow_loop_end(flow, indent, arg); + } +} + + /** * Dump a predicate like * #define F_pred(k, n, m) (__parsec_tp->ABC->rank == __parsec_tp->ABC->rank_of(__parsec_tp->ABC, k, n, m)) @@ -756,19 +899,60 @@ static char *dump_data_initialization_from_data_array(void **elem, void *arg) string_arena_init(sa); + expr_info_t expr_info = EMPTY_EXPR_INFO; + expr_info.sa = string_arena_new(256); + expr_info.prefix = ""; + expr_info.suffix = ""; + expr_info.assignments = "parametrized flow range"; + + + if(FLOW_IS_PARAMETRIZED(f)) + { + string_arena_add_string(sa, + " parsec_data_copy_t *_f_%s[(%s)+1];\n", + varname, dump_expr((void**)f->local_variables->jdf_ta2, &expr_info)); + string_arena_add_string(sa, + " void *%s[(%s)+1]; (void)%s;\n", + varname, dump_expr((void**)f->local_variables->jdf_ta2, &expr_info), varname); + } + else + { + string_arena_add_string(sa, + " parsec_data_copy_t *_f_%s;\n", + varname); + string_arena_add_string(sa, + " void *%s; (void)%s;\n", + varname, varname); + } + + dump_parametrized_flow_loop_if_parametrized(f, " ", sa); + + string_arena_t *osa = string_arena_new(32); + string_arena_t *osa2 = string_arena_new(32); + string_arena_add_string(sa, - " parsec_data_copy_t *_f_%s = this_task->data._f_%s.data_%s;\n", - varname, f->varname, where); + "%s _f_%s%s = this_task->data.%s.data_%s;\n", + INDENTATION_IF_PARAMETRIZED(f), varname, DUMP_ARRAY_OFFSET_IF_PARAMETRIZED(osa, f), + DUMP_DATA_FIELD_NAME_IN_TASK(osa2, f), where); + string_arena_add_string(sa, - " void *%s = PARSEC_DATA_COPY_GET_PTR(_f_%s); (void)%s;\n", - varname, varname, varname); + "%s %s%s = PARSEC_DATA_COPY_GET_PTR(_f_%s%s);\n", + INDENTATION_IF_PARAMETRIZED(f), varname, DUMP_ARRAY_OFFSET_IF_PARAMETRIZED(osa, f), + varname, DUMP_ARRAY_OFFSET_IF_PARAMETRIZED(osa, f)); + + string_arena_free(osa); + string_arena_free(osa2); + + dump_parametrized_flow_loop_end_if_parametrized(f, " ", sa); + return string_arena_get_string(sa); } static char *dump_data_copy_init_for_inline_function(void **elem, void *arg) { init_from_data_info_t *info = (init_from_data_info_t*)arg; - string_arena_t *sa = info->sa; + string_arena_t *sa = info->sa, + *osa = string_arena_new(32); const char *where = info->where; jdf_dataflow_t *f = (jdf_dataflow_t*)elem; char *varname = f->varname; @@ -778,12 +962,22 @@ static char *dump_data_copy_init_for_inline_function(void **elem, void *arg) } string_arena_init(sa); + + // dump a loop if parametrized + dump_parametrized_flow_loop_if_parametrized(f, " ", sa); + string_arena_add_string(sa, - " parsec_data_copy_t *_f_%s = this_task->data._f_%s.data_%s;\n" - " (void)_f_%s;", - varname, f->varname, where, - varname + "%s parsec_data_copy_t *_f_%s = this_task->data.%s.data_%s;\n" + "%s (void)_f_%s;", + INDENTATION_IF_PARAMETRIZED(f), varname, DUMP_DATA_FIELD_NAME_IN_TASK(osa, f), where, + INDENTATION_IF_PARAMETRIZED(f), varname ); + + // dump the end of the loop if parametrized + dump_parametrized_flow_loop_end_if_parametrized(f, " ", sa); + + string_arena_free(osa); + return string_arena_get_string(sa); } @@ -791,7 +985,7 @@ static char *dump_data_copy_init_for_inline_function(void **elem, void *arg) * dump_dataflow_varname: * Takes the pointer to a flow *f, and print the varname */ -static char *dump_dataflow_varname(void **elem, void *_) +char *dump_dataflow_varname(void **elem, void *_) { (void)_; jdf_dataflow_t *f = (jdf_dataflow_t *)elem; @@ -1175,6 +1369,15 @@ static jdf_function_entry_t *find_target_function(const jdf_t *jdf, const char * return targetf; } +static jdf_dataflow_t *find_target_flow(const jdf_t *jdf, const jdf_function_entry_t *f, const char *name) +{ + jdf_dataflow_t *target_flow; + for(target_flow = f->dataflow; target_flow != NULL; target_flow = target_flow->next) + if( !strcmp(target_flow->varname, name) ) + break; + return target_flow; +} + /** * Find the output flow corresponding to a particular input flow. This function * returns the flow and not a particular dependency. @@ -1327,8 +1530,29 @@ static inline char* jdf_generate_task_typedef(void **elt, void* arg) } JDF_COUNT_LIST_ENTRIES(f->dataflow, jdf_dataflow_t, next, nb_flows); + /* UTIL_DUMP_LIST_FIELD(sa_data, f->dataflow, next, varname, dump_string, NULL, "", " parsec_data_pair_t _f_", ";\n", ";\n"); + */ + // Add the list of data to sa_data without UTIL_DUMP_LIST_FIELD + { + jdf_dataflow_t *df; + for(df = f->dataflow; df != NULL; df = df->next) { + if( !FLOW_IS_PARAMETRIZED(df) ) { + string_arena_add_string(sa_data, " parsec_data_pair_t _f_%s;\n", df->varname); + } + else + { // Parametrized flow + // Becomes an array of data pairs + + //string_arena_add_string(sa_data, " parsec_data_pair_t *_f_%s;\n", df->varname); + string_arena_add_string(sa_data, " //parsec_data_pair_t *_f_%s;\n", df->varname); + nb_flows--; // This flow will be stored in the unused space of the array + } + } + } + + string_arena_init(sa); /* Prepare the structure for the named assignments */ string_arena_add_string(sa, @@ -1345,18 +1569,32 @@ static inline char* jdf_generate_task_typedef(void **elt, void* arg) nb_locals, parsec_get_name(NULL, f, "parsec_assignment_t")); string_arena_add_string(sa, - "#if MAX_PARAM_COUNT < %d /* total number of flows for task %s */\n" - " #error Too many flows (%d out of MAX_PARAM_COUNT) for task %s\n" - "#endif /* MAX_PARAM_COUNT */\n", + "#if MAX_DATAFLOWS_PER_TASK < %d /* total number of flows for task %s */\n" + " #error Too many flows (%d out of MAX_DATAFLOWS_PER_TASK) for task %s\n" + "#endif /* MAX_DATAFLOWS_PER_TASK */\n", nb_flows, f->fname, nb_flows, f->fname); string_arena_add_string(sa, "typedef struct %s {\n" "%s" - " parsec_data_pair_t unused[MAX_LOCAL_COUNT-%d];\n" + " parsec_data_pair_t %s[MAX_LOCAL_COUNT-%d];\n" "} %s;\n\n", parsec_get_name(NULL, f, "data_s"), string_arena_get_string(sa_data), + TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f) ? "dynamic" : "unused", nb_flows, parsec_get_name(NULL, f, "data_t")); + /*if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) { + string_arena_add_string(sa, "typedef struct %s {\n" + " %s super;\n", + parsec_get_name(NULL, f, "parametrized_data_s"), + parsec_get_name(NULL, f, "data_t")); + for(jdf_dataflow_t *df = f->dataflow; df != NULL; df = df->next) { + if( FLOW_IS_PARAMETRIZED(df) ) { + string_arena_add_string(sa, " parsec_data_pair_t *_f_%s;\n", df->varname); + } + } + string_arena_add_string(sa, "} %s;\n\n", + parsec_get_name(NULL, f, "parametrized_data_t")); + }*/ string_arena_add_string(sa, "typedef struct %s {\n" " PARSEC_MINIMAL_EXECUTION_CONTEXT\n" "#if defined(PARSEC_PROF_TRACE)\n" @@ -1372,6 +1610,28 @@ static inline char* jdf_generate_task_typedef(void **elt, void* arg) jdf_basename, f->fname, jdf_basename, f->fname, parsec_get_name(NULL, f, "task_t")); + /*if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) { + string_arena_add_string(sa, "typedef struct %s {\n" + " %s super;\n" + " %s data;\n" + "} %s;\n\n", + parsec_get_name(NULL, f, "parametrized_task_s"), + parsec_get_name(NULL, f, "task_t"), + parsec_get_name(NULL, f, "parametrized_data_t"), + parsec_get_name(NULL, f, "parametrized_task_t")); + + string_arena_add_string(sa, + "PARSEC_OBJ_CLASS_DECLARATION(%s);\n" + "PARSEC_OBJ_CLASS_INSTANCE(%s, %s,\n" + " %s, NULL);\n\n", + parsec_get_name(NULL, f, "task_t"), + parsec_get_name(NULL, f, "task_t"), + "parsec_list_item_t", + //parsec_get_name(NULL, f, "constructor") + "NULL" + ); + }*/ + string_arena_free(sa_locals); string_arena_free(sa_data); return string_arena_get_string(sa); @@ -1461,12 +1721,168 @@ static void jdf_generate_predeclarations( const jdf_t *jdf ) string_arena_t *sa2 = string_arena_new(64); int rc; + // If has any parametrized flow + if(JDF_ANY_FLOW_IS_PARAMETRIZED(jdf)) { + /*for(f = jdf->functions; f != NULL; f = f->next) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput("typedef struct parsec_%s_%s_task_class_s parsec_%s_%s_task_class_t;\n", jdf_basename, f->fname, jdf_basename, f->fname); + } + } + } + for(f = jdf->functions; f != NULL; f = f->next) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput("struct parsec_%s_%s_task_class_s;\n", jdf_basename, f->fname); + } + } + }*/ + + for(f = jdf->functions; f != NULL; f = f->next) { + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(f)) { + coutput("\ntypedef struct parsec_%s_%s_task_class_s {\n", jdf_basename, f->fname); + coutput(" parsec_task_class_t super;\n"); + + // Masks: + // If any flow/dep is parametrized/referrer, all the action masks have to be dynamically computed + coutput(" // Action masks of %s\n", f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + coutput(" parsec_dependency_t dep_mask_out_of_flow_of_%s_%s_for_%s;\n", + jdf_basename, f->fname, df->varname); + } + // action_mask for the entire task class + coutput(" parsec_dependency_t dep_mask_out_of_flow_of_%s_%s;\n", + jdf_basename, f->fname); + + + // Parametrized flows: + coutput(" // Local parametrized flows of %s\n//#if defined(PARSEC_DEBUG_NOISIER) // used in release mode too now\n", f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" int nb_specializations_of_parametrized_flow_of_%s_%s_for_%s;\n", jdf_basename, f->fname, df->varname); + } + } + coutput("//#endif\n"); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + // if "in" flow + if(df->flow_flags & JDF_FLOW_TYPE_READ) + coutput(" int in_flow_offset_of_parametrized_flow_of_%s_%s_for_%s;\n", jdf_basename, f->fname, df->varname); + if(df->flow_flags & JDF_FLOW_TYPE_WRITE) + coutput(" int out_flow_offset_of_parametrized_flow_of_%s_%s_for_%s;\n", jdf_basename, f->fname, df->varname); + coutput(" int data_dynamic_offset_of_parametrized_%s_%s_for_%s;\n", jdf_basename, f->fname, df->varname); + } + } + + // Referrers + coutput(" // Local referrers of %s\n", f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + int depid=1; + for( jdf_dep_t *dep = df->deps; NULL != dep; dep = dep->next, depid++ ) { + if((dep->dep_flags & JDF_DEP_FLOW_OUT) == 0) + { // We only need the out indices + continue; + } + + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + if( NULL != call->parametrized_offset ) + { + // Then the dep refers to a parametrized flow + + coutput(" int out_dep_offset_of_referrer%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s;\n", + FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + + // We also keep track of the flow that id that contains the referrer + coutput(" int out_flow_offset_of_referrer%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s;\n", + FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + } + } + } + } + + // Then the dep offsets to every non-parametrized flow + coutput(" // Dep offsets of non-referrers of %s\n", f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + int depid=1; + for( jdf_dep_t *dep = df->deps; NULL != dep; dep = dep->next, depid++ ) { + if((dep->dep_flags & JDF_DEP_FLOW_OUT) == 0) + { // We only need the out indices + continue; + } + + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + // If the target is NOT parametrized + if( NULL == call->parametrized_offset ) + { + coutput(" int out_dep_offset_of%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s;\n", + FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + /*coutput(" int out_flow_offset_of_flow_of_%s_%s_for_%s_dep%d_atline_%d%s;\n", + jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "");*/ + } + } + } + } + + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) + { + coutput(" // Task class %s has at least one parametrized flow: we need to store the flow id of every flow\n", f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + coutput(" uint8_t flow_id_of_flow_of_%s_%s_for_%s;\n", + jdf_basename, f->fname, df->varname); + } + } + + coutput("} parsec_%s_%s_task_class_t;\n\n", jdf_basename, f->fname); + } + } + } + coutput("/** Predeclarations of the parsec_task_class_t */\n"); for(f = jdf->functions; f != NULL; f = f->next) { rc = asprintf(&JDF_OBJECT_ONAME( f ), "%s_%s", jdf_basename, f->fname); assert(rc != -1); coutput("static const parsec_task_class_t %s;\n", JDF_OBJECT_ONAME( f )); } + + // If has any parametrized flow + if(JDF_ANY_FLOW_IS_PARAMETRIZED(jdf)) { + coutput("/** Predeclarations of the parametrized spec_TASK_TYPES */\n"); + for(f = jdf->functions; f != NULL; f = f->next) { + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(f)) + { + coutput("static parsec_%s_task_class_t spec_%s;\n", JDF_OBJECT_ONAME(f), JDF_OBJECT_ONAME(f)); + } + } + } + string_arena_free(sa); string_arena_free(sa2); coutput("/** Predeclarations of the parameters */\n"); @@ -1474,10 +1890,19 @@ static void jdf_generate_predeclarations( const jdf_t *jdf ) for(fl = f->dataflow; fl != NULL; fl = fl->next) { rc = asprintf(&JDF_OBJECT_ONAME( fl ), "flow_of_%s_%s_for_%s", jdf_basename, f->fname, fl->varname); assert(rc != -1); - coutput("static const parsec_flow_t %s;\n", - JDF_OBJECT_ONAME( fl )); + coutput("static%s parsec_flow_t %s;%s\n", +#if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) + "", +#else + " const", +#endif + JDF_OBJECT_ONAME( fl ), + // Add a comment to make it clear that the flow is parametrized + FLOW_IS_PARAMETRIZED(fl) ? " /* Parametrized flow, will not be used in the execution, but at init time to set up the parametrized specializations */" : ""); } } + + coutput("\n\n"); (void)rc; } @@ -1581,6 +2006,16 @@ static void jdf_generate_structure(jdf_t *jdf) coutput("/* Globals */\n%s\n", string_arena_get_string(sa1)); } + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput("#define parametrized__f_%s(it) dynamic[(spec_%s.data_dynamic_offset_of_parametrized_%s_%s_for_%s)+(it)]\n", + df->varname, + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + } + } + } + coutput("static inline int parsec_imin(int a, int b) { return (a <= b) ? a : b; };\n\n" "static inline int parsec_imax(int a, int b) { return (a >= b) ? a : b; };\n\n"); @@ -1633,26 +2068,37 @@ static void jdf_generate_structure(jdf_t *jdf) } coutput("/* Release dependencies output macro */\n" - "#if defined(PARSEC_DEBUG_NOISIER)\n" - "#define RELEASE_DEP_OUTPUT(ES, DEPO, TASKO, DEPI, TASKI, RSRC, RDST, DATA)\\\n" - " do { \\\n" - " char tmp1[128], tmp2[128]; (void)tmp1; (void)tmp2;\\\n" - " PARSEC_DEBUG_VERBOSE(20, parsec_debug_output, \"thread %%d VP %%d explore deps from %%s:%%s to %%s:%%s (from rank %%d to %%d) base ptr %%p\",\\\n" - " (NULL != (ES) ? (ES)->th_id : -1), (NULL != (ES) ? (ES)->virtual_process->vp_id : -1),\\\n" - " DEPO, parsec_task_snprintf(tmp1, 128, (parsec_task_t*)(TASKO)),\\\n" - " DEPI, parsec_task_snprintf(tmp2, 128, (parsec_task_t*)(TASKI)), (RSRC), (RDST), (DATA));\\\n" - " } while(0)\n" - "#define ACQUIRE_FLOW(TASKI, DEPI, FUNO, DEPO, LOCALS, PTR)\\\n" - " do { \\\n" - " char tmp1[128], tmp2[128]; (void)tmp1; (void)tmp2;\\\n" - " PARSEC_DEBUG_VERBOSE(20, parsec_debug_output, \"task %%s acquires flow %%s from %%s %%s data ptr %%p\",\\\n" - " parsec_task_snprintf(tmp1, 128, (parsec_task_t*)(TASKI)), (DEPI),\\\n" - " (DEPO), parsec_snprintf_assignments(tmp2, 128, (FUNO), (parsec_assignment_t*)(LOCALS)), (PTR));\\\n" - " } while(0)\n" - "#else\n" - "#define RELEASE_DEP_OUTPUT(ES, DEPO, TASKO, DEPI, TASKI, RSRC, RDST, DATA)\n" - "#define ACQUIRE_FLOW(TASKI, DEPI, TASKO, DEPO, LOCALS, PTR)\n" - "#endif\n"); + "#if defined(PARSEC_DEBUG_NOISIER)\n" + "// for parametrized flow\n" + "#define RELEASE_DEP_OUTPUT_PARAMETRIZED(ES, DEPO, OFFSETO, TASKO, DEPI, OFFSETI, TASKI, RSRC, RDST, DATA)\\\n" + "do { \\\n" + " char tmp1[128], tmp2[128]; (void)tmp1; (void)tmp2;\\\n" + " PARSEC_DEBUG_VERBOSE(20, parsec_debug_output, \"thread %%d VP %%d explore deps from %%s:%%s to %%s:%%s (from rank %%d to %%d) base ptr %%p\",\\\n" + " (NULL != (ES) ? (ES)->th_id : -1), (NULL != (ES) ? (ES)->virtual_process->vp_id : -1),\\\n" + " DEPO, OFFSETO, parsec_task_snprintf(tmp1, 128, (parsec_task_t*)(TASKO)),\\\n" + " DEPI, OFFSETI, parsec_task_snprintf(tmp2, 128, (parsec_task_t*)(TASKI)), (RSRC), (RDST), (DATA));\\\n" + "} while(0)\n" + "// for non-parametrized flow\n" + "#define RELEASE_DEP_OUTPUT(ES, DEPO, TASKO, DEPI, TASKI, RSRC, RDST, DATA)\\\n" + "do { \\\n" + " char tmp1[128], tmp2[128]; (void)tmp1; (void)tmp2;\\\n" + " PARSEC_DEBUG_VERBOSE(20, parsec_debug_output, \"thread %%d VP %%d explore deps from %%s:%%s to %%s:%%s (from rank %%d to %%d) base ptr %%p\",\\\n" + " (NULL != (ES) ? (ES)->th_id : -1), (NULL != (ES) ? (ES)->virtual_process->vp_id : -1),\\\n" + " DEPO, parsec_task_snprintf(tmp1, 128, (parsec_task_t*)(TASKO)),\\\n" + " DEPI, parsec_task_snprintf(tmp2, 128, (parsec_task_t*)(TASKI)), (RSRC), (RDST), (DATA));\\\n" + "} while(0)\n" + "#define ACQUIRE_FLOW(TASKI, DEPI, FUNO, DEPO, LOCALS, PTR)\\\n" + "do { \\\n" + " char tmp1[128], tmp2[128]; (void)tmp1; (void)tmp2;\\\n" + " PARSEC_DEBUG_VERBOSE(20, parsec_debug_output, \"task %%s acquires flow %%s from %%s %%s data ptr %%p\",\\\n" + " parsec_task_snprintf(tmp1, 128, (parsec_task_t*)(TASKI)), (DEPI),\\\n" + " (DEPO), parsec_snprintf_assignments(tmp2, 128, (FUNO), (parsec_assignment_t*)(LOCALS)), (PTR));\\\n" + "} while(0)\n" + "#else\n" + "#define RELEASE_DEP_OUTPUT(ES, DEPO, TASKO, DEPI, TASKI, RSRC, RDST, DATA)\n" + "#define ACQUIRE_FLOW(TASKI, DEPI, TASKO, DEPO, LOCALS, PTR)\n" + "#endif\n"); + string_arena_free(sa1); string_arena_free(sa2); } @@ -1705,10 +2151,93 @@ jdf_generate_function_without_expression(const jdf_t *jdf, coutput("%s\n", UTIL_DUMP_LIST(sa2, f->locals, next, dump_local_assignments, &ai, "", " ", "\n", "\n")); + + // Add parametrized iterators + char *dumped_iterator_lists[MAX_DATAFLOWS_PER_TASK]; + int dumped_iterator_lists_count = 0; + for( jdf_dataflow_t *df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + if(!STRING_IS_IN(get_parametrized_flow_iterator_name(df), dumped_iterator_lists, dumped_iterator_lists_count)) + { + dumped_iterator_lists[dumped_iterator_lists_count++] = get_parametrized_flow_iterator_name(df); + + coutput(" const int %s = locals->ldef[%d].value;\n", + get_parametrized_flow_iterator_name(df), df->local_variables->ldef_index); + } + else + { + coutput(" // Warning: %s already dumped, ldef_index might be ambiguous\n", + get_parametrized_flow_iterator_name(df)); + + // // output an error in stderr too + fprintf(stderr, "Warning: %s already dumped, ldef_index might be ambiguous\n", + get_parametrized_flow_iterator_name(df)); + } + } + } + + + coutput("/*\n // Commented because it gives a lot of errors on valgrind\n #if defined(PARSEC_DEBUG_PARANOID)\n"); + coutput(" // Coherency test:\n"); + dumped_iterator_lists_count = 0; + for( jdf_dataflow_t *df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + if(!STRING_IS_IN(get_parametrized_flow_iterator_name(df), dumped_iterator_lists, dumped_iterator_lists_count)) + { + dumped_iterator_lists[dumped_iterator_lists_count++] = get_parametrized_flow_iterator_name(df); + + expr_info_t info = EMPTY_EXPR_INFO; + info.sa = string_arena_new(8); + info.prefix = ""; + info.suffix = ""; + info.assignments = "assignments"; + + coutput(" if( %s < 0 || %s > %s ) {\n", + get_parametrized_flow_iterator_name(df), + get_parametrized_flow_iterator_name(df), + dump_expr((void**)df->local_variables->jdf_ta2, &info)); + + // Verify that the expression is the same for ALL the vlues from min to max + coutput(" // The local variable is out of its range, this can be reasonable if it does not change the result of the expression\n"); + coutput(" for(int %s = 0; %s <= %s; %s++) {\n", + get_parametrized_flow_iterator_name(df), + get_parametrized_flow_iterator_name(df), + dump_expr((void**)df->local_variables->jdf_ta2, &info), + get_parametrized_flow_iterator_name(df)); + coutput(" const int current_%s = %s;\n", + get_parametrized_flow_iterator_name(df), + get_parametrized_flow_iterator_name(df)); + coutput("#define %s current_%s\n", get_parametrized_flow_iterator_name(df), get_parametrized_flow_iterator_name(df)); + coutput(" const int expr_if_iterator_equals_current = %s;\n", dump_expr((void**)e, &info)); + coutput("#undef %s\n", get_parametrized_flow_iterator_name(df)); + coutput(" assert(expr_if_iterator_equals_current == %s);\n", + dump_expr((void**)e, &info)); + coutput(" }\n"); + coutput(" }\n"); + + string_arena_free(info.sa); + } + } + } + coutput("#endif*/\n"); + + ai.holder = ""; coutput("%s\n", UTIL_DUMP_LIST(sa2, f->locals, next, dump_local_used_in_expr, &ai, "", " (void)", ";\n", ";")); + + string_arena_init(sa); + + // Iterate over every referrer dep + //coutput("%s", dump_referrer_iterator(f, sa, e, name)); + //coutput("//there\n"); + string_arena_init(sa); + + // print name, suffix and rettype + //printf("name: %s, suffix: %s, rettype: %s\n", name, suffix, rettype); + + coutput("\n"); } info.sa = sa; @@ -1741,12 +2270,16 @@ static void jdf_generate_range_min_without_fn(const jdf_t *jdf, const jdf_expr_t for(ld = jdf_expr_lv_first(expr->local_variables); NULL != ld; ld = jdf_expr_lv_next(expr->local_variables, ld)) { assert(ld->ldef_index != -1); if( JDF_RANGE == ld->op ) - coutput(" { /* New scope for local definition '%s' */ \n" - " int %s = %s;\n" - " %s->ldef[%d].value = %s;\n", - ld->alias, - ld->alias, dump_expr((void**)ld->jdf_ta1, &info), - asname, ld->ldef_index, ld->alias); + // TODO: how should we handle this if the variable is at the flow scope? + //if(!VARIABLE_IS_FLOW_LEVEL(flow, ld)) + { + coutput(" { /* New scope for local definition '%s' */ \n" + " int %s = %s;\n" + " %s->ldef[%d].value = %s;\n", + ld->alias, + ld->alias, dump_expr((void**)ld->jdf_ta1, &info), + asname, ld->ldef_index, ld->alias); + } else coutput(" { /* New scope for local definition '%s' */ \n" " int %s = %s;\n" @@ -1779,12 +2312,35 @@ static void jdf_generate_range_min(const jdf_t *jdf, const jdf_function_entry_t " int32_t __parsec_ret;\n", fn_name, jdf_basename, parsec_get_name(jdf, f, "parsec_assignment_t")); + // Declare the parametrized variables + /*for(jdf_dataflow_t *flow = f->dataflow; NULL != flow; flow = flow->next) { + for(jdf_expr_t *it=f->dataflow->local_variables; NULL != it; it = it->next) { + coutput(" int %s = locals->ldef[%d].value;\n", it->alias, it->ldef_index); + } + } + for(jdf_dataflow_t *flow = f->dataflow; NULL != flow; flow = flow->next) { + for(jdf_expr_t *it=f->dataflow->local_variables; NULL != it; it = it->next) { + coutput(" (void) %s;\n", it->alias); + } + }*/ + + ai.sa = sa; ai.holder = "locals->"; ai.expr = expr; coutput("%s\n", UTIL_DUMP_LIST(sa2, f->locals, next, dump_local_assignments, &ai, "", " ", "\n", "\n")); + + string_arena_init(sa); + + // Iterate over every referrer dep + //coutput("%s", dump_referrer_iterator(f, sa, expr, fn_name)); + //coutput("//here\n"); + string_arena_init(sa); + + coutput("\n"); + string_arena_free(sa); string_arena_free(sa2); @@ -1793,12 +2349,17 @@ static void jdf_generate_range_min(const jdf_t *jdf, const jdf_function_entry_t " return __parsec_ret;\n" "}\n"); - coutput("static const parsec_expr_t %s = {\n" + coutput("static%s parsec_expr_t %s = {\n" " .op = PARSEC_EXPR_OP_INLINE,\n" " .u_expr.v_func = { .type = %s, /* PARSEC_RETURN_TYPE_INT32 */\n" " .func = { .inline_func_int32 = (parsec_expr_op_int32_inline_func_t)%s_fct }\n" " }\n" "};\n", +#if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) + "", +#else + " const", +#endif fn_name, enum_type_name(0), fn_name); } @@ -1856,12 +2417,17 @@ static void jdf_generate_range_max(const jdf_t *jdf, const jdf_function_entry_t " return __parsec_ret;\n" "}\n"); - coutput("static const parsec_expr_t %s = {\n" + coutput("static%s parsec_expr_t %s = {\n" " .op = PARSEC_EXPR_OP_INLINE,\n" " .u_expr.v_func = { .type = %s, /* PARSEC_RETURN_TYPE_INT32 */\n" " .func = { .inline_func_int32 = (parsec_expr_op_int32_inline_func_t)%s_fct }\n" " }\n" "};\n", +#if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) + "", +#else + " const", +#endif fn_name, enum_type_name(0), fn_name); string_arena_free(sa); @@ -1914,12 +2480,17 @@ static void jdf_generate_range_increment(const jdf_t *jdf, const jdf_function_en " return __parsec_ret;\n" "}\n"); - coutput("static const parsec_expr_t %s = {\n" + coutput("static%s parsec_expr_t %s = {\n" " .op = PARSEC_EXPR_OP_INLINE,\n" " .u_expr.v_func = { .type = %s, /* PARSEC_RETURN_TYPE_INT32 */\n" " .func = { .inline_func_int32 = (parsec_expr_op_int32_inline_func_t)%s_fct }\n" " }\n" "};\n", +#if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) + "", +#else + " const", +#endif fn_name, enum_type_name(0), fn_name); string_arena_free(sa); @@ -2011,7 +2582,7 @@ static void jdf_generate_affinity( const jdf_t *jdf, const jdf_function_entry_t " parsec_data_ref_t *ref)\n" "{\n" " const __parsec_%s_internal_taskpool_t *__parsec_tp = (const __parsec_%s_internal_taskpool_t*)this_task->taskpool;\n", - name, parsec_get_name(jdf, f, "task_t"), + name, parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename); info.sa = sa5; @@ -2528,9 +3099,14 @@ static int jdf_generate_dependency( const jdf_t *jdf, jdf_dataflow_t *flow, jdf_ dump_expr((void**)dep->guard->guard, &info); } string_arena_add_string(sa, - "static const parsec_dep_t %s = {\n" + "static%s parsec_dep_t %s = {\n" " .cond = %s, /* %s%s */\n" " .ctl_gather_nb = %s,\n", +#if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) + "", +#else + " const", +#endif JDF_OBJECT_ONAME(call), condname, (call == dep->guard->calltrue ? "" : "!"), string_arena_get_string(sa3), string_arena_get_string(sa2)); @@ -2594,6 +3170,41 @@ static int jdf_generate_dependency( const jdf_t *jdf, jdf_dataflow_t *flow, jdf_ return ret; } +static inline jdf_expr_t *jdf_create_parametrized_referrer_expr_cond(jdf_expr_t *cond, jdf_expr_t *iterator, jdf_expr_t *parametrized_expr) +{ + // goal: cond -> (iterator == expr) && cond + + jdf_expr_t *iterator_new = malloc(sizeof(jdf_expr_t)); + memcpy(iterator_new, iterator, sizeof(jdf_expr_t)); + iterator_new->op = JDF_VAR; + iterator_new->jdf_var = strdup(iterator->alias); + + jdf_expr_t *equal_expr = malloc(sizeof(jdf_expr_t)); + memcpy(equal_expr, cond, sizeof(jdf_expr_t)); + equal_expr->op = JDF_EQUAL; + equal_expr->jdf_ba1 = iterator_new; + equal_expr->jdf_ba2 = parametrized_expr; + + jdf_expr_t *and_expr = malloc(sizeof(jdf_expr_t)); + memcpy(and_expr, cond, sizeof(jdf_expr_t)); // copy to have the same jdf_obj parameters + and_expr->op = JDF_AND; + and_expr->jdf_ba1 = equal_expr; + and_expr->jdf_ba2 = cond; + + return and_expr; +} + +/* +static inline jdf_expr_t *jdf_create_parametrized_referrer_expr_cond_if_parametrized(jdf_call_t *call, jdf_expr_t *cond) +{ + if (NULL == call->parametrized_offset) { + return cond; + } + + return jdf_create_parametrized_referrer_expr_cond(cond, call->parametrized_offset, call->parametrized_offset); +} +*/ + static int jdf_generate_dataflow( const jdf_t *jdf, const jdf_function_entry_t* f, jdf_dataflow_t *flow, const char *prefix, int *has_control_gather ) @@ -2606,7 +3217,7 @@ static int jdf_generate_dataflow( const jdf_t *jdf, const jdf_function_entry_t* string_arena_t* flow_flags = string_arena_new(64); string_arena_t *psa; jdf_dep_t *dl; - uint32_t flow_datatype_mask = 0; + parsec_dependency_t flow_datatype_mask = 0; char sep_in[4], sep_out[4]; /* one char more to deal with '\n' special cases (Windows) */ (void)jdf; @@ -2717,15 +3328,20 @@ static int jdf_generate_dataflow( const jdf_t *jdf, const jdf_function_entry_t* deps_out, MAX_DEP_OUT_COUNT, deps_out); } string_arena_add_string(sa, - "\nstatic const parsec_flow_t %s = {\n" + "\nstatic%s parsec_flow_t %s = {\n" " .name = \"%s\",\n" " .sym_type = %s,\n" " .flow_flags = %s,\n" " .flow_index = %u,\n" - " .flow_datatype_mask = 0x%x,\n" + " .flow_datatype_mask = 0x%lx,\n" " .dep_in = { %s },\n" " .dep_out = { %s }\n" "};\n\n", +#if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) + "", +#else + " const", +#endif JDF_OBJECT_ONAME(flow), flow->varname, sym_type, @@ -2999,8 +3615,8 @@ static void jdf_generate_startup_tasks(const jdf_t *jdf, const jdf_function_entr " size_t total_nb_tasks = 0;\n" " parsec_list_item_t* pready_ring[context->nb_vp];\n" " int restore_context = 0;\n", - fname, parsec_get_name(jdf, f, "task_t"), - parsec_get_name(jdf, f, "task_t"), + fname, parsec_get_task_type_name(jdf, f), + parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename); for(vl = f->locals; vl != NULL; vl = vl->next) @@ -3107,7 +3723,7 @@ static void jdf_generate_startup_tasks(const jdf_t *jdf, const jdf_function_entr indent(nesting), indent(nesting), indent(nesting), - indent(nesting), parsec_get_name(jdf, f, "task_t"), + indent(nesting), parsec_get_task_type_name(jdf, f), indent(nesting)); JDF_COUNT_LIST_ENTRIES(f->locals, jdf_variable_list_t, next, nb_locals); @@ -3136,16 +3752,58 @@ static void jdf_generate_startup_tasks(const jdf_t *jdf, const jdf_function_entr { struct jdf_dataflow *dataflow = f->dataflow; for(idx = 0; NULL != dataflow; idx++, dataflow = dataflow->next ) { - coutput("%s new_task->data._f_%s.source_repo_entry = NULL;\n" - "%s new_task->data._f_%s.source_repo = NULL;\n" - "%s new_task->data._f_%s.data_in = NULL;\n" - "%s new_task->data._f_%s.data_out = NULL;\n" - "%s new_task->data._f_%s.fulfill = 0;\n", - indent(nesting), dataflow->varname, - indent(nesting), dataflow->varname, - indent(nesting), dataflow->varname, - indent(nesting), dataflow->varname, - indent(nesting), dataflow->varname); + string_arena_t *osa = string_arena_new(16); + + + if( FLOW_IS_PARAMETRIZED(dataflow) ) { + expr_info_t expr_info = EMPTY_EXPR_INFO; + expr_info.sa = string_arena_new(32); + expr_info.prefix = ""; + expr_info.suffix = ""; + expr_info.assignments = "max parametrized dataflow"; + + jdf_expr_t *variable = jdf_expr_lv_first(dataflow->local_variables); + assert(variable->op == JDF_PARAMETRIZED_FLOW_RANGE); + jdf_expr_t *max_parametrized_flow = variable->jdf_ta2; + + // TODO test + coutput("\n%s this_task->data._f_%s = malloc(sizeof(parsec_data_pair_t)*((%s)+1));\n", + indent(nesting), dataflow->varname, dump_expr((void**)max_parametrized_flow, &expr_info)); + coutput("%s assert( NULL != this_task->data._f_%s );\n", indent(nesting), dataflow->varname); + coutput("%s memset(this_task->data._f_%s, 0, sizeof(parsec_data_pair_t)*((%s)+1));\n", + indent(nesting), dataflow->varname, dump_expr((void**)max_parametrized_flow, &expr_info)); + } + + string_arena_t *sa = string_arena_new(256); + dump_parametrized_flow_loop_if_parametrized(dataflow, indent(nesting), sa); + coutput("%s", string_arena_get_string(sa)); + + // increase nesting if parametrized + if( FLOW_IS_PARAMETRIZED(dataflow) ) { + nesting++; + } + + coutput("%s new_task->data.%s.source_repo_entry = NULL;\n" + "%s new_task->data.%s.source_repo = NULL;\n" + "%s new_task->data.%s.data_in = NULL;\n" + "%s new_task->data.%s.data_out = NULL;\n" + "%s new_task->data.%s.fulfill = 0;\n", + indent(nesting), DUMP_DATA_FIELD_NAME_IN_TASK(osa, dataflow), + indent(nesting), DUMP_DATA_FIELD_NAME_IN_TASK(osa, dataflow), + indent(nesting), DUMP_DATA_FIELD_NAME_IN_TASK(osa, dataflow), + indent(nesting), DUMP_DATA_FIELD_NAME_IN_TASK(osa, dataflow), + indent(nesting), DUMP_DATA_FIELD_NAME_IN_TASK(osa, dataflow)); + + string_arena_init(sa); + dump_parametrized_flow_loop_end_if_parametrized(dataflow, indent(nesting), sa); + coutput("%s", string_arena_get_string(sa)); + + string_arena_free(sa); + string_arena_free(osa); + + if(FLOW_IS_PARAMETRIZED(dataflow)) { + nesting--; + } } } @@ -3210,6 +3868,115 @@ static void jdf_generate_startup_tasks(const jdf_t *jdf, const jdf_function_entr "}\n\n"); } +void jdf_generate_task_constructor(const jdf_t *jdf, jdf_function_entry_t *f) +{ + /*coutput( + "int %s(const parsec_task_t* task)\n" + "{\n" + " %s *spec_task = (%s*)task;\n" + " const __parsec_%s_internal_taskpool_t *__parsec_tp = (const __parsec_%s_internal_taskpool_t *)task->taskpool;\n" + , parsec_get_name(NULL, f, "constructor"), + parsec_get_name(jdf, f, "task_t"), parsec_get_name(jdf, f, "task_t"), + jdf_basename, jdf_basename); + + string_arena_t *sa = string_arena_new(64); + + coutput(" int specializations_num = 0;\n"); + + for(jdf_dataflow_t *flow = f->dataflow; NULL != flow; flow = flow->next) { + if( FLOW_IS_PARAMETRIZED(flow) ) { + coutput(" specializations_num += %s;\n", jdf_expr_print(sa, flow->expr)); + + string_arena_init(sa); + dump_parametrized_flow_loop(flow, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(flow), " ", sa); + coutput("%s", string_arena_get_string(sa)); + + coutput(" // ...\n"); + + string_arena_init(sa); + dump_parametrized_flow_loop_end(flow, " ", sa); + coutput("%s", string_arena_get_string(sa)); + } + } + + coutput(" memset(spec_task->data.dynamic, 0, sizeof(parsec_data_pair_t) * MAX_LOCAL_COUNT);\n"); + + string_arena_free(sa); +*/ +/* +string_arena_init(sa); + dump_parametrized_flow_loop(df, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), " ", sa); + + // First parametrized flows: + string_arena_add_string(sa, " // Local parametrized flows of %s\n", f->fname); + string_arena_add_string(sa, "#if defined(PARSEC_DEBUG_NOISIER)\n"); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + string_arena_add_string(sa, " , .nb_specializations_flow_of_%s_%s_for_%s = -1\n", jdf_basename, f->fname, df->varname); + } + } + string_arena_add_string(sa, "#endif\n"); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + string_arena_add_string(sa, " , .out_dep_offset_flow_of_%s_%s_for_%s = -1\n", jdf_basename, f->fname, df->varname); + // store the offset for every output dep of this parametrized flow + string_arena_add_string(sa, " , .out_offset_dep_of_%s_%s_for_%s = -1\n", jdf_basename, f->fname, df->varname); + } + } + +*/ + + + + +/* +TODO: framework suggested by Thomas: + +int __parsec_LBM_LBM_STEP_constructor(parsec_task_t *task) { + // initialize the fields above the base object on which the task derives +} + +PARSEC_OBJ_DECLARE(__parsec_LBM_LBM_STEP_task_t); +PARSEC_OBJ_CLASS_INSTANCE(__parsec_LBM_LBM_STEP_task_t, parsec_list_item_t, + __parsec_LBM_LBM_STEP_constructor, NULL); + +void __parsec_LBM_LBM_new_task(parsec_task_t **task) +{ + __parsec_LBM_LBM_STEP_task_t *n = PARSEC_OBJ_NEW(__parsec_LBM_LBM_STEP_task_t); + *task = &n->super; +} + +parsec_taskpool_t *LBM_new(...) +{ + parsec_taskpool_t *lbm_tp = malloc(...); + ... + lbm_tp->new_task = __parsec_LBM_LBM_new_task; + ... + return lbm_tp; +} +*/ + + + // simple version: + coutput( + "int %s(const parsec_task_t** task)\n" + "{\n" + " %s *spec_task = (%s*)(*task);\n", + parsec_get_name(NULL, f, "constructor"), + parsec_get_name(jdf, f, "task_t"), parsec_get_name(jdf, f, "task_t")); + + int non_parametrized_count = 0; + for(jdf_dataflow_t *flow = f->dataflow; NULL != flow; flow = flow->next) { + if( !FLOW_IS_PARAMETRIZED(flow) ) { + non_parametrized_count++; + } + } + + coutput(" memset(spec_task->data.dynamic, 0, sizeof(parsec_data_pair_t) * (MAX_LOCAL_COUNT-%d));\n", non_parametrized_count); + + coutput( "}\n"); +} + /* structure to handle the correspondence between local variables and function parameters */ typedef struct jdf_l2p_s { const jdf_variable_list_t *vl; @@ -3426,7 +4193,7 @@ static void jdf_generate_internal_init(const jdf_t *jdf, const jdf_function_entr need_min_max ? "min-max" : "-", need_to_count_tasks ? "count-tasks" : "-", need_to_iterate ? "iterate" : "-", - fname, parsec_get_name(jdf, f, "task_t"), + fname, parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename); if(need_to_count_tasks) { @@ -3755,6 +4522,7 @@ static void jdf_generate_internal_init(const jdf_t *jdf, const jdf_function_entr if( f->user_defines & JDF_FUNCTION_HAS_UD_DEPENDENCIES_FUNS ) { coutput(" PARSEC_DEBUG_VERBOSE(20, parsec_debug_output, \"Allocating dependencies array for %s (user-defined allocator)\\n\");\n", fname); + // TODO: if the flow is parametrized: need to be smarter coutput(" __parsec_tp->super.super.dependencies_array[%d] = %s(__parsec_tp);\n", f->task_class_id, jdf_property_get_function(f->properties, JDF_PROP_UD_ALLOC_DEPS_FN_NAME, NULL)); } else { @@ -3771,15 +4539,27 @@ static void jdf_generate_internal_init(const jdf_t *jdf, const jdf_function_entr } } - /* Generate the repo for all tasks classes, they can be used when: - * - a predecessor sets up a reshape promised for a datacopy - * - the own tasks use it when reshaping a datacopy directly read from desc - * No longer only when if( !(f->flags & JDF_FUNCTION_FLAG_NO_SUCCESSORS) ) - */ - coutput(" __parsec_tp->repositories[%d] = data_repo_create_nothreadsafe(%s, %s, (parsec_taskpool_t*)__parsec_tp, %d);\n", + string_arena_t *sa_item_num = string_arena_new(128); + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) + { + DUMP_NUMBER_OF_FLOWS_IN_TASK_CLASS(sa_item_num, jdf_basename, f); + } + else + { + string_arena_add_string(sa_item_num, "%d", idx); + } + + /* Generate the repo for all tasks classes, they can be used when: + * - a predecessor sets up a reshape promised for a datacopy + * - the own tasks use it when reshaping a datacopy directly read from desc + * No longer only when if( !(f->flags & JDF_FUNCTION_FLAG_NO_SUCCESSORS) ) + */ + coutput(" __parsec_tp->repositories[%d] = data_repo_create_nothreadsafe(%s, %s, (parsec_taskpool_t*)__parsec_tp, %s);\n", f->task_class_id, need_to_count_tasks ? "nb_tasks" : "PARSEC_DEFAULT_DATAREPO_HASH_LENGTH", jdf_property_get_string(f->properties, JDF_PROP_UD_HASH_STRUCT_NAME, NULL), - idx ); + string_arena_get_string(sa_item_num) ); + + string_arena_free(sa_item_num); coutput("%s" " %s (void)__parsec_tp; (void)es;\n", @@ -3858,7 +4638,7 @@ static void jdf_generate_simulation_cost_fct(const jdf_t *jdf, const jdf_functio " const parsec_taskpool_t *__parsec_tp = (const parsec_taskpool_t*)this_task->taskpool;\n" "%s" " (void)__parsec_tp;\n", - prefix, parsec_get_name(jdf, f, "task_t"), + prefix, parsec_get_task_type_name(jdf, f), UTIL_DUMP_LIST(sa1, f->locals, next, dump_local_assignments, &ai, "", " ", "\n", "\n")); @@ -4087,7 +4867,7 @@ static void jdf_generate_one_function( const jdf_t *jdf, jdf_function_entry_t *f "static const parsec_task_class_t %s = {\n" " .name = \"%s\",\n" " .task_class_id = %d,\n" - " .nb_flows = %d,\n" + " .nb_flows = %d,\n" // TODO change nb_flows when parametrized " .nb_parameters = %d,\n" " .nb_locals = %d,\n" " .task_class_type = PARSEC_TASK_CLASS_TYPE_PTG,\n", @@ -4163,12 +4943,12 @@ static void jdf_generate_one_function( const jdf_t *jdf, jdf_function_entry_t *f out_flows += !!(fl->flow_flags & JDF_FLOW_TYPE_WRITE); } string_arena_add_string(sa, - "#if MAX_PARAM_COUNT < %d /* number of read flows of %s */\n" + "#if MAX_DATAFLOWS_PER_TASK < %d /* number of read flows of %s */\n" " #error Too many read flows for task %s\n" - "#endif /* MAX_PARAM_COUNT */\n" - "#if MAX_PARAM_COUNT < %d /* number of write flows of %s */\n" + "#endif /* MAX_DATAFLOWS_PER_TASK */\n" + "#if MAX_DATAFLOWS_PER_TASK < %d /* number of write flows of %s */\n" " #error Too many write flows for task %s\n" - "#endif /* MAX_PARAM_COUNT */\n", + "#endif /* MAX_DATAFLOWS_PER_TASK */\n", in_flows, f->fname, f->fname, out_flows, f->fname, f->fname); } @@ -4271,6 +5051,7 @@ static void jdf_generate_one_function( const jdf_t *jdf, jdf_function_entry_t *f jdf_generate_code_release_deps(jdf, f, prefix); string_arena_add_string(sa, " .release_deps = (parsec_release_deps_t*)%s,\n", prefix); +// Parametrized flows: TODO sprintf(prefix, "data_lookup_of_%s_%s", jdf_basename, f->fname); jdf_generate_code_data_lookup(jdf, f, prefix); string_arena_add_string(sa, " .prepare_output = (parsec_hook_t*)%s,\n", "NULL"); @@ -4298,6 +5079,28 @@ static void jdf_generate_one_function( const jdf_t *jdf, jdf_function_entry_t *f string_arena_add_string(sa, " .release_task = &%s,\n", prefix); } + + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) { + string_arena_add_string(sa, " .new_task = &%s,\n", parsec_get_name(NULL, f, "constructor")); + + /*string_arena_add_string(sa, + "PARSEC_OBJ_CLASS_DECLARATION(%s);\n" + "PARSEC_OBJ_CLASS_INSTANCE(%s, %s,\n" + " %s, NULL);\n\n", + parsec_get_name(NULL, f, "task_t"), + parsec_get_name(NULL, f, "task_t"), + "parsec_list_item_t", + //parsec_get_name(NULL, f, "constructor") + "NULL" + );*/ + } + else + { + string_arena_add_string(sa, " .new_task = NULL,\n"); + } + + //.new_task = (parsec_task_new_t*)new_task_of_%s_%s, + if( NULL != f->simcost ) { sprintf(prefix, "simulation_cost_of_%s_%s", jdf_basename, f->fname); jdf_generate_simulation_cost_fct(jdf, f, prefix); @@ -4320,8 +5123,140 @@ static void jdf_generate_one_function( const jdf_t *jdf, jdf_function_entry_t *f jdf_generate_startup_tasks(jdf, f, jdf_property_get_function(f->properties, JDF_PROP_UD_STARTUP_TASKS_FN_NAME, NULL)); } + if( TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f) ) { + jdf_generate_task_constructor(jdf, f); + } + string_arena_add_string(sa, "};\n"); + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(f)) + { + string_arena_add_string(sa, "static parsec_%s_task_class_t spec_%s = {\n", JDF_OBJECT_ONAME(f), JDF_OBJECT_ONAME(f)); + string_arena_add_string(sa, " .super = %s\n", JDF_OBJECT_ONAME(f)); + + // Masks: + // If any flow/dep is parametrized/referrer, all the action masks have to be dynamically computed + string_arena_add_string(sa, " // Action masks of %s\n", f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + string_arena_add_string(sa, " , .dep_mask_out_of_flow_of_%s_%s_for_%s = 0x0\n", + jdf_basename, f->fname, df->varname); + } + string_arena_add_string(sa, " , .dep_mask_out_of_flow_of_%s_%s = 0x0\n", + jdf_basename, f->fname); + + + // Parametrized flows: + string_arena_add_string(sa, " // Local parametrized flows of %s\n", f->fname); + string_arena_add_string(sa, "//#if defined(PARSEC_DEBUG_NOISIER) // used in release mode too now\n"); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + string_arena_add_string(sa, " , .nb_specializations_of_parametrized_flow_of_%s_%s_for_%s = -1\n", jdf_basename, f->fname, df->varname); + } + } + string_arena_add_string(sa, "//#endif\n"); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + // store the offset for every output dep of this parametrized flow + if(df->flow_flags & JDF_FLOW_TYPE_READ) + string_arena_add_string(sa, " , .in_flow_offset_of_parametrized_%s = -1\n", JDF_OBJECT_ONAME(df)); + if(df->flow_flags & JDF_FLOW_TYPE_WRITE) + string_arena_add_string(sa, " , .out_flow_offset_of_parametrized_%s = -1\n", JDF_OBJECT_ONAME(df)); + string_arena_add_string(sa, " , .data_dynamic_offset_of_parametrized_%s_%s_for_%s = -1\n", jdf_basename, f->fname, df->varname); + } + } + + // Referrers + string_arena_add_string(sa, " // Local referrers of %s\n", f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + int depid=1; + for( jdf_dep_t *dep = df->deps; NULL != dep; dep = dep->next, depid++ ) { + if((dep->dep_flags & JDF_DEP_FLOW_OUT) == 0) + { // We only need the out indices + continue; + } + + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + if( NULL != call->parametrized_offset ) + { + string_arena_add_string(sa, " , .out_dep_offset_of_referrer%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = -1\n", + FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + string_arena_add_string(sa, " , .out_flow_offset_of_referrer%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = -1\n", + FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + } + } + } + } + + + // Then the dep offsets to every non-parametrized flow + string_arena_add_string(sa, " // Dep offsets of non-referrers of %s\n", f->fname); + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) + { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + int depid=1; + for( jdf_dep_t *dep = df->deps; NULL != dep; dep = dep->next, depid++ ) { + if((dep->dep_flags & JDF_DEP_FLOW_OUT) == 0) + { // We only need the out indices + continue; + } + + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + // If the target is NOT parametrized + if( NULL == call->parametrized_offset ) + { + string_arena_add_string(sa, " , .out_dep_offset_of%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = -1\n", + FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + /*string_arena_add_string(sa, " , .out_flow_offset_of_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = -1\n", + jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "");*/ + } + } + } + } + + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) + { + string_arena_add_string(sa, " // Task class %s has at least one parametrized flow: we need to store the flow id of every flow\n", f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + string_arena_add_string(sa, " , .flow_id_of_flow_of_%s_%s_for_%s = %d\n", + jdf_basename, f->fname, df->varname, df->flow_index); + } + } + } + + string_arena_add_string(sa, "\n};"); + + } + + coutput("\n\n"); + coutput("%s\n\n", string_arena_get_string(sa)); string_arena_free(sa2); @@ -4611,7 +5546,7 @@ static void jdf_generate_constructor( const jdf_t* jdf ) " __parsec_tp->super.super.dependencies_array = (void **)\n" " calloc(__parsec_tp->super.super.nb_task_classes, sizeof(void*));\n" " /* Twice the size to hold the startup tasks function_t */\n" - " __parsec_tp->super.super.task_classes_array = (const parsec_task_class_t**)\n" + " __parsec_tp->super.super.task_classes_array = (parsec_task_class_t**)\n" " calloc((2 * PARSEC_%s_NB_TASK_CLASSES + 1), sizeof(parsec_task_class_t*));\n" " __parsec_tp->super.super.tdm.module->taskpool_addto_runtime_actions(&__parsec_tp->super.super, PARSEC_%s_NB_TASK_CLASSES); /* for the startup tasks */\n" " __parsec_tp->super.super.taskpool_type = PARSEC_TASKPOOL_TYPE_PTG;\n" @@ -4623,7 +5558,7 @@ static void jdf_generate_constructor( const jdf_t* jdf ) string_arena_get_string(jdf->termdet_init_line), jdf_basename, jdf_basename, string_arena_get_string(sa1)); - +// TODO use uintX_t instead of uint8 if MAX_DEP_IN_COUNT or MAX_DEP_OUT > 8 ? (in the task structure) /* Prepare the functions */ coutput(" for( i = 0; i < __parsec_tp->super.super.nb_task_classes; i++ ) {\n" " __parsec_tp->super.super.task_classes_array[i] = tc = malloc(sizeof(parsec_task_class_t));\n" @@ -4638,6 +5573,10 @@ static void jdf_generate_constructor( const jdf_t* jdf ) " tc->incarnations = (__parsec_chore_t*)malloc(2 * sizeof(__parsec_chore_t));\n" " memcpy((__parsec_chore_t*)tc->incarnations, (void*)__parsec_generic_startup.incarnations, 2 * sizeof(__parsec_chore_t));\n" " tc->release_task = parsec_release_task_to_mempool_and_count_as_runtime_tasks;\n" + "\n" + "#if defined(PARSEC_DEBUG_PARANOID)\n" + " parsec_check_sanity_of_task_class(tc, true);\n" + "#endif\n" " }\n", jdf_basename, jdf_basename); @@ -4727,8 +5666,19 @@ static void jdf_generate_constructor( const jdf_t* jdf ) coutput(" __parsec_tp->super.super.repo_array = %s;\n", (NULL != jdf->functions) ? "__parsec_tp->repositories" : "NULL"); +// TODO use uintX_t instead of uint8 if MAX_DEP_IN_COUNT or MAX_DEP_OUT > 8 ? (in the task structure) coutput(" __parsec_tp->super.super.startup_hook = (parsec_startup_fn_t)%s_startup;\n" " (void)parsec_taskpool_reserve_id((parsec_taskpool_t*)__parsec_tp);\n" + "\n\n" + "#if defined(PARSEC_DEBUG_PARANOID)\n" + " // use parsec_debug_dump_task_class_at_exec(tc); on each task class\n" + " parsec_debug_verbose(10, parsec_debug_output, \"############ Task classes before update ############\\n\");\n" + " for( uint32_t i = 0; i < __parsec_tp->super.super.nb_task_classes; i++ ) {\n" + " parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[i];\n" + " parsec_debug_dump_task_class_at_exec(tc);\n" + " parsec_check_sanity_of_task_class(tc, true);\n" + " }\n" + "#endif\n" "}\n\n", jdf_basename); @@ -4743,6 +5693,8 @@ static void jdf_generate_new_function( const jdf_t* jdf ) sa1 = string_arena_new(64); sa2 = string_arena_new(64); + string_arena_t *sa = string_arena_new(64); + coutput("%s\n", UTIL_DUMP_LIST_FIELD( sa1, jdf->globals, next, name, dump_string, NULL, "", "#undef ", "\n", "\n")); @@ -4770,6 +5722,1197 @@ static void jdf_generate_new_function( const jdf_t* jdf ) "%s", UTIL_DUMP_LIST(sa1, jdf->globals, next, dump_globals_init, sa2, "", " ", "\n", "\n")); + if(JDF_ANY_FLOW_IS_PARAMETRIZED(jdf)) + { + int depid; + + coutput( + "\n" + " // Rework the structure to handle parametrized flows\n" + "\n" + " int i, j;\n" + " /* update the dependency IDs in case of parametrized flows */\n" + " /* The general idea is: */\n" + " /* (A) If a dependency refers to a parametrized flow, it should be divided into N dependencies, */\n" + " /* With each dependency referring to the corresponding flow and having the corresponding cond */\n" + " /* E.g. the jdf: DATA_FROM -> DATA_TO[i+j*SIZE] MyFunc(...) */\n" + " /* should translate into : */\n" + " /* -> ((i+j*SIZE)==0) ? DATA_TO[0] SuccFunc(...) */\n" + " /* -> ((i+j*SIZE)==1) ? DATA_TO[1] SuccFunc(...) */\n" + " /**/\n" + " /* (B) On the other side, if a flow is parametrized: */\n" + " /* It should be divided into N flows, the deps of which should be correctly linked with the corresponding generated dep in (A) */\n" + " /* E.g. the jdf: DATA_TO[it=0...N-1] <- DATA_FROM PredFunc(it%%SIZE, it/size, ...) */\n" + " /* should translate into : */\n" + " /* DATA_TO[0] <- DATA_FROM PredFunc(0, 0, ...) */\n" + " /* DATA_TO[1] <- DATA_FROM PredFunc(1, 0, ...) */\n" + " /* ... */\n" + " /* DATA_TO[SIZE] <- DATA_FROM PredFunc(0, 1, ...) */\n" + " /* DATA_TO[SIZE+1] ... */\n" + " /**/\n" + " /* We refer to (A) as referrer and to (B) as parametrized flow. */\n\n" + ); + + // TODO: delete the following lines when the code is ready +/* + coutput( + " // list of parametrized flows\n" + ); + + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + expr_info_t expr_info = EMPTY_EXPR_INFO; + expr_info.sa = string_arena_new(64); + expr_info.prefix = ""; + expr_info.suffix = ""; + expr_info.assignments = "parametrized flow range"; + + //jdf_expr_t *from = variable->jdf_ta1; + jdf_expr_t *to = df->local_variables->jdf_ta2; + //jdf_expr_t *step = variable->jdf_ta3; + + coutput(" parsec_flow_t *new_flow_for_task_%s_parametrized_flow_%s[(%s)+1];\n", + f->fname, df->varname, dump_expr((void**)to, &expr_info)); + } + } + } + + coutput("\n"); +*/ + + coutput(" // Declarations\n\n"); + + coutput(" // Declaration of parametrized flow specializations:\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + + coutput(" parsec_flow_t *flow_of_%s_%s_for_parametrized_%s;\n", + jdf_basename, f->fname, df->varname); + } + } + } + + coutput(" // Declaration of the parametrized flows referrers\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + depid=1; + for( jdf_dep_t *dep = df->deps; NULL != dep; dep = dep->next, depid++ ) { + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + if( NULL != call->parametrized_offset ) + { + // Then the dep refers to a parametrized flow + + coutput(" parsec_dep_t *%s_referrer_dep%d_atline_%d%s;\n", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + } + } + } + } + } + + // Set the parametrized flows upper bounds + coutput(" // Upper bounds\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + expr_info_t expr_info = EMPTY_EXPR_INFO; + expr_info.sa = string_arena_new(64); + expr_info.prefix = ""; + expr_info.suffix = ""; + expr_info.assignments = "parametrized flow range"; + + //jdf_expr_t *from = variable->jdf_ta1; + jdf_expr_t *to = df->local_variables->jdf_ta2; + //jdf_expr_t *step = variable->jdf_ta3; + + coutput(" const int nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s = (%s)+1;\n", + jdf_basename, f->fname, df->varname, dump_expr((void**)to, &expr_info)); + } + } + } + coutput(" // Parametrized flows\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" flow_of_%s_%s_for_parametrized_%s = malloc(sizeof(parsec_flow_t) * nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s);\n", + jdf_basename, f->fname, df->varname, jdf_basename, f->fname, df->varname); + } + } + } + coutput(" // Referrers\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + depid=1; + for( jdf_dep_t *dep = df->deps; NULL != dep; dep = dep->next, depid++ ) { + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + if( NULL != call->parametrized_offset ) + { + // Then the dep refers to a parametrized flow + + if(!FLOW_IS_PARAMETRIZED(df)) + { + coutput(" %s_referrer_dep%d_atline_%d%s = malloc(sizeof(parsec_dep_t) * nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s);\n", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "", + jdf_basename, call->func_or_mem, call->var); + } + else + { + coutput(" %s_referrer_dep%d_atline_%d%s = malloc(sizeof(parsec_dep_t) * " + "nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s * " + "nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s);\n", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "", + jdf_basename, call->func_or_mem, call->var, + jdf_basename, f->fname, df->varname); + } + } + } + } + } + } + coutput("\n"); + + coutput(" // Set the number of specializations\n"); + coutput("//#if defined(PARSEC_DEBUG_NOISIER) // used in release mode too now\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" spec_%s.nb_specializations_of_parametrized_flow_of_%s_%s_for_%s = nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s;\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, jdf_basename, f->fname, df->varname); + } + } + } + coutput("//#endif\n"); + coutput("\n"); + + // TODO delete parametrized_flows when not needed anymore! + coutput("/* // Store parametrized flows in a table for convenience\n"); + coutput(" parsec_flow_t const *parametrized_flows[MAX_DATAFLOWS_PER_TASK] = {\n"); + int nb_parametrized_flows = 0; + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" &flow_of_%s_%s_for_%s,\n", jdf_basename, f->fname, df->varname); + ++ nb_parametrized_flows; + } + } + } + coutput(" NULL\n };*/\n"); + coutput("\n"); + + // Declare local arrays to simplify the future parametrization of flows + coutput(" const int nb_parametrized_flows = %d;\n", nb_parametrized_flows); + // Number of specializations of each parametrized flow + coutput(" const int nb_specializations_of_parametrized_flows[] = {\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s,\n", jdf_basename, f->fname, df->varname); + } + } + } + coutput(" 0\n };\n"); + // Task class of each parametrized flow + coutput(" parsec_task_class_t *task_class_of_parametrized_flows[] = {\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" __parsec_tp->super.super.task_classes_array[%d],\n", f->task_class_id); + } + } + } + coutput(" NULL\n };\n"); + // Specialization array of each parametrized flow + coutput(" parsec_flow_t *specialization_array_of_parametrized_flows[] = {\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" &flow_of_%s_%s_for_parametrized_%s[0],\n", jdf_basename, f->fname, df->varname); + } + } + } + coutput(" NULL\n };\n"); + // Base flow of each parametrized flow (the base jdf generated one which will be replaced with each specialization) + coutput(" const parsec_flow_t *base_flow_of_parametrized_flows[] = {\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" &flow_of_%s_%s_for_%s,\n", jdf_basename, f->fname, df->varname); + } + } + } + coutput(" NULL\n };\n"); + + coutput("\n"); + + + + coutput(" // Unroll all the parametrized flows\n"); + coutput(" for( int parametrized_flow_id=0; parametrized_flow_idflow_index + parametrized_iterator;\n" + " //char specialized_flow_name[64];\n" + //" //sprintf(specialized_flow_name, \"%s_%s_%%d\", parametrized_iterator); // modifying the name causes find_target_flow to fail!\n" + " //specialization_array_of_current_flow[parametrized_iterator].name = strdup(specialized_flow_name);\n" + "\n" + " // Keep the dep_index of each dep of each specialized flow\n" + " /*for( int j=0; jdep_index += parametrized_iterator;\n" + " dep->dep_datatype_index += parametrized_iterator;\n" + " }\n" + " for( int j=0; jdep_index += parametrized_iterator;\n" + " dep->dep_datatype_index += parametrized_iterator;\n" + " }\n" + " }*/\n" + ); + + coutput(" }\n"); + + coutput( + "\n" + ); + + + coutput( + " // Insert the new flows in the task class\n" + " for(int flow_in_out=0;flow_in_out<2;++flow_in_out) {\n" + " bool pivot_reached = false;\n" + " int parametrized_iterator = 0;\n" + " for(i = 0; i < MAX_DATAFLOWS_PER_TASK && parametrized_iterator < nb_specializations_of_current_flow; i++) {\n" + " parsec_flow_t *flow = (parsec_flow_t*)(flow_in_out?tc->out[i]:tc->in[i]);\n" + " if(!flow && !pivot_reached) {\n" + " break;\n" + " }\n" + " if(flow == base_flow_of_current_flow) {\n" + " pivot_reached = true;\n" + " /*// Update the goal of the task class\n" + " if(flow_in_out == 0)\n" + " {\n" + " // If is input, shift the proper values in the goal\n" + " // Idea: 00abcxyz -> abcccxyz (if shift=2 (i.e. nb_specializations=3) and pivot index = 3)\n" + " int shift = nb_specializations_of_current_flow-1;\n" + " parsec_dependency_t unshifted_values = tc->dependencies_goal & ((1<dependencies_goal >> (i + 1)) << (i + 1 + shift);\n" + " parsec_dependency_t in_between = ((1<<(shift+1))-1) << i;\n" + " tc->dependencies_goal = unshifted_values | shifted_values | in_between;\n" + " }*/\n" + " assert(i+nb_specializations_of_current_flow < MAX_DATAFLOWS_PER_TASK);\n" + " }\n" + " if(pivot_reached)\n" + " {\n" + " // Insert the new specialized flow\n" + " //(flow_in_out?tc->out:tc->in)[i] = &specialization_array_of_current_flow[base_flow_of_current_flow.flow_index+parametrized_iterator];\n" + " (flow_in_out?tc->out:tc->in)[i] = &specialization_array_of_current_flow[parametrized_iterator];\n" + " ++parametrized_iterator;\n" + " }\n" + " }\n" + " // assert(pivot_reached); // Actually, the pivot is not reached if READ/WRITE-only\n" + " }\n" + " // Update nb_flows\n" + " tc->nb_flows += nb_specializations_of_current_flow-1;\n" + ); + // coutput( + // // " // Update the mask of each flow\n" + // // " for(i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) {\n" + // // " parsec_flow_t *flow = tc->out[i];\n" + // // " if(!flow) {\n" + // // " break;\n" + // // " }\n" + // // " flow->flow_datatype_mask = 1 << flow->flow_index; // TODO verify (related to in/out)\n" + // // " }\n" + // " // Update nb_flows\n" + // " tc->nb_flows += nb_specializations_of_current_flow-1;\n" + // ); + + + coutput(" }\n"); + + coutput( + "#if defined(PARSEC_DEBUG_PARANOID)\n" + " // use parsec_debug_dump_task_class_at_exec(tc); on each task class\n" + " parsec_debug_verbose(2, parsec_debug_output, \"##\");\n" + " parsec_debug_verbose(2, parsec_debug_output, \"##\");\n" + " parsec_debug_verbose(2, parsec_debug_output, \"############ Task classes after unrolling parametrized flows ############\");\n" + " parsec_debug_verbose(2, parsec_debug_output, \"##\");\n" + " for( int i = 0; i < __parsec_tp->super.super.nb_task_classes; i++ ) {\n" + " parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[i];\n" + " parsec_debug_dump_task_class_at_exec(tc);\n" + " parsec_check_sanity_of_task_class(tc, false);\n" + " }\n" + "#endif\n" + ); + + /*for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" {\n"); + coutput(" // Parametrized flow %s of task class %s\n\n", df->varname, f->fname); + + coutput(" parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[%d];\n\n", f->task_class_id); + coutput( + " // Shift the flows that are after the parametrized flow\n" + " parsec_shift_all_flows_after(tc, &flow_of_%s_%s_for_%s, nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s-1);\n" + "\n", + jdf_basename, f->fname, df->varname, + jdf_basename, f->fname, df->varname + ); + coutput( + " // Unroll the parametrized flow to generate each specialized flow\n" + ); + + string_arena_init(sa); + dump_parametrized_flow_loop(df, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), " ", sa); + coutput("%s", string_arena_get_string(sa)); + + coutput( + " parsec_helper_copy_flow(&flow_of_%s_%s_for_parametrized_%s[%s], &flow_of_%s_%s_for_%s);\n" + " flow_of_%s_%s_for_parametrized_%s[%s].flow_index = flow_of_%s_%s_for_%s.flow_index + %s;\n" + " //char specialized_flow_name[64];\n" + " //sprintf(specialized_flow_name, \"%s_%s_%%d\", %s); // modifying the name causes find_target_flow to fail!\n" + " //flow_of_%s_%s_for_parametrized_%s[%s].name = strdup(specialized_flow_name);\n", + jdf_basename, f->fname, df->varname, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), + jdf_basename, f->fname, df->varname, + jdf_basename, f->fname, df->varname, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), jdf_basename, f->fname, df->varname, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), + df->varname, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), + jdf_basename, f->fname, df->varname, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df) + ); + + string_arena_init(sa); + dump_parametrized_flow_loop_end(df, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + coutput( + "\n" + ); + + + coutput( + " // Insert the new flows in the task class\n" + " for(int flow_in_out=0;flow_in_out<2;++flow_in_out) {\n" + " bool pivot_reached = false;\n" + " int %s = 0;\n" + " for(i = 0; i < MAX_DATAFLOWS_PER_TASK && %s < nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s; i++) {\n" + " parsec_flow_t *flow = (parsec_flow_t*)(flow_in_out?tc->out[i]:tc->in[i]);\n" + " if(!flow && !pivot_reached) {\n" + " break;\n" + " }\n" + " if(flow == &flow_of_%s_%s_for_%s) {\n" + " pivot_reached = true;\n" +// out_offset_flow_of_%s_%s_for_%s will be computed after all the shifts have been computed, just to be certain that no future shift will change the value +// " if(flow_in_out) {\n" +// " spec_%s.out_offset_flow_of_%s_%s_for_%s = i;\n" +// " }\n" + " // Update the goal of the task class\n" + " if(flow_in_out == 0)\n" + " {\n" + " // If is input, shift the proper values in the goal\n" + " // Idea: 00abcxyz -> abcccxyz (if shift=2 (i.e. nb_specializations=3) and pivot index = 3)\n" + " int shift = nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s-1;\n" + " parsec_dependency_t unshifted_values = tc->dependencies_goal & ((1<dependencies_goal >> (i + 1)) << (i + 1 + shift);\n" + " parsec_dependency_t in_between = ((1<<(shift+1))-1) << i;\n" + " tc->dependencies_goal = unshifted_values | shifted_values | in_between;\n" + " }\n" + " assert(i+nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s < MAX_DATAFLOWS_PER_TASK);\n" + " }\n" + " if(pivot_reached)\n" + " {\n" + " // Insert the new specialized flow\n" + " //(flow_in_out?tc->out:tc->in)[i] = &flow_of_%s_%s_for_parametrized_%s[flow_of_%s_%s_for_%s.flow_index+%s];\n" + " (flow_in_out?tc->out:tc->in)[i] = &flow_of_%s_%s_for_parametrized_%s[%s];\n" + " ++%s;\n" + " }\n" + " }\n" + " }\n", + GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), + GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), jdf_basename, f->fname, df->varname, + jdf_basename, f->fname, df->varname, + //JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, + jdf_basename, f->fname, df->varname, + jdf_basename, f->fname, df->varname, + jdf_basename, f->fname, df->varname, jdf_basename, f->fname, df->varname, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), + jdf_basename, f->fname, df->varname, GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df), + GET_PARAMETRIZED_FLOW_ITERATOR_NAME(df) + ); + coutput( + " // Update the mask of each flow\n" + // " for(i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) {\n" + // " parsec_flow_t *flow = tc->out[i];\n" + // " if(!flow) {\n" + // " break;\n" + // " }\n" + // " flow->flow_datatype_mask = 1 << flow->flow_index; // TODO verify (related to in/out)\n" + // " }\n" + " // Update nb_flows\n" + " tc->nb_flows += nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s-1;\n", + jdf_basename, f->fname, df->varname + ); + + coutput(" }\n"); + } + } + }*/ + + coutput("\n"); + + coutput(" // Unroll all the referrer's deps\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + depid=1; + for( jdf_dep_t *dep = df->deps; NULL != dep; dep = dep->next, depid++ ) { + for( int dep_in_out=0 ; dep_in_out < 2 ; dep_in_out++ ) { + if( (dep_in_out==0 && !(dep->dep_flags & JDF_DEP_FLOW_IN)) + || ((dep_in_out==1 && !(dep->dep_flags & JDF_DEP_FLOW_OUT))) ) { + // If the dep is not an input, skip dep_in_out=0, and if the dep is not an output, skip dep_in_out=1 + continue; + } + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + if( NULL != call->parametrized_offset ) + { + // Then the dep refers to a parametrized flow + + coutput(" {\n"); + coutput(" // %s of %s dep %d of flow %s of task class %s refers to a parametrized flow\n", + target_call?"callfalse":"calltrue", + dep_in_out?"output":"input", + dep->dep_index, df->varname, f->fname); + coutput("\n"); + + coutput(" parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[%d];\n\n", f->task_class_id); + coutput(" parsec_dep_t *dep = &%s_dep%d_atline_%d%s;\n", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + coutput(" int flow_in_out = %d;\n", dep_in_out); + + + // spec_%s_%s.offset_%s%s will be computed after all the shifts have been computed, just to be certain that no future shift will change the value + /* + coutput("\n"); + coutput(" spec_%s_%s.offset_%s%s = parsec_helper_get_dep_index(flow, dep, flow_in_out);\n", + jdf_basename, f->fname, JDF_OBJECT_ONAME(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "");*/ + + coutput("\n"); + + // Get iterator strings + string_arena_t *sa_it_name = string_arena_new(16); + string_arena_t *sa_it2_name = string_arena_new(16); // second iterator in case of referrer inside a parametrized flow + string_arena_add_string(sa_it_name, "%s", call->parametrized_offset->alias); + if(FLOW_IS_PARAMETRIZED(df)) + { + string_arena_add_string(sa_it2_name, "%s", df->local_variables->alias); + if(strcmp(string_arena_get_string(sa_it_name), string_arena_get_string(sa_it2_name)) == 0) { + string_arena_add_string(sa_it2_name, "_2"); // avoid name clash + } + } + + jdf_function_entry_t *targetf = find_target_function(jdf, call->func_or_mem); + jdf_dataflow_t *target_flow = find_target_flow(jdf, targetf, call->var); + assert(targetf && target_flow); + + //coutput(" parsec_update_dep_index_after_dep(tc, parsec_flow_t *flow, int dep_in_out, parsec_dep_t *pivot_dep, int shift)") + if(FLOW_IS_PARAMETRIZED(df) && FLOW_IS_PARAMETRIZED(target_flow)) + { + coutput(" parsec_update_dep_index_after_dep(tc, &flow_of_%s_%s_for_parametrized_%s[0], flow_in_out, dep, nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s-1);\n", + jdf_basename, f->fname, df->varname, jdf_basename, call->func_or_mem, call->var); + } + else + { + coutput(" parsec_update_dep_index_after_dep(tc, &flow_of_%s_%s_for_%s, flow_in_out, dep, nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s-1);\n", + jdf_basename, f->fname, df->varname, jdf_basename, call->func_or_mem, call->var); + } + + if(FLOW_IS_PARAMETRIZED(df)) + { + coutput(" for( int %s=0;%sfname, df->varname, + string_arena_get_string(sa_it2_name) + ); + } + + if(FLOW_IS_PARAMETRIZED(df) && FLOW_IS_PARAMETRIZED(target_flow)) + { + coutput("\n parsec_flow_t *flow = &flow_of_%s_%s_for_parametrized_%s[%s];\n", + jdf_basename, f->fname, df->varname, string_arena_get_string(sa_it2_name)); + } + else + { + coutput("\n parsec_flow_t *flow = &flow_of_%s_%s_for_%s;\n", + jdf_basename, f->fname, df->varname); + } + coutput(" int depid=parsec_helper_get_dep_index_in_flow(flow, dep, flow_in_out);\n"); + + coutput( + " // Shift the deps that are after dep (which references the parametrized flow)\n" + " parsec_shift_all_deps_after(tc, flow, dep, flow_in_out, nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s-1);\n\n", + jdf_basename, call->func_or_mem, call->var + ); + + coutput(" for( int %s=0;%sfunc_or_mem, call->var, + string_arena_get_string(sa_it_name) + ); + + if(!FLOW_IS_PARAMETRIZED(df)) + { + coutput( + " parsec_dep_t *dep_specialization = &%s_referrer_dep%d_atline_%d%s[%s];\n", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "", + string_arena_get_string(sa_it_name) + ); + } + else + { + coutput( + " parsec_dep_t *dep_specialization = &%s_referrer_dep%d_atline_%d%s[%s+%s*nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s];\n", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "", + string_arena_get_string(sa_it_name), string_arena_get_string(sa_it2_name), + jdf_basename, call->func_or_mem, call->var + ); + } + + coutput(" dep_specialization = parsec_helper_copy_dep(dep_specialization, dep);\n"); + + coutput( + " dep_specialization->flow = &flow_of_%s_%s_for_parametrized_%s[%s];\n", + jdf_basename, call->func_or_mem, call->var, string_arena_get_string(sa_it_name) + ); + coutput( + " dep_specialization->dep_index += %s;\n", + string_arena_get_string(sa_it_name) + ); + + // if(FLOW_IS_PARAMETRIZED(df)) + // { + // coutput( + // " dep_specialization->belongs_to = &flow_of_%s_%s_for_parametrized_%s[%s];\n", + // jdf_basename, f->fname, df->varname, string_arena_get_string(sa_it2_name) + // ); + // } + coutput( + " dep_specialization->belongs_to = flow;\n" + ); + + coutput( + " (flow_in_out?flow->dep_out:flow->dep_in)[depid+%s] = dep_specialization;\n", + string_arena_get_string(sa_it_name) + ); + + + coutput( + " assert(depid+%s < %s);\n", + string_arena_get_string(sa_it_name), + (dep_in_out)?"MAX_DEP_OUT_COUNT":"MAX_DEP_IN_COUNT" + ); + + if(FLOW_IS_PARAMETRIZED(df)) + { + coutput(" }\n"); + } + coutput(" }\n"); + coutput(" }\n"); + + string_arena_free(sa_it_name); + string_arena_free(sa_it2_name); + + + // coutput( + // " parsec_dep_t *new_dep = parsec_helper_copy_dep(dep);\n" + // " assert(NULL != new_dep);\n" + // " new_dep->flow = &flow_of_%s_%s_for_parametrized_%s[%s];\n" + // " //new_dep->cond = target_expr_cond; // TODO !\n" + // " // new_dep->ctl_gather_nb = ; // TODO\n" + // " new_dep->dep_index += %s;\n" + // " //new_dep->dep_datatype_index += cd; // TODO maybe modify?\n" + // " //assert(new_dep->direct_data != NULL);\n" + // " // Insert the new dep\n" + // " (flow_in_out?flow->dep_out:flow->dep_in)[depid+cd] = new_dep;\n", + // jdf_basename, call->func_or_mem, call->var, call->parametrized_offset->alias, + // call->parametrized_offset->alias + //); + } + } + } + } + } + } + + coutput("\n"); + + coutput( + "#if defined(PARSEC_DEBUG_PARANOID)\n" + " // use parsec_debug_dump_task_class_at_exec(tc); on each task class\n" + " parsec_debug_verbose(2, parsec_debug_output, \"##\");\n" + " parsec_debug_verbose(2, parsec_debug_output, \"##\");\n" + " parsec_debug_verbose(2, parsec_debug_output, \"############ Task classes after unrolling referrers ############\");\n" + " parsec_debug_verbose(2, parsec_debug_output, \"##\");\n" + " for( int i = 0; i < __parsec_tp->super.super.nb_task_classes; i++ ) {\n" + " parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[i];\n" + " parsec_debug_dump_task_class_at_exec(tc);\n" + " parsec_check_sanity_of_task_class(tc, false);\n" + " }\n" + "#endif\n" + ); + + + coutput(" // at this point, all the parametrized flows have been created, but the structure can have some incoherencies:\n"); + coutput(" // - when a parametrized flow is unrolled, the deps are not copied in memory\n"); + coutput(" // - the dep_index is not correct (there can be duplicates in a task class)\n"); + coutput(" // - the goal masks are not correct (dependencies_goal and flow_datatype_mask)\n"); + coutput(" // The next block of code will fix these issues\n"); + coutput(" {\n"); + + + coutput(" // First, ensure that there is no duplicate pointer\n"); + coutput("//#if defined(PARSEC_DEBUG_PARANOID) // This is not paranoid at all\n"); + coutput(" for(int tcid = 0; tcid < __parsec_tp->super.super.nb_task_classes; tcid++) {\n"); + coutput(" parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[tcid];\n"); + coutput(" parsec_dep_t *found_deps[MAX_DEP_IN_COUNT*MAX_DATAFLOWS_PER_TASK];\n"); + coutput(" int found_deps_count = 0; // unique found INPUT deps\n"); + coutput(" for(int flow_id = 0; flow_id < tc->nb_flows && flow_id < MAX_DATAFLOWS_PER_TASK; flow_id++) {\n"); + coutput(" parsec_flow_t *flow = tc->in[flow_id];\n"); + coutput(" if(NULL == flow) break;\n"); + coutput(" for(int depid = 0; depid < MAX_DEP_IN_COUNT; depid++) {\n"); + coutput(" parsec_dep_t *dep = flow->dep_in[depid];\n"); + coutput(" if(NULL == dep) break;\n"); + coutput(" if(parsec_helper_dep_is_in_flow_array(dep, found_deps, found_deps_count)) {\n"); + coutput(" // duplicate: create a new dep and copy the content\n"); + coutput(" dep = parsec_helper_copy_dep(malloc(sizeof(parsec_dep_t)), dep);\n"); + coutput(" flow->dep_in[depid] = dep;\n"); + coutput(" }\n"); + coutput(" assert(found_deps_count < MAX_DEP_IN_COUNT*MAX_DATAFLOWS_PER_TASK);\n"); + coutput(" found_deps[found_deps_count++] = dep;\n"); + coutput(" }\n"); + coutput(" }\n"); + coutput(" found_deps_count = 0; // unique found OUTPUT deps\n"); + coutput(" for(int flow_id = 0; flow_id < tc->nb_flows && flow_id < MAX_DATAFLOWS_PER_TASK; flow_id++) {\n"); + coutput(" parsec_flow_t *flow = tc->out[flow_id];\n"); + coutput(" if(NULL == flow) break;\n"); + coutput(" for(int depid = 0; depid < MAX_DEP_OUT_COUNT; depid++) {\n"); + coutput(" parsec_dep_t *dep = flow->dep_out[depid];\n"); + coutput(" if(NULL == dep) break;\n"); + coutput(" if(parsec_helper_dep_is_in_flow_array(dep, found_deps, found_deps_count)) {\n"); + coutput(" // duplicate: create a new dep and copy the content\n"); + coutput(" dep = parsec_helper_copy_dep(malloc(sizeof(parsec_dep_t)), dep);\n"); + coutput(" flow->dep_out[depid] = dep;\n"); + coutput(" }\n"); + coutput(" assert(found_deps_count < MAX_DEP_OUT_COUNT*MAX_DATAFLOWS_PER_TASK);\n"); + coutput(" found_deps[found_deps_count++] = dep;\n"); + coutput(" }\n"); + coutput(" }\n"); + coutput(" }\n"); + coutput("//#endif\n"); + + coutput("\n"); + + + coutput(" // Second, fix the dep_indexes\n"); + coutput(" // We want to make sure that the dep_indexes are unique per task class, except for the ternaries where duplicates are mandatory\n"); + coutput(" // The idea of the algorithm is to compute the proper lifting for each flow (i.e.: current_max_dep_id_task_class - current_min_dep_id_flow)\n"); + coutput(" for(int in_out = 0; in_out < 2; in_out++) {\n"); + coutput(" for(int tcid = 0; tcid < __parsec_tp->super.super.nb_task_classes; tcid++) {\n"); + coutput(" parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[tcid];\n"); + coutput(" int current_max_dep_id_task_class = 0; // Max dep_id of this task class\n"); + coutput(" for(int flow_id = 0; flow_id < tc->nb_flows && flow_id < MAX_DATAFLOWS_PER_TASK; flow_id++) {\n"); + coutput(" parsec_flow_t *flow = (in_out?tc->out:tc->in)[flow_id];\n"); + coutput(" if(NULL == flow) break;\n"); + coutput(" if(in_out == 1)\n"); + coutput(" flow->flow_datatype_mask = 0;\n"); + coutput(" // We look for the min and max, because we need them to compute the exact lifting\n"); + coutput(" int current_min_dep_id_flow = INT_MAX; // Min dep_id of this flow\n"); + coutput(" int current_max_dep_id_flow = 0; // Max dep_id of this flow\n\n"); + coutput(" if(NULL == flow) break;\n"); + coutput(" // First compute the max dep_id of this flow\n"); + coutput(" for(int depid = 0; depid < (in_out?MAX_DEP_OUT_COUNT:MAX_DEP_IN_COUNT); depid++) {\n"); + coutput(" parsec_dep_t *dep = (in_out?flow->dep_out:flow->dep_in)[depid];\n"); + coutput(" if(NULL == dep) break;\n"); + coutput(" int current_dep_index = dep->dep_index;\n"); + coutput(" if(current_dep_index > current_max_dep_id_flow) {\n"); + coutput(" current_max_dep_id_flow = current_dep_index;\n"); + coutput(" }\n"); + coutput(" if(current_dep_index < current_min_dep_id_flow) {\n"); + coutput(" current_min_dep_id_flow = current_dep_index;\n"); + coutput(" }\n"); + coutput(" }\n"); + coutput(" // Secondly, increase each dep_id of this flow by current_max_dep_id_task_class+1\n"); + coutput(" for(int depid = 0; depid < (in_out?MAX_DEP_OUT_COUNT:MAX_DEP_IN_COUNT); depid++) {\n"); + coutput(" parsec_dep_t *dep = (in_out?flow->dep_out:flow->dep_in)[depid];\n"); + coutput(" if(NULL == dep) break;\n"); + coutput(" dep->dep_index += current_max_dep_id_task_class - current_min_dep_id_flow;\n"); + coutput(" dep->dep_datatype_index += current_max_dep_id_task_class - current_min_dep_id_flow;\n"); + coutput("#if defined(PARSEC_DEBUG_PARANOID)\n"); + coutput(" assert(dep->dep_index >= 0);\n"); + coutput(" assert(dep->dep_datatype_index >= 0);\n"); + coutput(" assert(dep->dep_index < (in_out?MAX_DEP_OUT_COUNT:MAX_DEP_IN_COUNT));\n"); + coutput(" assert(dep->dep_datatype_index < (in_out?MAX_DEP_OUT_COUNT:MAX_DEP_IN_COUNT));\n"); + coutput("#endif\n"); + coutput(" if(in_out==1)\n"); + coutput(" flow->flow_datatype_mask |= 1<dep_index; // keep the flow_datatype_mask up-to-date\n"); + coutput(" }\n"); + coutput(" current_max_dep_id_task_class += current_max_dep_id_flow-current_min_dep_id_flow+1;\n"); + coutput(" }\n"); + coutput(" }\n"); + coutput(" }\n"); + + + //coutput(" for(int tcid = 0; tcid < __parsec_tp->super.super.nb_task_classes; tcid++) {\n"); + + coutput(" }\n"); + + + coutput("\n"); + coutput(" // Set dependencies_goal to zero for task classes that have parametrized flows\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) + { + if( TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) + { + coutput(" { // %s\n", f->fname); + coutput(" parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[%d];\n\n", f->task_class_id); + coutput(" tc->dependencies_goal = 0;\n"); + coutput(" }\n"); + } + } + coutput("\n"); + + + coutput(" // Finally, retrieve the correct indices for the parametrized flows and the referrers\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) + { + coutput(" { // task class %s\n", f->fname); + coutput(" parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[%d];\n\n", f->task_class_id); + + coutput(" int current_data_offset_for_%s_%s = 0;\n", jdf_basename, f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + coutput(" { // Parametrized flow %s of task class %s\n", df->varname, f->fname); + //coutput(" parsec_task_class_t *tc = &parsec_%s_%s;\n", jdf_basename, f->fname); + //coutput(" parsec_flow_t *flow = &flow_of_%s_%s_for_parametrized_%s[0];\n", jdf_basename, f->fname, df->varname); + //coutput(" spec_%s.out_offset_flow_of_%s_%s_for_%s = parsec_helper_get_flow_index_that_contains_dep(parsec_task_class_t *tc, parsec_dep_t *dep, int in_out);\n" + // JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname,); + + coutput("//#if defined(PARSEC_DEBUG_NOISIER) // used in release mode too now\n"); + coutput(" spec_%s.nb_specializations_of_parametrized_flow_of_%s_%s_for_%s = nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s;\n", + JDF_OBJECT_ONAME(f), + jdf_basename, f->fname, df->varname, + jdf_basename, f->fname, df->varname); + coutput("//#endif\n"); + + if(df->flow_flags & JDF_FLOW_TYPE_READ) + { + coutput(" spec_%s.in_flow_offset_of_parametrized_flow_of_%s_%s_for_%s = parsec_helper_get_flow_index(tc, &flow_of_%s_%s_for_parametrized_%s[0], 0);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, jdf_basename, f->fname, df->varname); + coutput(" assert(spec_%s.in_flow_offset_of_parametrized_flow_of_%s_%s_for_%s >= 0);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + } + if(df->flow_flags & JDF_FLOW_TYPE_WRITE) + { + coutput(" spec_%s.out_flow_offset_of_parametrized_flow_of_%s_%s_for_%s = parsec_helper_get_flow_index(tc, &flow_of_%s_%s_for_parametrized_%s[0], 1);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, jdf_basename, f->fname, df->varname); + coutput(" assert(spec_%s.out_flow_offset_of_parametrized_flow_of_%s_%s_for_%s >= 0);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + } + coutput("\n"); + + coutput(" spec_%s.data_dynamic_offset_of_parametrized_%s_%s_for_%s = current_data_offset_for_%s_%s;\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, jdf_basename, f->fname); + coutput(" current_data_offset_for_%s_%s += nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s;\n", + jdf_basename, f->fname, jdf_basename, f->fname, df->varname); + coutput("\n"); + + + depid=1; + for(jdf_dep_t *dep=df->deps; NULL != dep; dep = dep->next, ++depid) { + if((dep->dep_flags & JDF_DEP_FLOW_OUT) == 0) + { // We only need the out indices + continue; + } + + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + /*coutput(" spec_%s.out_flow_offset_of_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = parsec_helper_get_flow_index(tc, &flow_of_%s_%s_for_%s, 1);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "", + jdf_basename, f->fname, df->varname);*/ + + jdf_function_entry_t *targetf = find_target_function(jdf, call->func_or_mem); + jdf_dataflow_t *target_flow = find_target_flow(jdf, targetf, call->var); + if(!FLOW_IS_PARAMETRIZED(target_flow)) + { // Referrer to a non-parametrized flow + coutput(" spec_%s.out_dep_offset_of%s%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = parsec_helper_get_dep_index(tc, &flow_of_%s_%s_for_%s_dep%d_atline_%d%s, 1);\n", + JDF_OBJECT_ONAME(f), + call->parametrized_offset != NULL?"_referrer":"", FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", + jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "", + jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + } + else + { // Referrer to a parametrized flow + coutput(" spec_%s.out_dep_offset_of%s%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = " + "parsec_helper_get_dep_index(tc, &%s_referrer_dep%d_atline_%d%s[0], 1);\n", + JDF_OBJECT_ONAME(f), + call->parametrized_offset != NULL?"_referrer":"", FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", + jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "" + ); + } + + /*coutput(" spec_%s.out_dep_offset_of_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = ;\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "");*/ + } + } + + coutput("\n"); + + // Now output asserts: + + coutput("#if defined(PARSEC_DEBUG_NOISIER)\n"); + coutput(" assert(spec_%s.nb_specializations_of_parametrized_flow_of_%s_%s_for_%s >= 0);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + coutput("#endif\n"); + if(df->flow_flags & JDF_FLOW_TYPE_READ) + coutput(" assert(spec_%s.in_flow_offset_of_parametrized_flow_of_%s_%s_for_%s >= 0);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + if(df->flow_flags & JDF_FLOW_TYPE_WRITE) + coutput(" assert(spec_%s.out_flow_offset_of_parametrized_flow_of_%s_%s_for_%s >= 0);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + coutput(" assert(spec_%s.data_dynamic_offset_of_parametrized_%s_%s_for_%s >= 0);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + + coutput("\n"); + + // For each dep of a parametrized flow: + depid=1; + for(jdf_dep_t *dep=df->deps; NULL != dep; dep = dep->next, ++depid) { + if((dep->dep_flags & JDF_DEP_FLOW_OUT) == 0) + { // We only need the out indices + continue; + } + + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + /*coutput(" assert(spec_%s.out_flow_offset_of_flow_of_%s_%s_for_%s_dep%d_atline_%d%s >= 0);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : "");*/ + coutput(" assert(spec_%s.out_dep_offset_of%s%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s >= 0);\n", + JDF_OBJECT_ONAME(f), + call->parametrized_offset != NULL?"_referrer":"", FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", + jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + } + } + + //if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) // We already know that the flow is parametrized + { + coutput(" // dynamic flow id of flow %s of task class %s\n", df->varname, f->fname); + + coutput(" spec_%s.flow_id_of_flow_of_%s_%s_for_%s = parsec_helper_get_flow_index_in_or_out(tc, &flow_of_%s_%s_for_parametrized_%s[0]);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, + jdf_basename, f->fname, df->varname); + + coutput(" assert(spec_%s.flow_id_of_flow_of_%s_%s_for_%s >= 0); // nonesense because uint\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + } + + coutput(" }\n"); + } + else// if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) // we already know that TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED + { + coutput(" { // flow %s of task class %s\n", df->varname, f->fname); + + coutput(" // dynamic flow id of flow %s of task class %s\n", df->varname, f->fname); + + coutput(" spec_%s.flow_id_of_flow_of_%s_%s_for_%s = parsec_helper_get_flow_index_in_or_out(tc, &flow_of_%s_%s_for_%s);\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname, + jdf_basename, f->fname, df->varname); + + coutput(" // assert(spec_%s.flow_id_of_flow_of_%s_%s_for_%s >= 0); // nonesense because uint\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + + coutput(" }\n"); + } + } + coutput(" }\n"); + } + } + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + depid=1; + for( jdf_dep_t *dep = df->deps; NULL != dep; dep = dep->next, depid++ ) { + if((dep->dep_flags & JDF_DEP_FLOW_OUT) == 0) + { // We only need the out indices + continue; + } + + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + if( NULL != call->parametrized_offset ) + { + coutput(" { // Parametrized referrer %s of task class %s\n", df->varname, f->fname); + coutput(" parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[%d];\n", f->task_class_id); + + + jdf_function_entry_t *targetf = find_target_function(jdf, call->func_or_mem); + jdf_dataflow_t *target_flow = find_target_flow(jdf, targetf, call->var); + assert(targetf && target_flow); + if(FLOW_IS_PARAMETRIZED(df) && !FLOW_IS_PARAMETRIZED(target_flow)) + { + coutput(" parsec_dep_t *dep = &flow_of_%s_%s_for_%s_dep%d_atline_%d%s;\n\n", + jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + } + else + { + coutput(" parsec_dep_t *dep = &%s_referrer_dep%d_atline_%d%s[0];\n\n", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + } + /*if(FLOW_IS_PARAMETRIZED(df)) + { + coutput(" parsec_dep_t *dep = %s_referrer_dep%d_atline_%d%s;\n\n", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + } + else + { + coutput(" parsec_dep_t *dep = %s_referrer_dep%d_atline_%d%s;\n\n", + JDF_OBJECT_ONAME(df), depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + }*/ + + //assert(!FLOW_IS_PARAMETRIZED(df)); // If the flow is parametrized, // Commenting this because a referrer can be parametrized as well?? + + coutput(" spec_%s.out_dep_offset_of_referrer%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = parsec_helper_get_dep_index(tc, dep, 1);\n", + JDF_OBJECT_ONAME(f), FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + coutput(" spec_%s.out_flow_offset_of_referrer%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s = parsec_helper_get_flow_index_that_contains_dep(tc, dep, 1);\n", + JDF_OBJECT_ONAME(f), FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + + coutput("\n"); + coutput(" assert(spec_%s.out_dep_offset_of_referrer%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s >= 0);\n", + JDF_OBJECT_ONAME(f), FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + coutput(" assert(spec_%s.out_flow_offset_of_referrer%s_flow_of_%s_%s_for_%s_dep%d_atline_%d%s >= 0);\n", + JDF_OBJECT_ONAME(f), FLOW_IS_PARAMETRIZED(df)?"_parametrized":"", jdf_basename, f->fname, df->varname, + depid, JDF_OBJECT_LINENO(dep), + // If ternary, add _iftrue or _iffalse + (dep->guard->guard_type==JDF_GUARD_TERNARY) ? ((target_call)?"_iffalse":"_iftrue") : ""); + coutput(" }\n"); + } + } + } + } + } + + // Apparently it's not output dep_index that needs a mask, but the input flow + coutput(" // Update masks for task classes that need them\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + if( TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(f)) { + coutput(" { // task class %s\n", f->fname); + + coutput(" // spec_%s.dep_mask_out_of_flow_of_%s_%s = 0; // should already be set to 0\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname); + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + coutput(" { // Flow %s of task class %s\n", df->varname, f->fname); + + if(FLOW_IS_PARAMETRIZED(df)) + { + // get the first parametrized specialization + coutput(" parsec_flow_t *flow = &flow_of_%s_%s_for_parametrized_%s[0];\n", + jdf_basename, f->fname, df->varname); + coutput(" int specializations_number = nb_specializations_of_parametrized_flow_of_%s_%s_for_parametrized_%s;\n", + jdf_basename, f->fname, df->varname); + /*coutput(" spec_%s.dep_mask_out_of_flow_of_%s_%s_for_%s = ((1<<(specializations_number))-1)<flow_index;\n", + JDF_OBJECT_ONAME(f), + jdf_basename, f->fname, df->varname);*/ + } + else + { + coutput(" parsec_flow_t *flow = &flow_of_%s_%s_for_%s;\n", + jdf_basename, f->fname, df->varname); + + } + + coutput(" for(int idep=0;idepdep_out[idep];\n"); + coutput(" if(NULL == dep) break;\n"); + coutput(" spec_%s.dep_mask_out_of_flow_of_%s_%s_for_%s |= 1<dep_index;\n", + JDF_OBJECT_ONAME(f), + jdf_basename, f->fname, df->varname); + coutput(" }\n"); + + coutput(" //spec_%s.dep_mask_out_of_flow_of_%s_%s_for_%s = flow->flow_datatype_mask;\n", + JDF_OBJECT_ONAME(f), + jdf_basename, f->fname, df->varname); + + + coutput(" spec_%s.dep_mask_out_of_flow_of_%s_%s |= spec_%s.dep_mask_out_of_flow_of_%s_%s_for_%s;\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + coutput(" //flow->flow_datatype_mask = spec_%s.dep_mask_out_of_flow_of_%s_%s_for_%s;\n", + JDF_OBJECT_ONAME(f), jdf_basename, f->fname, df->varname); + coutput(" }\n"); + } + coutput(" }\n"); + } + } + + coutput("\n"); + coutput(" // Update dependencies_goal for task classes that need them\n"); + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + if( TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) { + coutput(" { // task class %s\n", f->fname); + coutput(" parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[%d];\n", f->task_class_id); + coutput(" for(int i=0; iin[i];\n"); + coutput(" if( NULL == flow ) break;\n"); + coutput(" tc->dependencies_goal |= 1<flow_index;\n"); + coutput(" }\n"); + coutput(" }\n"); + } + } + + coutput("\n"); + + coutput( + "#if defined(PARSEC_DEBUG_PARANOID)\n" + " // use parsec_debug_dump_task_class_at_exec(tc); on each task class\n" + " parsec_debug_verbose(2, parsec_debug_output, \"##\");\n" + " parsec_debug_verbose(2, parsec_debug_output, \"##\");\n" + " parsec_debug_verbose(2, parsec_debug_output, \"############ Task classes after update ############\");\n" + " parsec_debug_verbose(2, parsec_debug_output, \"##\");\n" + " for( int i = 0; i < __parsec_tp->super.super.nb_task_classes; i++ ) {\n" + " parsec_task_class_t *tc = __parsec_tp->super.super.task_classes_array[i];\n" + " parsec_debug_dump_task_class_at_exec(tc);\n" + " parsec_check_sanity_of_task_class(tc, true);\n" + " }\n" + "#endif\n" + ); + + coutput("\n"); + } + coutput("\n"); + + for(jdf_function_entry_t *f = jdf->functions; f != NULL; f = f->next) { coutput(" PARSEC_AYU_REGISTER_TASK(&%s_%s);\n", jdf_basename, f->fname); @@ -4860,6 +7003,15 @@ static void jdf_generate_hashfunction_for(const jdf_t *jdf, const jdf_function_e idx++; } + // rubish + // if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) { + // for(int ldef_index=0;ldef_indexnb_max_local_def;++ldef_index) { + // coutput(" const int ldef_%d = assignment->ldef[%d].value;\n", + // ldef_index, ldef_index); + // coutput(" assert( ldef_%d >= 0 );\n", ldef_index); + // } + // } + string_arena_init(sa_range_multiplier); for(vl = f->locals; vl != NULL; vl = vl->next) { if( local_is_parameter(f, vl) != NULL ) { @@ -4868,6 +7020,15 @@ static void jdf_generate_hashfunction_for(const jdf_t *jdf, const jdf_function_e } } + // rubish + // // TODO verify that this is optimized away when not needed + // if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) { + // for(int ldef_index=0;ldef_indexnb_max_local_def;++ldef_index) { + // coutput(" __parsec_id += ldef_%d%s;\n", ldef_index, string_arena_get_string(sa_range_multiplier)); + // string_arena_add_string(sa_range_multiplier, " * %d", MAX_DATAFLOWS_PER_TASK); // TODO get the true range, MAX_DATAFLOWS_PER_TASK is the maximum possible + // } + // } + coutput(" (void)__parsec_tp;\n" " return (parsec_key_t)__parsec_id;\n" "}\n"); @@ -4915,25 +7076,25 @@ char *malloc_and_dump_jdf_expr_list(const jdf_expr_t *el) /** Code Generators */ static char *jdf_create_code_assignments_calls(string_arena_t *sa, int spaces, - const jdf_t *jdf, const char *name, const jdf_call_t *call) + const jdf_t *jdf, const char *name, const jdf_call_t *source_call) { const jdf_expr_t *el; expr_info_t infodst = EMPTY_EXPR_INFO, infosrc = EMPTY_EXPR_INFO; string_arena_t *sa2; - jdf_expr_t *params = call->parameters; + jdf_expr_t *params = source_call->parameters; jdf_variable_list_t *vl; jdf_param_list_t *pl; - const jdf_function_entry_t *f; + const jdf_function_entry_t *targetf; - f = find_target_function(jdf, call->func_or_mem); + targetf = find_target_function(jdf, source_call->func_or_mem); - assert(f != NULL); + assert(targetf != NULL); string_arena_init(sa); sa2 = string_arena_new(64); infodst.sa = sa2; - infodst.prefix = f->fname; + infodst.prefix = targetf->fname; infodst.suffix = ""; infodst.assignments = (char*)name; infosrc.sa = sa2; @@ -4941,10 +7102,10 @@ static char *jdf_create_code_assignments_calls(string_arena_t *sa, int spaces, infosrc.suffix = ""; infosrc.assignments = "&this_task->locals"; - for(vl = f->locals; vl != NULL; vl = vl->next) { + for(vl = targetf->locals; vl != NULL; vl = vl->next) { /* Is this definition a parameter or a value? */ /* If it is a parameter, find the corresponding param in the call */ - for(el = params, pl = f->parameters; pl != NULL; el = el->next, pl = pl->next) { + for(el = params, pl = targetf->parameters; pl != NULL; el = el->next, pl = pl->next) { if( NULL == el ) { /* Badly formulated call */ string_arena_t *sa_caller, *sa_callee; expr_info_t caller = EMPTY_EXPR_INFO; @@ -4958,7 +7119,7 @@ static char *jdf_create_code_assignments_calls(string_arena_t *sa, int spaces, caller.assignments = ""; string_arena_init(sa); - UTIL_DUMP_LIST_FIELD(sa_callee, f->parameters, next, name, + UTIL_DUMP_LIST_FIELD(sa_callee, targetf->parameters, next, name, dump_string, sa, "(", "", ", ", ")"); string_arena_init(sa); @@ -4966,14 +7127,14 @@ static char *jdf_create_code_assignments_calls(string_arena_t *sa, int spaces, dump_expr, (void*)&caller, "(", "", ", ", ")"); fprintf(stderr, "%s.jdf:%d Badly formulated call %s%s instead of %s%s\n", - jdf_basename, call->super.lineno, - f->fname, string_arena_get_string(sa_caller), - f->fname, string_arena_get_string(sa_callee)); + jdf_basename, source_call->super.lineno, + targetf->fname, string_arena_get_string(sa_caller), + targetf->fname, string_arena_get_string(sa_callee)); exit(-1); } assert( el != NULL ); if(!strcmp(pl->name, vl->name)) - break; + break; } string_arena_init(sa2); /** @@ -4983,17 +7144,18 @@ static char *jdf_create_code_assignments_calls(string_arena_t *sa, int spaces, * assignment context, including target locals, or the usage of %inline * will be broken. */ + //name_to_dump = (char*)vl->name; if( NULL == pl ) { /* It is a value. Let's dump it's expression in the destination context */ string_arena_add_string(sa, "%sconst int %s%s = %s->%s.value = %s; (void)%s%s;\n", - indent(spaces), f->fname, vl->name, name, vl->name, dump_expr((void**)vl->expr, &infodst), f->fname, vl->name); + indent(spaces), targetf->fname, vl->name, name, vl->name, dump_expr((void**)vl->expr, &infodst), targetf->fname, vl->name); } else { /* It is a parameter. Let's dump it's expression in the source context */ assert(el != NULL); string_arena_add_string(sa, "%sconst int %s%s = %s->%s.value = %s; (void)%s%s;\n", - indent(spaces), f->fname, vl->name, name, vl->name, dump_expr((void**)el, &infosrc), f->fname, vl->name); + indent(spaces), targetf->fname, vl->name, name, vl->name, dump_expr((void**)el, &infosrc), targetf->fname, vl->name); } } @@ -5229,15 +7391,28 @@ jdf_generate_code_reshape_input_from_desc(const jdf_t *jdf, ".", "local", 1); coutput("%s %s", spaces, string_arena_get_string(sa_datatype)); + // Get the flow id as a string + string_arena_t *sa_flow_index = string_arena_new(128); + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) + { + DUMP_FLOW_ID_VARIABLE(sa_flow_index, jdf_basename, f, flow); + } + else + { + string_arena_add_string(sa_flow_index, "%d", flow->flow_index); + } + /*INLINE RESHAPING WHEN READING FROM MATRIX NEW COPY EACH THREAD*/ coutput("%s data.data_future = NULL;\n", spaces); - coutput("%s if( (ret = parsec_get_copy_reshape_from_desc(es, this_task->taskpool, (parsec_task_t *)this_task, %d, reshape_repo, reshape_entry_key, &data, &chunk)) < 0){\n" + coutput("%s if( (ret = parsec_get_copy_reshape_from_desc(es, this_task->taskpool, (parsec_task_t *)this_task, %s, reshape_repo, reshape_entry_key, &data, &chunk)) < 0){\n" "%s return ret;\n" "%s }\n", - spaces, flow->flow_index, + spaces, string_arena_get_string(sa_flow_index),//flow->flow_index, spaces, spaces); + string_arena_free(sa_flow_index); + string_arena_free(sa); string_arena_free(sa2); @@ -5315,6 +7490,7 @@ jdf_generate_code_reshape_input_from_dep(const jdf_t *jdf, * Format: type = XX type_remote = ... -> pack XX unpack XX * */ coutput("%s data.data = NULL;\n", spaces); + coutput("%s assert(consumed_entry);\n", spaces); coutput("%s data.data_future = (parsec_datacopy_future_t*)consumed_entry->data[consumed_flow_index];\n", spaces); @@ -5377,12 +7553,25 @@ jdf_generate_code_reshape_input_from_dep(const jdf_t *jdf, ".", "local", 1); coutput("%s %s", spaces, string_arena_get_string(sa_datatype)); - coutput("%s if( (ret = parsec_get_copy_reshape_from_dep(es, this_task->taskpool, (parsec_task_t *)this_task, %d, reshape_repo, reshape_entry_key, &data, &chunk)) < 0){\n" + // Get the flow id as a string + string_arena_t *sa_flow_index = string_arena_new(128); + if(FLOW_IS_PARAMETRIZED(flow)) + { + DUMP_FLOW_ID_VARIABLE(sa_flow_index, jdf_basename, f, flow); + } + else + { + string_arena_add_string(sa_flow_index, "%d", flow->flow_index); + } + + coutput("%s if( (ret = parsec_get_copy_reshape_from_dep(es, this_task->taskpool, (parsec_task_t *)this_task, %s, reshape_repo, reshape_entry_key, &data, &chunk)) < 0){\n" "%s return ret;\n" "%s }\n", - spaces, flow->flow_index, + spaces, string_arena_get_string(sa_flow_index), //flow->flow_index, spaces, spaces); + + string_arena_free(sa_flow_index); string_arena_free(sa); string_arena_free(sa2); @@ -5411,62 +7600,112 @@ jdf_generate_code_consume_predecessor_setup(const jdf_t *jdf, const jdf_call_t * (void)pred_var; /*final_check = case predecessor has set up stuff on our data */ + expr_info_t expr_info = EMPTY_EXPR_INFO; + + string_arena_t *osa = string_arena_new(64); + string_arena_t *sa_consumed_flow_index = string_arena_new(256); + string_arena_t *sa_pred_consumed_flow_index = string_arena_new(256); + string_arena_init(osa); + string_arena_init(sa_consumed_flow_index); + string_arena_init(sa_pred_consumed_flow_index); + + + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(pred_f)) + { + DUMP_FLOW_ID_VARIABLE(sa_pred_consumed_flow_index, jdf_basename, pred_f, pred_flow); + } + else + { + string_arena_add_string(sa_pred_consumed_flow_index, "%d", pred_flow->flow_index); + } + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) + { + DUMP_FLOW_ID_VARIABLE(sa_consumed_flow_index, jdf_basename, f, flow); + } + else + { + string_arena_add_string(sa_consumed_flow_index, "%d", flow->flow_index); + } + +// if(FLOW_IS_PARAMETRIZED(f_pred)) +// { // If the target is parametrized, we need to set the flow index according to the expression +// for(jdf_variable_list_t *vl = pred_f->locals; vl != NULL; vl = vl->next) { +// coutput("#define %s %s%s\n", vl->name, pred_f->fname, vl->name); +// } +// #error remove // TODO +// coutput("%s %s = %s;\n", +// spaces, pred_f->local_defs->alias, +// dump_expr((void**)pred_f->parametrized_offset, &expr_info)); +// } + if( final_check ){ - coutput("%s consumed_repo = this_task->data._f_%s.source_repo;\n" - "%s consumed_entry = this_task->data._f_%s.source_repo_entry;\n" - "%s consumed_entry_key = this_task->data._f_%s.source_repo_entry->ht_item.key;\n", - spaces, flow->varname, - spaces, flow->varname, - spaces, flow->varname); + coutput("%s consumed_repo = this_task->data.%s.source_repo;\n" + "%s consumed_entry = this_task->data.%s.source_repo_entry;\n" + "%s consumed_entry_key = this_task->data.%s.source_repo_entry->ht_item.key;\n", + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow)); /* Is this current task repo or predecessor repo? Different flow index */ - coutput("%s if( (reshape_entry != NULL) && (reshape_entry->data[%d] != NULL) ){\n" + coutput("%s if( (reshape_entry != NULL) && (reshape_entry->data[%s] != NULL) ){\n" "%s /* Reshape promise set up on input by predecessor is on this task repo */\n" - "%s consumed_flow_index = %d;\n", - spaces, flow->flow_index, + "%s consumed_flow_index = %s;\n", + spaces, string_arena_get_string(sa_consumed_flow_index), spaces, - spaces, flow->flow_index); - coutput("%s assert( (this_task->data._f_%s.source_repo == reshape_repo)\n" - "%s && (this_task->data._f_%s.source_repo_entry == reshape_entry));\n", - spaces, flow->varname, - spaces, flow->varname); + spaces, string_arena_get_string(sa_consumed_flow_index)); + coutput("%s assert( (this_task->data.%s.source_repo == reshape_repo)\n" + "%s && (this_task->data.%s.source_repo_entry == reshape_entry));\n", + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow)); coutput("%s }else{\n" "%s /* Reshape promise set up on input by predecessor is the predecesssor task repo */\n" - "%s consumed_flow_index = %d;\n" + "%s consumed_flow_index = %s;\n" "%s }\n", spaces, spaces, - spaces, pred_flow->flow_index, + spaces, string_arena_get_string(sa_pred_consumed_flow_index), spaces); }else{ - coutput("%s if( (reshape_entry != NULL) && (reshape_entry->data[%d] != NULL) ){\n" + coutput("%s if( (reshape_entry != NULL) && (reshape_entry->data[%s] != NULL) ){\n" "%s /* Reshape promise set up on this task repo by predecessor */\n" "%s consumed_repo = reshape_repo;\n" "%s consumed_entry = reshape_entry;\n" "%s consumed_entry_key = reshape_entry_key;\n" - "%s consumed_flow_index = %d;\n", - spaces, flow->flow_index, + "%s consumed_flow_index = %s;\n", + spaces, string_arena_get_string(sa_consumed_flow_index), spaces, spaces, spaces, spaces, - spaces, flow->flow_index); + spaces, string_arena_get_string(sa_consumed_flow_index)); coutput("%s }else{\n" "%s /* Consume from predecessor's repo */\n" "%s consumed_repo = %s_repo;\n" "%s consumed_entry_key = %s((const parsec_taskpool_t*)__parsec_tp, (const parsec_assignment_t*)target_locals) ;\n" "%s consumed_entry = data_repo_lookup_entry( consumed_repo, consumed_entry_key );\n" - "%s consumed_flow_index = %d;\n" + "%s consumed_flow_index = %s;\n" "%s }\n", spaces, spaces, spaces, pred_name, spaces, jdf_property_get_string(pred_f->properties, JDF_PROP_UD_MAKE_KEY_FN_NAME, NULL), spaces, - spaces, pred_flow->flow_index, + spaces, string_arena_get_string(sa_pred_consumed_flow_index), spaces); } + + // if(FLOW_IS_PARAMETRIZED(f_pred)) + // { // If the target is parametrized, we need to set the flow index according to the expression + // for(jdf_variable_list_t *vl = pred_f->locals; vl != NULL; vl = vl->next) { + // coutput("#undef %s\n", vl->name); + // } + // } + + + string_arena_free(osa); + string_arena_free(sa_consumed_flow_index); + string_arena_free(sa_pred_consumed_flow_index); } static void @@ -5482,6 +7721,10 @@ jdf_generate_code_call_initialization(const jdf_t *jdf, const jdf_call_t *call, sa = string_arena_new(64); sa2 = string_arena_new(64); + string_arena_t *osa; + osa = string_arena_new(64); + string_arena_init(osa); + info.sa = sa2; info.prefix = ""; info.suffix = ""; @@ -5528,15 +7771,21 @@ jdf_generate_code_call_initialization(const jdf_t *jdf, const jdf_call_t *call, spaces, flow->varname, flow->flow_index, dl->dep_index, string_arena_get_string(sa) ); string_arena_init(sa); - coutput("%s if( NULL == (chunk = this_task->data._f_%s.data_in) ) {\n" + coutput("%s if( NULL == (chunk = this_task->data.%s.data_in) ) {\n" "%s /* No data set up by predecessor on this task input flow */\n", - spaces, flow->varname, + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), spaces); /* Function calls */ if( call->var != NULL ) { coutput("%s *target_locals = (%s*)&generic_locals;\n", parsec_get_name(jdf, targetf, "parsec_assignment_t"), parsec_get_name(jdf, targetf, "parsec_assignment_t")); + if(CALL_IS_PARAMETRIZED(call)) + { + // output the value of the iterator + coutput("%s const int %s = %s; (void)%s;\n", + spaces, call->parametrized_offset->alias, dump_expr((void**)call->parametrized_offset, &info), call->parametrized_offset->alias); + } coutput("%s", jdf_create_code_assignments_calls(sa, strlen(spaces)+1, jdf, "target_locals", call)); /* Code to fulfill a reshape promise set up by predecessor if there's one */ @@ -5550,9 +7799,15 @@ jdf_generate_code_call_initialization(const jdf_t *jdf, const jdf_call_t *call, jdf_generate_code_reshape_input_from_dep(jdf, f, flow, dl, spaces); coutput("%s ACQUIRE_FLOW(this_task, \"%s\", &%s_%s, \"%s\", target_locals, chunk);\n" - "%s this_task->data._f_%s.data_out = chunk;\n", + "%s this_task->data.%s.data_out = chunk;\n", spaces, flow->varname, jdf_basename, call->func_or_mem, call->var, - spaces, flow->varname); + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow)); + if(FLOW_IS_PARAMETRIZED(flow)) { + coutput("#if defined(PARSEC_DEBUG_NOISIER)\n"); + coutput("%s parsec_debug_verbose(10, parsec_debug_output, \"%s = %%d\", %s);\n", + spaces, get_parametrized_flow_iterator_name(flow), get_parametrized_flow_iterator_name(flow)); + coutput("#endif\n"); + } } else { @@ -5573,9 +7828,9 @@ jdf_generate_code_call_initialization(const jdf_t *jdf, const jdf_call_t *call, jdf_generate_code_reshape_input_from_desc(jdf, f, flow, dl, spaces); - coutput("%s this_task->data._f_%s.data_out = chunk;\n" + coutput("%s this_task->data.%s.data_out = chunk;\n" "%s PARSEC_OBJ_RETAIN(chunk);\n", - spaces, flow->varname, + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), spaces); } @@ -5602,10 +7857,10 @@ jdf_generate_code_call_initialization(const jdf_t *jdf, const jdf_call_t *call, coutput("%s chunk = parsec_arena_get_copy(%s->arena, %s, target_device, %s->opaque_dtt);\n" "%s chunk->original->owner_device = target_device;\n" - "%s this_task->data._f_%s.data_out = chunk;\n", + "%s this_task->data.%s.data_out = chunk;\n", spaces, string_arena_get_string(sa), string_arena_get_string(sa2), string_arena_get_string(sa), spaces, - spaces, flow->varname); + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow)); string_arena_free(info.sa); } @@ -5622,6 +7877,13 @@ jdf_generate_code_call_initialization(const jdf_t *jdf, const jdf_call_t *call, spaces, spaces); + if(CALL_IS_PARAMETRIZED(call)) + { + // output the value of the iterator + coutput("%s const int %s = %s; (void)%s;\n", + spaces, call->parametrized_offset->alias, dump_expr((void**)call->parametrized_offset, &info), call->parametrized_offset->alias); + } + /* Code to fulfill a reshape promise set up by predecessor if there's one */ jdf_generate_code_consume_predecessor_setup(jdf, call, f, flow, @@ -5631,15 +7893,17 @@ jdf_generate_code_call_initialization(const jdf_t *jdf, const jdf_call_t *call, /* Code to create & fulfill a reshape promise locally in case this input dependency is typed */ jdf_generate_code_reshape_input_from_dep(jdf, f, flow, dl, spaces); - coutput("%s this_task->data._f_%s.data_out = parsec_data_get_copy(chunk->original, target_device);\n" + coutput("%s this_task->data.%s.data_out = parsec_data_get_copy(chunk->original, target_device);\n" "#if defined(PARSEC_PROF_GRAPHER) && defined(PARSEC_PROF_TRACE)\n" "%s parsec_prof_grapher_data_input(chunk->original, (parsec_task_t*)this_task, &%s, 0);\n" "#endif\n" "%s }\n", - spaces, flow->varname, + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), spaces, JDF_OBJECT_ONAME( flow ), spaces); } + + string_arena_free(osa); string_arena_free(sa); string_arena_free(sa2); } @@ -5654,7 +7918,7 @@ static void jdf_generate_code_call_init_output(const jdf_t *jdf, const jdf_call_ const char *spaces) { int dataindex; - string_arena_t *sa, *sa_arena, *sa_datatype, *sa_count ; + string_arena_t *sa, *sa_arena, *sa_datatype, *sa_count, *osa ; expr_info_t info = EMPTY_EXPR_INFO; if( (NULL != call) && (NULL != call->var) ) { @@ -5679,6 +7943,7 @@ static void jdf_generate_code_call_init_output(const jdf_t *jdf, const jdf_call_ } sa = string_arena_new(64); + osa = string_arena_new(64); info.sa = sa; info.prefix = ""; @@ -5705,18 +7970,18 @@ static void jdf_generate_code_call_init_output(const jdf_t *jdf, const jdf_call_ coutput("%s /* Flow %s [%d] dependency [%d] pure output data */\n", spaces, flow->varname, flow->flow_index, dl->dep_index); - coutput("%s if( NULL == (chunk = this_task->data._f_%s.data_in) ) {\n" + coutput("%s if( NULL == (chunk = this_task->data.%s.data_in) ) {\n" "%s /* No data set up by predecessor */\n", - spaces, flow->varname, + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), spaces); coutput("%s chunk = parsec_arena_get_copy(%s->arena, %s, target_device, %s);\n" "%s chunk->original->owner_device = target_device;\n", spaces, string_arena_get_string(sa_arena), string_arena_get_string(sa_count), string_arena_get_string(sa_datatype), spaces); - coutput("%s this_task->data._f_%s.data_out = chunk;\n" + coutput("%s this_task->data.%s.data_out = chunk;\n" "%s }\n", - spaces, flow->varname, + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), spaces); #if defined(PARSEC_DEBUG_NOISIER) || defined(PARSEC_DEBUG_PARANOID) @@ -5731,6 +7996,7 @@ static void jdf_generate_code_call_init_output(const jdf_t *jdf, const jdf_call_ #endif string_arena_free(sa); + string_arena_free(osa); string_arena_free(sa_arena); string_arena_free(sa_datatype); string_arena_free(sa_count); @@ -5747,26 +8013,44 @@ static void jdf_generate_code_flow_initialization(const jdf_t *jdf, char* condition[] = {" if( %s ) {\n", " else if( %s ) {\n"}; if( JDF_FLOW_TYPE_CTL & flow->flow_flags ) { + string_arena_t *sa; + sa = string_arena_new(64); + string_arena_init(sa); + dump_parametrized_flow_loop_if_parametrized(flow, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + coutput(" /* %s is a control flow */\n" - " this_task->data._f_%s.data_in = NULL;\n" - " this_task->data._f_%s.data_out = NULL;\n" - " this_task->data._f_%s.source_repo = NULL;\n" - " this_task->data._f_%s.source_repo_entry = NULL;\n", - flow->varname, - flow->varname, - flow->varname, + "%s this_task->data.%s.data_in = NULL;\n" + "%s this_task->data.%s.data_out = NULL;\n" + "%s this_task->data.%s.source_repo = NULL;\n" + "%s this_task->data.%s.source_repo_entry = NULL;\n", flow->varname, - flow->varname); + INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(sa, flow), + INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(sa, flow), + INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(sa, flow), + INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(sa, flow)); + + string_arena_init(sa); + dump_parametrized_flow_loop_end_if_parametrized(flow, " ", sa); + coutput("%s", string_arena_get_string(sa)); + string_arena_free(sa); + return; } + string_arena_t *osa; + osa = string_arena_new(64); + dump_parametrized_flow_loop_if_parametrized(flow, " ", osa); + coutput("%s", string_arena_get_string(osa)); + coutput("\n" - "if(! this_task->data._f_%s.fulfill ){ /* Flow %s */\n", flow->varname, flow->varname); + "%sif(! this_task->data.%s.fulfill ){ /* Flow %s */\n", INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), flow->varname); - coutput(" consumed_repo = NULL;\n" - " consumed_entry_key = 0;\n" - " consumed_entry = NULL;\n" - " chunk = NULL;\n"); + coutput("%s consumed_repo = NULL;\n" + "%s consumed_entry_key = 0;\n" + "%s consumed_entry = NULL;\n" + "%s chunk = NULL;\n", INDENTATION_IF_PARAMETRIZED(flow), INDENTATION_IF_PARAMETRIZED(flow), INDENTATION_IF_PARAMETRIZED(flow), INDENTATION_IF_PARAMETRIZED(flow)); for(dl = flow->deps; dl != NULL; dl = dl->next) { if ( dl->dep_flags & JDF_DEP_FLOW_OUT ) { @@ -5775,9 +8059,9 @@ static void jdf_generate_code_flow_initialization(const jdf_t *jdf, } } if( !has_output_deps ) { - coutput("\n this_task->data._f_%s.data_out = NULL; /* input only */\n", flow->varname); + coutput("\n%s this_task->data.%s.data_out = NULL; /* input only */\n", INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow)); } else { - coutput("\n this_task->data._f_%s.data_out = NULL; /* By default, if nothing matches */\n", flow->varname); + coutput("\n%s this_task->data.%s.data_out = NULL; /* By default, if nothing matches */\n", INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow)); } sa = string_arena_new(64); @@ -5797,22 +8081,22 @@ static void jdf_generate_code_flow_initialization(const jdf_t *jdf, case JDF_GUARD_UNCONDITIONAL: if( 0 != cond_index ) coutput(" else {\n"); jdf_generate_code_call_initialization( jdf, dl->guard->calltrue, f, flow, dl, - (0 != cond_index ? " " : "") ); + FLOW_IS_PARAMETRIZED(flow)?((0 != cond_index ? " " : " ")):((0 != cond_index ? " " : "")) ); if( 0 != cond_index ) coutput(" }\n"); goto done_with_input; case JDF_GUARD_BINARY: coutput( (0 == cond_index ? condition[0] : condition[1]), dump_expr((void**)dl->guard->guard, &info)); - jdf_generate_code_call_initialization( jdf, dl->guard->calltrue, f, flow, dl, " " ); + jdf_generate_code_call_initialization( jdf, dl->guard->calltrue, f, flow, dl, FLOW_IS_PARAMETRIZED(flow)?" ":" " ); coutput(" }\n"); cond_index++; break; case JDF_GUARD_TERNARY: coutput( (0 == cond_index ? condition[0] : condition[1]), dump_expr((void**)dl->guard->guard, &info)); - jdf_generate_code_call_initialization( jdf, dl->guard->calltrue, f, flow, dl, " " ); + jdf_generate_code_call_initialization( jdf, dl->guard->calltrue, f, flow, dl, FLOW_IS_PARAMETRIZED(flow)?" ":" " ); coutput(" } else {\n"); - jdf_generate_code_call_initialization( jdf, dl->guard->callfalse, f, flow, dl, " " ); + jdf_generate_code_call_initialization( jdf, dl->guard->callfalse, f, flow, dl, FLOW_IS_PARAMETRIZED(flow)?" ":" " ); coutput(" }\n"); goto done_with_input; } @@ -5864,30 +8148,51 @@ static void jdf_generate_code_flow_initialization(const jdf_t *jdf, } } done_with_input: - coutput(" this_task->data._f_%s.data_in = chunk;\n" - " this_task->data._f_%s.source_repo = consumed_repo;\n" - " this_task->data._f_%s.source_repo_entry = consumed_entry;\n", - flow->varname, - flow->varname, - flow->varname); + coutput("%s this_task->data.%s.data_in = chunk;\n" + "%s this_task->data.%s.source_repo = consumed_repo;\n" + "%s this_task->data.%s.source_repo_entry = consumed_entry;\n", + INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), + INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), + INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow)); if( !(f->flags & JDF_FUNCTION_FLAG_NO_SUCCESSORS) ) { /* If we have consume from our repo, we clean up the repo entry for that flow, * so we don't have old stuff during release_deps_of when we will set up outputs * on our repo as a predecessor. */ - coutput(" if( this_task->data._f_%s.source_repo_entry == this_task->repo_entry ){\n" - " /* in case we have consume from this task repo entry for the flow,\n" - " * it is cleaned up, avoiding having old stuff during release_deps_of\n" - " */\n" - " this_task->repo_entry->data[%d] = NULL;\n" - " }\n", - flow->varname, - flow->flow_index); + coutput("%s if( this_task->data.%s.source_repo_entry == this_task->repo_entry ){\n" + "%s /* in case we have consume from this task repo entry for the flow,\n" + "%s * it is cleaned up, avoiding having old stuff during release_deps_of\n" + "%s */\n", + INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), + INDENTATION_IF_PARAMETRIZED(flow), INDENTATION_IF_PARAMETRIZED(flow), INDENTATION_IF_PARAMETRIZED(flow)); + + // Get the flow id as a string + string_arena_t *sa_flow_index = string_arena_new(128); + if(FLOW_IS_PARAMETRIZED(flow)) + { + DUMP_FLOW_ID_VARIABLE(sa_flow_index, jdf_basename, f, flow); + } + else + { + string_arena_add_string(sa_flow_index, "%d", flow->flow_index); + } + + coutput("%s this_task->repo_entry->data[%s] = NULL;\n", INDENTATION_IF_PARAMETRIZED(flow), + string_arena_get_string(sa_flow_index)); + + string_arena_free(sa_flow_index); + + coutput("%s }\n", + INDENTATION_IF_PARAMETRIZED(flow)); } - coutput(" this_task->data._f_%s.fulfill = 1;\n" + coutput("%s this_task->data.%s.fulfill = 1;\n" "}\n\n", - flow->varname);/* coutput("if(! this_task->data._f_%s.fulfill ){\n", flow->varname);*/ + INDENTATION_IF_PARAMETRIZED(flow), DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow));/* coutput("if(! this_task->data._f_%s.fulfill ){\n", flow->varname);*/ + + string_arena_init(osa); + dump_parametrized_flow_loop_end_if_parametrized(flow, " ", osa); + coutput("%s", string_arena_get_string(osa)); string_arena_free(sa); if( NULL != sa2 ) @@ -5904,6 +8209,7 @@ static void jdf_generate_code_call_final_write(const jdf_t *jdf, const jdf_dataflow_t *flow) { string_arena_t *sa, *sa2; + string_arena_t *osa; string_arena_t *sa_arena, *sa_tmp_type_src, *sa_tmp_type_dst; string_arena_t *sa_type_src, *sa_displ_src, *sa_count_src; string_arena_t *sa_type_dst, *sa_displ_dst, *sa_count_dst; @@ -5916,6 +8222,7 @@ static void jdf_generate_code_call_final_write(const jdf_t *jdf, sa = string_arena_new(64); sa2 = string_arena_new(64); + osa = string_arena_new(16); sa_tmp_type_src = string_arena_new(64); sa_tmp_type_dst = string_arena_new(64); @@ -6007,10 +8314,10 @@ static void jdf_generate_code_call_final_write(const jdf_t *jdf, } coutput("%s data_t_desc = data_of_%s(%s);\n" - "%s if( (NULL != this_task->data._f_%s.data_out) && (this_task->data._f_%s.data_out->original != data_t_desc) ) {\n" + "%s if( (NULL != this_task->data.%s.data_out) && (this_task->data.%s.data_out->original != data_t_desc) ) {\n" "%s /* Writting back using remote_type */;\n" "%s parsec_dep_data_description_t data;\n" - "%s data.data = this_task->data._f_%s.data_out;\n" + "%s data.data = this_task->data.%s.data_out;\n" "%s data.local.arena = %s;\n" "%s data.local.src_datatype = %s;\n" "%s data.local.src_count = %s;\n" @@ -6023,13 +8330,13 @@ static void jdf_generate_code_call_final_write(const jdf_t *jdf, "%s parsec_remote_dep_memcpy(es,\n" "%s this_task->taskpool,\n" "%s parsec_data_get_copy(data_of_%s(%s), 0),\n" - "%s this_task->data._f_%s.data_out, &data);\n" + "%s this_task->data.%s.data_out, &data);\n" "%s }\n", spaces, call->func_or_mem, string_arena_get_string(sa), - spaces, flow->varname, flow->varname, + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), spaces, spaces, - spaces, flow->varname, + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), spaces, string_arena_get_string(sa_arena), spaces, string_arena_get_string(sa_type_src), spaces, string_arena_get_string(sa_count_src), @@ -6042,7 +8349,7 @@ static void jdf_generate_code_call_final_write(const jdf_t *jdf, spaces, spaces, spaces, call->func_or_mem, string_arena_get_string(sa), - spaces, flow->varname, + spaces, DUMP_DATA_FIELD_NAME_IN_TASK(osa, flow), spaces); coutput("#if defined(PARSEC_PROF_GRAPHER) && defined(PARSEC_PROF_TRACE)\n" @@ -6053,6 +8360,7 @@ static void jdf_generate_code_call_final_write(const jdf_t *jdf, string_arena_free(sa); string_arena_free(sa2); + string_arena_free(osa); string_arena_free(sa_arena); string_arena_free(sa_tmp_type_src); string_arena_free(sa_tmp_type_dst); @@ -6156,9 +8464,54 @@ static void jdf_generate_code_cache_awareness_update(const jdf_t *jdf, const jdf sa = string_arena_new(64); (void)jdf; - UTIL_DUMP_LIST(sa, f->dataflow, next, - dump_dataflow_varname, NULL, - "", " cache_buf_referenced(es->closest_cache, ", ");\n", ""); + // if(f->dataflow && f->dataflow->array_offset != NULL) + // { + // expr_info_t expr_info = EMPTY_EXPR_INFO; + // expr_info.sa = string_arena_new(8); + // expr_info.prefix = ""; + // expr_info.suffix = ""; + // expr_info.assignments = "parametrized flow range"; + + // string_arena_add_string(sa, " for(int i=0;i<(%s);++i) {\n", dump_expr((void**)f->dataflow->array_offset, &expr_info)); + // /*UTIL_DUMP_LIST(sa, f->dataflow, next, + // dump_dataflow_varname, NULL, + // "", " cache_buf_referenced(es->closest_cache, ", "[i]);\n }\n", "");*/ + + // // add cache_buf_referenced for all the dataflow variables + // jdf_dataflow_t *df; + // for(df = f->dataflow; df != NULL; df = df->next) { + // string_arena_add_string(sa, " cache_buf_referenced(es->closest_cache, %s[i]);\n", df->varname); + // } + + // string_arena_add_string(sa, " }\n"); + // } + // else + // { + // UTIL_DUMP_LIST(sa, f->dataflow, next, + // dump_dataflow_varname, NULL, + // "", " cache_buf_referenced(es->closest_cache, ", ");\n", ""); + // } + + for(jdf_dataflow_t *df = f->dataflow; df != NULL; df = df->next) { + expr_info_t expr_info = EMPTY_EXPR_INFO; + expr_info.sa = string_arena_new(128); + expr_info.prefix = ""; + expr_info.suffix = ""; + expr_info.assignments = "parametrized flow range"; + + string_arena_t *osa = string_arena_new(16); + + dump_parametrized_flow_loop_if_parametrized(df, " ", sa); + //dump_parametrized_flow_loop(df, df->local_variables->alias, " ", sa); + string_arena_add_string(sa, "%s cache_buf_referenced(es->closest_cache, _f_%s%s);\n", + INDENTATION_IF_PARAMETRIZED(df), df->varname, DUMP_ARRAY_OFFSET_IF_PARAMETRIZED(osa, df)); + dump_parametrized_flow_loop_end_if_parametrized(df, " ", sa); + //string_arena_add_string(sa, " }\n"); + + string_arena_free(expr_info.sa); + string_arena_free(osa); + } + if( strlen(string_arena_get_string(sa)) ) { coutput(" /** Cache Awareness Accounting */\n" "#if defined(PARSEC_CACHE_AWARENESS)\n" @@ -6173,21 +8526,35 @@ static void jdf_generate_code_call_release_dependencies(const jdf_t *jdf, const jdf_function_entry_t *function, const char* context_name) { - uint32_t complete_mask = 0; + parsec_dependency_t complete_mask = 0; jdf_dataflow_t* dl; (void)jdf; + char complete_mask_str[256]; + for( dl = function->dataflow; dl != NULL; dl = dl->next ) { complete_mask |= dl->flow_dep_mask_out; } + + // if the task class has any parametrized flow is referrer, the mask can not be computed at compile time + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(function)) + { + snprintf(complete_mask_str, 256, "spec_%s.dep_mask_out_of_flow_of_%s_%s", + JDF_OBJECT_ONAME(function), jdf_basename, function->fname); + } + else + { + snprintf(complete_mask_str, 256, "0x%lx", complete_mask); + } + coutput(" release_deps_of_%s_%s(es, %s,\n" " PARSEC_ACTION_RELEASE_REMOTE_DEPS |\n" " PARSEC_ACTION_RELEASE_LOCAL_DEPS |\n" " PARSEC_ACTION_RELEASE_LOCAL_REFS |\n" " PARSEC_ACTION_RESHAPE_ON_RELEASE |\n" - " 0x%x, /* mask of all dep_index */ \n" + " %s, /* mask of all dep_index */ \n" " NULL);\n", - jdf_basename, function->fname, context_name, complete_mask); + jdf_basename, function->fname, context_name, complete_mask_str); } /** @@ -6195,12 +8562,12 @@ static void jdf_generate_code_call_release_dependencies(const jdf_t *jdf, * allows us to delay the code generation in order to merge together multiple deps * using the same datatype, count and displacement. */ -#define JDF_CODE_DATATYPE_DUMP(SA_WHERE, MASK, SA_COND, SA_DATATYPE, SKIP_COND) \ +#define JDF_CODE_DATATYPE_DUMP(SA_WHERE, MASK, MASK_STR, SA_COND, SA_DATATYPE, SKIP_COND) \ do { \ if( strlen(string_arena_get_string((SA_DATATYPE))) ) { \ string_arena_add_string((SA_WHERE), \ - " if( ((*flow_mask) & 0x%xU)", \ - (MASK)); \ + " if( ((*flow_mask) & %s)", \ + (MASK_STR)); \ if( strlen(string_arena_get_string((SA_COND))) ) { \ if( !(SKIP_COND) ) { \ string_arena_add_string((SA_WHERE), \ @@ -6214,10 +8581,10 @@ static void jdf_generate_code_call_release_dependencies(const jdf_t *jdf, (SKIP_COND) = 0; \ string_arena_add_string((SA_WHERE), \ "%s" \ - " (*flow_mask) &= ~0x%xU;\n" \ + " (*flow_mask) &= ~%s;\n" \ " return PARSEC_HOOK_RETURN_NEXT;\n", \ string_arena_get_string((SA_DATATYPE)), \ - (MASK)); \ + (MASK_STR)); \ string_arena_add_string((SA_WHERE), " }\n"); \ if( strlen(string_arena_get_string((SA_COND))) ) { \ string_arena_init((SA_COND)); \ @@ -6228,6 +8595,7 @@ static void jdf_generate_code_call_release_dependencies(const jdf_t *jdf, } while(0) +// TODO: needs to be changed for parametrized flows (the masks won't work) static void jdf_generate_code_datatype_lookup(const jdf_t *jdf, const jdf_function_entry_t *f, @@ -6237,22 +8605,23 @@ jdf_generate_code_datatype_lookup(const jdf_t *jdf, assignment_info_t ai; jdf_dataflow_t *fl; jdf_dep_t *dl; - string_arena_t *sa_coutput = string_arena_new(1024); - string_arena_t *sa_deps = string_arena_new(1024); - string_arena_t *sa_datatype = string_arena_new(1024); - string_arena_t *sa_arena = string_arena_new(256); - string_arena_t *sa_tmp_arena = string_arena_new(256); - string_arena_t *sa_count = string_arena_new(256); - string_arena_t *sa_tmp_count = string_arena_new(256); - string_arena_t *sa_displ = string_arena_new(256); - string_arena_t *sa_tmp_displ = string_arena_new(256); - string_arena_t *sa_type = string_arena_new(256); - string_arena_t *sa_tmp_type = string_arena_new(256); - string_arena_t *sa_cond = string_arena_new(256); - string_arena_t *sa_temp = string_arena_new(256); + string_arena_t *sa_coutput = string_arena_new(1024); + string_arena_t *sa_deps = string_arena_new(1024); + string_arena_t *sa_datatype = string_arena_new(1024); + string_arena_t *sa_arena = string_arena_new(256); + string_arena_t *sa_tmp_arena = string_arena_new(256); + string_arena_t *sa_count = string_arena_new(256); + string_arena_t *sa_tmp_count = string_arena_new(256); + string_arena_t *sa_displ = string_arena_new(256); + string_arena_t *sa_tmp_displ = string_arena_new(256); + string_arena_t *sa_type = string_arena_new(256); + string_arena_t *sa_tmp_type = string_arena_new(256); + string_arena_t *sa_cond = string_arena_new(256); + string_arena_t *sa_temp = string_arena_new(256); + string_arena_t *sa_current_mask = string_arena_new(256); int last_datatype_idx, continue_dependencies, type, skip_condition, generate_exit_label = 0; - uint32_t current_mask = 0; + parsec_dependency_t current_mask = 0; expr_info_t info = EMPTY_EXPR_INFO; sa = string_arena_new(64); @@ -6267,12 +8636,12 @@ jdf_generate_code_datatype_lookup(const jdf_t *jdf, ai.holder = "this_task->locals."; ai.expr = NULL; coutput("static int %s(parsec_execution_stream_t *es, const %s *this_task,\n" - " uint32_t* flow_mask, parsec_dep_data_description_t* data)\n" + " parsec_dependency_t* flow_mask, parsec_dep_data_description_t* data)\n" "{\n" " const __parsec_%s_internal_taskpool_t *__parsec_tp = (__parsec_%s_internal_taskpool_t *)this_task->taskpool;\n" " (void)__parsec_tp; (void)es; (void)this_task; (void)data;\n" "%s", - name, parsec_get_name(jdf, f, "task_t"), + name, parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename, UTIL_DUMP_LIST(sa, f->locals, next, dump_local_assignments, &ai, "", " ", "\n", "\n")); @@ -6296,8 +8665,28 @@ jdf_generate_code_datatype_lookup(const jdf_t *jdf, if( !(fl->flow_flags & JDF_FLOW_IS_OUT) ) continue; } skip_condition = 0; /* Assume we have a valid not-yet-optimized condition */ - string_arena_add_string(sa_coutput, "if( (*flow_mask) & 0x%xU ) { /* Flow %s */\n", - (type == JDF_DEP_FLOW_OUT ? fl->flow_dep_mask_out : (1U << fl->flow_index)), fl->varname); + + //string_arena *sa_parametrized_flow = string_arena_new(256); + //string_arena_init(sa_parametrized_flow); + + // Get the action mask for this flow as a string + string_arena_t *sa_action_mask = string_arena_new(128); + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(f)) { + // dynamic masks if any flow/dep is parametrized + string_arena_add_string(sa_action_mask, "spec_%s.dep_mask_out_of_flow_of_%s_%s_for_%s", + JDF_OBJECT_ONAME(f), + jdf_basename, f->fname, fl->varname); + } + else + { + // static masks if no parametrization in this task class + string_arena_add_string(sa_action_mask, "0x%lxU", (type == JDF_DEP_FLOW_OUT ? fl->flow_dep_mask_out : (1U << fl->flow_index))); + } + + string_arena_add_string(sa_coutput, "if( (*flow_mask) & %s ) { /* Flow %s */\n", + string_arena_get_string(sa_action_mask), fl->varname); + + dump_parametrized_flow_loop_if_parametrized(fl, " ", sa_coutput); last_datatype_idx = -1; continue_dependencies = 1; @@ -6308,13 +8697,16 @@ jdf_generate_code_datatype_lookup(const jdf_t *jdf, string_arena_init(sa_displ); string_arena_init(sa_type); string_arena_init(sa_cond); + string_arena_init(sa_current_mask); for(dl = fl->deps; NULL != dl; dl = dl->next) { if( !(dl->dep_flags & type) ) continue; /* Prepare the memory layout of the output dependency. */ if( last_datatype_idx != dl->dep_datatype_index ) { - JDF_CODE_DATATYPE_DUMP(sa_coutput, current_mask, sa_cond, sa_datatype, skip_condition); + string_arena_init(sa_current_mask); + string_arena_add_string(sa_current_mask, "0x%lxU", current_mask); + JDF_CODE_DATATYPE_DUMP(sa_coutput, current_mask, string_arena_get_string(sa_current_mask), sa_cond, sa_datatype, skip_condition); /************************************/ /* REMOTE DATATYPE USED FOR RECV */ /************************************/ @@ -6369,14 +8761,20 @@ jdf_generate_code_datatype_lookup(const jdf_t *jdf, } /* update the mask before the next dump */ - current_mask |= (type == JDF_DEP_FLOW_OUT ? (1U << dl->dep_index) : (1U << fl->flow_index)); + current_mask |= (type == JDF_DEP_FLOW_OUT ? (1U << dl->dep_index) : (1U << fl->flow_index)); // TODO if( !continue_dependencies ) break; } - JDF_CODE_DATATYPE_DUMP(sa_coutput, current_mask, sa_cond, sa_datatype, skip_condition); + string_arena_init(sa_current_mask); + string_arena_add_string(sa_current_mask, "0x%lxU", current_mask); + JDF_CODE_DATATYPE_DUMP(sa_coutput, current_mask, string_arena_get_string(sa_current_mask), sa_cond, sa_datatype, skip_condition); + + dump_parametrized_flow_loop_end_if_parametrized(fl, " ", sa_coutput); + + string_arena_add_string(sa_coutput, "} /* (flow_mask & %s) */\n", + string_arena_get_string(sa_action_mask)); - string_arena_add_string(sa_coutput, "} /* (flow_mask & 0x%xU) */\n", - (type == JDF_DEP_FLOW_OUT ? fl->flow_dep_mask_out : (1U << fl->flow_index))); + string_arena_free(sa_action_mask); } if( type == JDF_DEP_FLOW_IN ) { @@ -6426,6 +8824,239 @@ jdf_generate_code_datatype_lookup(const jdf_t *jdf, string_arena_free(sa_tmp_displ); string_arena_free(sa_tmp_type); string_arena_free(sa_temp); + string_arena_free(sa_current_mask); +} + +static void jdf_generate_check_for_one_call_to_call_link(const jdf_t *jdf, const jdf_function_entry_t *sourcef, const jdf_dataflow_t *source_flow, int dep_index, const jdf_call_t *source_call, + const jdf_function_entry_t *targetf, const jdf_dataflow_t *target_flow, const jdf_call_t *target_call, int is_calltrue) +{ + string_arena_t *sa = string_arena_new(64); + + char spaces[] = ""; + + expr_info_t expr_info = EMPTY_EXPR_INFO; + expr_info.sa = string_arena_new(64); + expr_info.prefix = ""; + expr_info.suffix = ""; + expr_info.assignments = "expr info of referrer"; + + coutput("%s // call%s of dep %d of flow %s of task class %s\n", spaces, is_calltrue?"true":"false", dep_index, target_flow->varname, targetf->fname); + coutput("%s {\n", spaces); + + int nb_opened_call_locals = 0; + int any_local_is_ranged = 0; + + string_arena_init(sa); + coutput("%s %s *target_locals = (%s*)&generic_locals;\n", + spaces, parsec_get_name(jdf, targetf, "parsec_assignment_t"), parsec_get_name(jdf, targetf, "parsec_assignment_t")); + // for(jdf_variable_list_t *vl = targetf->locals; vl != NULL; vl = vl->next) { + // // Get the function parameter if it is one + // const jdf_expr_t *el; + // jdf_expr_t *params = source_call->parameters; + // jdf_param_list_t *pl; + // for(el = params, pl = targetf->parameters; pl != NULL; el = el->next, pl = pl->next) { + // if( NULL == el ) { /* Badly formulated call */ + // string_arena_t *sa_caller, *sa_callee; + // expr_info_t caller = EMPTY_EXPR_INFO; + + // sa_caller = string_arena_new(64); + // sa_callee = string_arena_new(64); + + // caller.sa = sa; + // caller.prefix = ""; + // caller.suffix = ""; + // caller.assignments = ""; + + // string_arena_init(sa); + // UTIL_DUMP_LIST_FIELD(sa_callee, targetf->parameters, next, name, + // dump_string, sa, + // "(", "", ", ", ")"); + // string_arena_init(sa); + // UTIL_DUMP_LIST(sa_caller, params, next, + // dump_expr, (void*)&caller, + // "(", "", ", ", ")"); + // fprintf(stderr, "%s.jdf:%d Badly formulated call %s%s instead of %s%s\n", + // jdf_basename, source_call->super.lineno, + // targetf->fname, string_arena_get_string(sa_caller), + // targetf->fname, string_arena_get_string(sa_callee)); + // exit(-1); + // } + // assert( el != NULL ); + // if(!strcmp(pl->name, vl->name)) + // break; + // } + + // expr_info_t infodst; + // infodst.sa = sa; + // infodst.prefix = targetf->fname; + // infodst.suffix = ""; + // infodst.assignments = "target_locals"; + // expr_info_t infosrc; + // infosrc.sa = sa; + // infosrc.prefix = ""; + // infosrc.suffix = ""; + // infosrc.assignments = "&this_task->locals"; + + // if( NULL == pl ) { + // /* It is a value. Let's dump it's expression in the destination context */ + // string_arena_init(sa); + // coutput(" %sconst int %s%s = %s; (void)%s%s;\n", + // (spaces), targetf->fname, vl->name, dump_expr((void**)vl->expr, &infodst), targetf->fname, vl->name); + // } else { + // /* It is a parameter. Let's dump it's expression in the source context */ + // assert(el != NULL); + // string_arena_init(sa); + // coutput(" %sconst int %s%s = %s; (void)%s%s;\n", + // (spaces), targetf->fname, vl->name, dump_expr((void**)el, &infosrc), targetf->fname, vl->name); + // } + // } + + + // TODO looks like this is completely useless + // add the relevant call variables: + jdf_call_t *dl = target_call; + if( NULL != dl->local_defs ) { + jdf_expr_t *ld; + for(ld = jdf_expr_lv_first(dl->local_defs); ld != NULL; ld = jdf_expr_lv_next(dl->local_defs, ld)) { + + assert(NULL != ld->alias); + assert(-1 != ld->ldef_index); + + if(JDF_RANGE == ld->op || JDF_PARAMETRIZED_FLOW_RANGE == ld->op) + { + any_local_is_ranged = 1; + } + + if(strcmp(ld->alias, get_parametrized_flow_iterator_name(source_flow))==0) + { // skip the local that is the parametrized iterator (already handled in the outer loop) + continue; + } + + expr_info_t expr_info = EMPTY_EXPR_INFO; + expr_info.sa = string_arena_new(64); + expr_info.prefix = ""; + expr_info.suffix = ""; + expr_info.assignments = ""; + + coutput("%s int %s;\n", spaces, ld->alias); + if(JDF_RANGE == ld->op || JDF_PARAMETRIZED_FLOW_RANGE == ld->op) { + coutput( + "%s for( %s = %s;", + spaces, ld->alias, dump_expr((void**)ld->jdf_ta1, &expr_info)); + coutput("%s <= %s; %s+=", + ld->alias, dump_expr((void**)ld->jdf_ta2, &expr_info), ld->alias); + coutput("%s) {\n", + dump_expr((void**)ld->jdf_ta3, &expr_info)); + ++nb_opened_call_locals; + } else { + coutput( + "%s %s = %s;\n", + spaces, ld->alias, dump_expr((void**)ld, &expr_info)); + } + } + } + coutput("%s", jdf_create_code_assignments_calls(sa, strlen(spaces)+1, jdf, "target_locals", source_call)); + + for(jdf_variable_list_t *vl = targetf->locals; vl != NULL; vl = vl->next) { + coutput("#define %s %s%s\n", vl->name, targetf->fname, vl->name); + } + + // dump the parsec_fatal if an incoherency is detected + coutput("%s // call%s dependency %d of flow %s of function %s\n", + spaces, is_calltrue?"true":"false", dep_index, target_flow->varname, targetf->fname); + if(any_local_is_ranged) + { + coutput("%s // Ensure that we stay in the bounds;\n", spaces); + + for(int comparator=0;comparator<2;comparator++) { + coutput( + "%s if((%s) %s (%s)) {\n" + "%s parsec_fatal(\"A dependency between a parametrized flow and its referrer is incoherent.\\n\"\n" + "%s \"If %s = %%d, %s !%s %%d\\n\"\n" + "%s \"The parametrized flow is %s of task class %s.\\n\"\n" + "%s \"The referrer is call%s of dep %d of flow %s of task class %s.\\n\",\n" + "%s %s, %s);\n" + "%s }\n", + spaces, + // lower or upper bound, depending on the comparator + dump_expr((void**)(comparator?source_flow->local_variables->jdf_ta1:source_flow->local_variables->jdf_ta2), &expr_info), + comparator?">":"<", target_call->local_defs->alias, + spaces, + spaces, get_parametrized_flow_iterator_name(source_flow), dump_expr((void**)target_call->parametrized_offset, &expr_info), comparator?">":"<", + spaces, source_flow->varname, sourcef->fname, + spaces, is_calltrue?"true":"false", dep_index, target_flow->varname, targetf->fname, + spaces, get_parametrized_flow_iterator_name(source_flow), get_parametrized_flow_iterator_name(source_flow), + spaces); + } + } + else + { + coutput("%s // Since no local is ranged, we can assume an exact equality);\n", spaces); + + coutput( + "%s if((%s) != (%s)) {\n" + "%s parsec_fatal(\"A dependency between a parametrized flow and its referrer is incoherent.\\n\"\n" + "%s \"If %s = %%d, %s != %%d\\n\"\n" + "%s \"The parametrized flow is %s of task class %s.\\n\"\n" + "%s \"The referrer is call%s of dep %d of flow %s of task class %s.\\n\",\n" + "%s %s, %s);\n" + "%s }\n", + spaces, dump_expr((void**)target_call->parametrized_offset, &expr_info), get_parametrized_flow_iterator_name(source_flow), + spaces, + spaces, get_parametrized_flow_iterator_name(source_flow), dump_expr((void**)target_call->parametrized_offset, &expr_info), + spaces, source_flow->varname, sourcef->fname, + spaces, is_calltrue?"true":"false", dep_index, target_flow->varname, targetf->fname, + spaces, get_parametrized_flow_iterator_name(source_flow), get_parametrized_flow_iterator_name(source_flow), + spaces); + } + + + for(jdf_variable_list_t *vl = targetf->locals; vl != NULL; vl = vl->next) { + coutput("#undef %s\n", vl->name); + } + + // close opened calls: + while(nb_opened_call_locals > 0) { + coutput("%s }\n", spaces); + --nb_opened_call_locals; + } + + coutput("%s }\n", spaces); +} + +static void jdf_generate_check_parametrized_link(const jdf_t *jdf, const jdf_function_entry_t *sourcef, const jdf_dataflow_t *source_flow, const jdf_call_t *source_call) +{ + for(jdf_function_entry_t *targetf = jdf->functions; targetf != NULL; targetf = targetf->next) { + if(strcmp(targetf->fname, source_call->func_or_mem) != 0) + continue; + for(jdf_dataflow_t *target_flow = targetf->dataflow; target_flow != NULL; target_flow = target_flow->next) { + if(strcmp(target_flow->varname, source_call->var) != 0) + continue; + + int dep_index = 0; + for(jdf_dep_t *target_dep = target_flow->deps; NULL != target_dep; target_dep = target_dep->next, ++dep_index) { + jdf_guarded_call_t *guard = target_dep->guard; + jdf_call_t *target_call; + switch(guard->guard_type) { + case JDF_GUARD_TERNARY: + target_call = guard->callfalse; + if(target_call->parametrized_offset && 0 == strcmp(target_call->var, source_flow->varname) && 0 == strcmp(target_call->func_or_mem, sourcef->fname)) { + jdf_generate_check_for_one_call_to_call_link(jdf, sourcef, source_flow, dep_index, source_call, targetf, target_flow, target_call, 0); + } + __attribute__ ((fallthrough)); + case JDF_GUARD_BINARY: + case JDF_GUARD_UNCONDITIONAL: + target_call = guard->calltrue; + if(target_call->parametrized_offset && 0 == strcmp(target_call->var, source_flow->varname) && 0 == strcmp(target_call->func_or_mem, sourcef->fname)) { + jdf_generate_check_for_one_call_to_call_link(jdf, sourcef, source_flow, dep_index, source_call, targetf, target_flow, target_call, 1); + } + break; + default: + assert(0); + } + } + } + } } static void @@ -6461,13 +9092,60 @@ jdf_generate_code_data_lookup(const jdf_t *jdf, " (void)consumed_flow_index;\n" " (void)chunk; (void)data; (void)ret;\n" "%s", - name, parsec_get_name(jdf, f, "task_t"), + name, parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename, UTIL_DUMP_LIST(sa, f->locals, next, dump_local_assignments, &ai, "", " ", "\n", "\n")); UTIL_DUMP_LIST(sa, f->dataflow, next, dump_data_declaration, sa2, "", "", "", ""); + + + // Check that the jdf dependencies are correct + for( jdf_dataflow_t* flow = f->dataflow; flow != NULL; flow = flow->next ) { + if(!FLOW_IS_PARAMETRIZED(flow)) { + continue; + } + + coutput(" /* check the dependencies for %s */\n", flow->varname); + coutput("#if defined(PARSEC_DEBUG_PARANOID)\n"); + coutput("/* Commented because these checks are too restrictive\n"); + coutput("// All the referrers to the parametrized flow %s of task class %s:\n", flow->varname, f->fname); + + string_arena_t *sa_loop = string_arena_new(64); + dump_parametrized_flow_loop(flow, get_parametrized_flow_iterator_name(flow), "", sa_loop); + coutput("%s", string_arena_get_string(sa_loop)); + + + // Search in targetf all the dependencies (referrers) that point to me (parametrized flow) + for(jdf_dep_t *dep = flow->deps; NULL != dep; dep = dep->next) { + jdf_guarded_call_t *guard = dep->guard; + jdf_call_t *call; + switch(guard->guard_type) { + case JDF_GUARD_TERNARY: + call = guard->callfalse; + jdf_generate_check_parametrized_link(jdf, f, flow, call); + __attribute__ ((fallthrough)); + case JDF_GUARD_BINARY: + case JDF_GUARD_UNCONDITIONAL: + call = guard->calltrue; + jdf_generate_check_parametrized_link(jdf, f, flow, call); + break; + default: + assert(0); + } + } + + string_arena_init(sa_loop); + dump_parametrized_flow_loop_end(flow, "", sa_loop); + coutput("%s", string_arena_get_string(sa_loop)); + string_arena_free(sa_loop); + + coutput("*/\n"); + coutput("#endif // PARSEC_DEBUG_PARANOID\n\n"); + } + + /* We need to set up +1 as usage limit because we are creating it during datalookup *ONLY* when it hasn't been * advanced by the predecessor. @@ -6570,7 +9248,7 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, const char *dyldtype; const char *device; const char *weight; - string_arena_t *sa, *sa2, *sa3; + string_arena_t *sa, *sa2, *sa3, *osa; assignment_info_t ai; init_from_data_info_t ai2; jdf_dataflow_t *fl; @@ -6590,6 +9268,7 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, sa = string_arena_new(64); sa2 = string_arena_new(64); sa3 = string_arena_new(64); + osa = string_arena_new(64); ai.sa = sa2; ai.holder = "this_task->locals."; @@ -6624,7 +9303,7 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, jdf_basename, f->fname, dyldtype, jdf_basename, f->fname, - parsec_get_name(jdf, f, "task_t"), parsec_get_name(jdf, f, "task_t"), + parsec_get_task_type_name(jdf, f), parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename, jdf_basename, f->fname, string_arena_get_string( sa3 )); @@ -6650,10 +9329,10 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, if(fl->flow_flags & JDF_FLOW_TYPE_CTL) continue; /* control flow, nothing to store */ - coutput(" data_repo_entry_t *e%s = this_task->data._f_%s.source_repo_entry;\n" + coutput(" data_repo_entry_t *e%s = this_task->data.%s.source_repo_entry;\n" " if( (NULL != e%s) && (e%s->sim_exec_date > this_task->sim_exec_date) )\n" " this_task->sim_exec_date = e%s->sim_exec_date;\n", - fl->varname, fl->varname, + fl->varname, DUMP_DATA_FIELD_NAME_IN_TASK(osa, fl), fl->varname, fl->varname, fl->varname); } @@ -6665,6 +9344,8 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, " }\n" "#endif\n"); + + jdf_generate_code_cache_awareness_update(jdf, f); coutput("#if defined(PARSEC_DEBUG_NOISIER)\n" @@ -6727,7 +9408,7 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, " %s\n" " (void)es; (void)__parsec_tp;\n" "\n", - name, type_property->expr->jdf_var, parsec_get_name(jdf, f, "task_t"), + name, type_property->expr->jdf_var, parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename, string_arena_get_string( sa3 )); @@ -6793,16 +9474,57 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, /* Dump the dataflow */ coutput(" gpu_task->pushout = 0;\n"); + + string_arena_t *sa_di = string_arena_new(64); + string_arena_t *sa_flow = string_arena_new(256); for(fl = f->dataflow, di = 0; fl != NULL; fl = fl->next, di++) { - coutput(" gpu_task->flow[%d] = &%s;\n", - di, JDF_OBJECT_ONAME( fl )); + coutput(" // Dataflow %s\n", fl->varname); + + string_arena_init(sa_flow); + if( FLOW_IS_PARAMETRIZED(fl) ) { + if( JDF_FLOW_TYPE_WRITE & fl->flow_flags ) { + // If the flow is out (note: we use either in or out, this is our only way of getting a parametrized_flow) + string_arena_add_string(sa_flow, "this_task->task_class->out[spec_%s_%s.out_flow_offset_of_parametrized_%s + %s]", + jdf_basename, f->fname, JDF_OBJECT_ONAME(fl), get_parametrized_flow_iterator_name(fl)); + } + else + { + string_arena_add_string(sa_flow, "this_task->task_class->in[spec_%s_%s.in_flow_offset_of_parametrized_%s + %s]", + jdf_basename, f->fname, JDF_OBJECT_ONAME(fl), get_parametrized_flow_iterator_name(fl)); + } + } + else + { + string_arena_add_string(sa_flow, "(&%s)", JDF_OBJECT_ONAME( fl )); + } + string_arena_init(sa_di); + if( FLOW_IS_PARAMETRIZED(fl) || TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) { + // The flow is parametrized + string_arena_add_string(sa_di, "%s->flow_index", + string_arena_get_string(sa_flow)); + } else { + // No parametrized flow, we know di at compile time + string_arena_add_string(sa_di, "%d", di); + } + const char *di_str = string_arena_get_string(sa_di); + + if(FLOW_IS_PARAMETRIZED(fl)) { + string_arena_t *sa = string_arena_new(64); + dump_parametrized_flow_loop(fl, get_parametrized_flow_iterator_name(fl), " ", sa); + coutput("%s", string_arena_get_string(sa)); + string_arena_free(sa); + } + + coutput("%s gpu_task->flow[%s] = %s;\n", + INDENTATION_IF_PARAMETRIZED(fl), di_str, string_arena_get_string(sa_flow)); sprintf(sa->ptr, "%s.dc", fl->varname); jdf_find_property(body->properties, sa->ptr, &desc_property); if(desc_property == NULL){ - coutput(" gpu_task->flow_dc[%d] = NULL;\n", di); + coutput("%s gpu_task->flow_dc[%s] = NULL;\n", INDENTATION_IF_PARAMETRIZED(fl), di_str); }else{ - coutput(" gpu_task->flow_dc[%d] = (parsec_data_collection_t *)%s;\n", di, + coutput("%s gpu_task->flow_dc[%s] = (parsec_data_collection_t *)%s;\n", + INDENTATION_IF_PARAMETRIZED(fl), di_str, dump_expr((void**)desc_property->expr, &info)); } @@ -6815,16 +9537,19 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, fl->varname, JDF_OBJECT_LINENO(fl)); exit(-1); } - coutput(" gpu_task->flow_nb_elts[%d] = 0;\n", di); + coutput("%s gpu_task->flow_nb_elts[%s] = 0;\n", INDENTATION_IF_PARAMETRIZED(fl), di_str); + coutput("%s ++current_flow_id;\n", INDENTATION_IF_PARAMETRIZED(fl)); }else{ if(size_property == NULL){ - coutput(" gpu_task->flow_nb_elts[%d] = gpu_task->ec->data[%d].data_in->original->nb_elts;\n", di, di); + coutput("%s // If gpu_task->ec->data[%s].data_in is NULL, then 0 elements\n", INDENTATION_IF_PARAMETRIZED(fl), di_str); + coutput("%s gpu_task->flow_nb_elts[%s] = (gpu_task->ec->data[%s].data_in)?(gpu_task->ec->data[%s].data_in->original->nb_elts):0;\n", + INDENTATION_IF_PARAMETRIZED(fl), di_str, di_str, di_str); }else{ - coutput(" gpu_task->flow_nb_elts[%d] = %s;\n", - di, dump_expr((void**)size_property->expr, &info)); + coutput("%s gpu_task->flow_nb_elts[%s] = %s;\n", + INDENTATION_IF_PARAMETRIZED(fl), di_str, dump_expr((void**)size_property->expr, &info)); if( (stage_in_property == NULL) || ( stage_out_property == NULL )){ - coutput(" assert(gpu_task->ec->data[%d].data_in->original->nb_elts <= %s);\n", - di, dump_expr((void**)size_property->expr, &info)); + coutput("%s assert(gpu_task->ec->data[%s].data_in->original->nb_elts <= %s);\n", + INDENTATION_IF_PARAMETRIZED(fl), di_str, dump_expr((void**)size_property->expr, &info)); } } @@ -6854,33 +9579,33 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, switch( dl->guard->guard_type ) { case JDF_GUARD_UNCONDITIONAL: if(testtrue) { - coutput(" gpu_task->pushout |= (1 << %d);\n", di); + coutput(" gpu_task->pushout |= (1 << %s);\n", di_str); goto nextflow; } break; case JDF_GUARD_BINARY: if(testtrue) { coutput(" if( %s ) {\n" - " gpu_task->pushout |= (1 << %d);\n" + " gpu_task->pushout |= (1 << %s);\n" " }", - dump_expr((void**)dl->guard->guard, &info), di); + dump_expr((void**)dl->guard->guard, &info), di_str); } break; case JDF_GUARD_TERNARY: if( testtrue ) { if( testfalse ) { - coutput(" gpu_task->pushout |= (1 << %d);\n", di); + coutput(" gpu_task->pushout |= (1 << %s);\n", di_str); } else { coutput(" if( %s ) {\n" - " gpu_task->pushout |= (1 << %d);\n" + " gpu_task->pushout |= (1 << %s);\n" " }\n", - dump_expr((void**)dl->guard->guard, &info), di); + dump_expr((void**)dl->guard->guard, &info), di_str); } } else if ( testfalse ) { coutput(" if( !(%s) ) {\n" - " gpu_task->pushout |= (1 << %d);\n" + " gpu_task->pushout |= (1 << %s);\n" " }\n", - dump_expr((void**)dl->guard->guard, &info), di); + dump_expr((void**)dl->guard->guard, &info), di_str); } break; } @@ -6888,7 +9613,22 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, nextflow: ; } + + if(FLOW_IS_PARAMETRIZED(fl)) { + string_arena_t *sa = string_arena_new(64); + dump_parametrized_flow_loop_end_if_parametrized(fl, " ", sa); + coutput("%s", string_arena_get_string(sa)); + string_arena_free(sa); + } } + + /*if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) { + coutput(" assert(this_task->task_class->nb_flows > 0);\n"); + coutput(" memcpy(gpu_task->flow, this_task->task_class->flow, sizeof(parsec_flow_t) * this_task->task_class->nb_flows);\n"); + }*/ + + string_arena_free(sa_di); + string_arena_free(info.sa); coutput(" parsec_device_load[dev_index] += gpu_task->load;\n" @@ -6899,6 +9639,7 @@ static void jdf_generate_code_hook_cuda(const jdf_t *jdf, string_arena_free(sa); string_arena_free(sa2); string_arena_free(sa3); + string_arena_free(osa); } static void jdf_generate_code_hook(const jdf_t *jdf, @@ -6907,13 +9648,15 @@ static void jdf_generate_code_hook(const jdf_t *jdf, const char *name) { jdf_def_list_t* type_property; - string_arena_t *sa, *sa2; + string_arena_t *sa, *sa2, *osa; assignment_info_t ai; init_from_data_info_t ai2; jdf_dataflow_t *fl; int di; char* output; + osa = string_arena_new(32); + jdf_find_property(body->properties, "type", &type_property); if(NULL != type_property) { if(JDF_VAR != type_property->expr->op) { @@ -6949,10 +9692,10 @@ static void jdf_generate_code_hook(const jdf_t *jdf, if(NULL == type_property) coutput("static int %s(parsec_execution_stream_t *es, %s *this_task)\n", - name, parsec_get_name(jdf, f, "task_t")); + name, parsec_get_task_type_name(jdf, f)); else coutput("static int %s_%s(parsec_execution_stream_t *es, %s *this_task)\n", - name, type_property->expr->jdf_var, parsec_get_name(jdf, f, "task_t")); + name, type_property->expr->jdf_var, parsec_get_task_type_name(jdf, f)); coutput("{\n" " __parsec_%s_internal_taskpool_t *__parsec_tp = (__parsec_%s_internal_taskpool_t *)this_task->taskpool;\n" @@ -6986,12 +9729,23 @@ static void jdf_generate_code_hook(const jdf_t *jdf, if(fl->flow_flags & JDF_FLOW_TYPE_CTL) continue; /* control flow, nothing to store */ - coutput(" data_repo_entry_t *e%s = this_task->data._f_%s.source_repo_entry;\n" - " if( (NULL != e%s) && (e%s->sim_exec_date > this_task->sim_exec_date) )\n" - " this_task->sim_exec_date = e%s->sim_exec_date;\n", - fl->varname, fl->varname, - fl->varname, fl->varname, - fl->varname); + string_arena_t *sa = string_arena_new(64); + dump_parametrized_flow_loop_if_parametrized(fl, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + coutput("%s data_repo_entry_t *e%s = this_task->data.%s.source_repo_entry;\n" + "%s if( (NULL != e%s) && (e%s->sim_exec_date > this_task->sim_exec_date) )\n" + "%s this_task->sim_exec_date = e%s->sim_exec_date;\n", + INDENTATION_IF_PARAMETRIZED(fl), fl->varname, DUMP_DATA_FIELD_NAME_IN_TASK(osa, fl), + INDENTATION_IF_PARAMETRIZED(fl), fl->varname, fl->varname, + INDENTATION_IF_PARAMETRIZED(fl), fl->varname); + + string_arena_init(sa); + + dump_parametrized_flow_loop_end_if_parametrized(fl, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + string_arena_free(sa); } coutput(" if( this_task->task_class->sim_cost_fct != NULL ) {\n" " this_task->sim_exec_date += this_task->task_class->sim_cost_fct(this_task);\n" @@ -7011,15 +9765,29 @@ static void jdf_generate_code_hook(const jdf_t *jdf, /* Applied only on the Write data, since the number of readers is not atomically increased yet */ if ((fl->flow_flags & JDF_FLOW_TYPE_READ) && (fl->flow_flags & JDF_FLOW_TYPE_WRITE) ) { - coutput(" if ( NULL != _f_%s ) {\n" - " parsec_data_transfer_ownership_to_copy( _f_%s->original, 0 /* device */,\n" - " %s);\n" - " }\n", - fl->varname, - fl->varname, - ((fl->flow_flags & JDF_FLOW_TYPE_CTL) ? "PARSEC_FLOW_ACCESS_NONE" : + + string_arena_t *sa = string_arena_new(64); + dump_parametrized_flow_loop_if_parametrized(fl, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + coutput("%s if ( NULL != _f_%s%s ) {\n" + "%s parsec_data_transfer_ownership_to_copy( _f_%s%s->original, 0 /* device */,\n" + "%s %s);\n" + "%s }\n", + INDENTATION_IF_PARAMETRIZED(fl), fl->varname, DUMP_ARRAY_OFFSET_IF_PARAMETRIZED(osa, fl), + INDENTATION_IF_PARAMETRIZED(fl), fl->varname, DUMP_ARRAY_OFFSET_IF_PARAMETRIZED(osa, fl), + INDENTATION_IF_PARAMETRIZED(fl), ((fl->flow_flags & JDF_FLOW_TYPE_CTL) ? "PARSEC_FLOW_ACCESS_NONE" : ((fl->flow_flags & JDF_FLOW_TYPE_READ) ? - ((fl->flow_flags & JDF_FLOW_TYPE_WRITE) ? "PARSEC_FLOW_ACCESS_RW" : "PARSEC_FLOW_ACCESS_READ") : "PARSEC_FLOW_ACCESS_WRITE"))); + ((fl->flow_flags & JDF_FLOW_TYPE_WRITE) ? "PARSEC_FLOW_ACCESS_RW" : "PARSEC_FLOW_ACCESS_READ") : "PARSEC_FLOW_ACCESS_WRITE")), + INDENTATION_IF_PARAMETRIZED(fl)); + + string_arena_init(sa); + + dump_parametrized_flow_loop_end_if_parametrized(fl, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + string_arena_free(sa); + } } coutput("#endif /* defined(PARSEC_HAVE_CUDA) */\n"); @@ -7040,6 +9808,7 @@ static void jdf_generate_code_hook(const jdf_t *jdf, string_arena_free(sa); string_arena_free(sa2); + string_arena_free(osa); hook_end_block: if( NULL != type_property) @@ -7068,7 +9837,7 @@ jdf_generate_code_complete_hook(const jdf_t *jdf, " %s" "#endif /* defined(DISTRIBUTED) */\n" " (void)es; (void)__parsec_tp;\n", - name, parsec_get_name(jdf, f, "task_t"), + name, parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename, UTIL_DUMP_LIST(sa, f->locals, next, dump_local_assignments, &ai, "", " ", "\n", "\n")); @@ -7081,19 +9850,34 @@ jdf_generate_code_complete_hook(const jdf_t *jdf, /** * The data_out might be NULL if we don't forward anything. */ - coutput(" if ( NULL != this_task->data._f_%s.data_out ) {\n" + + string_arena_t *osa = string_arena_new(128); + + dump_parametrized_flow_loop_if_parametrized(fl, " ", osa); + coutput("%s", string_arena_get_string(osa)); + + coutput("%s if ( NULL != this_task->data.%s.data_out ) {\n" "#if defined(PARSEC_DEBUG_NOISIER)\n" - " char tmp[128];\n" + "%s char tmp[128];\n" "#endif\n" - " this_task->data._f_%s.data_out->version++; /* %s */\n" - " PARSEC_DEBUG_VERBOSE(10, parsec_debug_output,\n" - " \"Complete hook of %%s: change Data copy %%p to version %%d at %%s:%%d\",\n" - " parsec_task_snprintf(tmp, 128, (parsec_task_t*)(this_task)),\n" - " this_task->data._f_%s.data_out, this_task->data._f_%s.data_out->version, __FILE__, __LINE__);\n" - " }\n", - fl->varname, - fl->varname, fl->varname, - fl->varname, fl->varname ); + "%s this_task->data.%s.data_out->version++; /* %s */\n" + "%s PARSEC_DEBUG_VERBOSE(10, parsec_debug_output,\n" + "%s \"Complete hook of %%s: change Data copy %%p to version %%d at %%s:%%d\",\n" + "%s parsec_task_snprintf(tmp, 128, (parsec_task_t*)(this_task)),\n" + "%s this_task->data.%s.data_out, this_task->data.%s.data_out->version, __FILE__, __LINE__);\n" + "%s }\n", + INDENTATION_IF_PARAMETRIZED(fl), DUMP_DATA_FIELD_NAME_IN_TASK(osa, fl), + INDENTATION_IF_PARAMETRIZED(fl), + INDENTATION_IF_PARAMETRIZED(fl), DUMP_DATA_FIELD_NAME_IN_TASK(osa, fl), fl->varname, + INDENTATION_IF_PARAMETRIZED(fl), INDENTATION_IF_PARAMETRIZED(fl), INDENTATION_IF_PARAMETRIZED(fl), INDENTATION_IF_PARAMETRIZED(fl), + DUMP_DATA_FIELD_NAME_IN_TASK(osa, fl), DUMP_DATA_FIELD_NAME_IN_TASK(osa, fl), + INDENTATION_IF_PARAMETRIZED(fl)); + + string_arena_init(osa); + dump_parametrized_flow_loop_end_if_parametrized(fl, " ", osa); + coutput("%s", string_arena_get_string(osa)); + + string_arena_free(osa); } } @@ -7132,25 +9916,59 @@ static void jdf_generate_code_hooks(const jdf_t *jdf, static void jdf_generate_code_free_hash_table_entry(const jdf_t *jdf, const jdf_function_entry_t *f, int consume_repo, int release_inputs) { - jdf_dataflow_t *dl; + jdf_dataflow_t *df; coutput(" if( action_mask & PARSEC_ACTION_RELEASE_LOCAL_REFS ) {\n"); - for( dl = f->dataflow; dl != NULL; dl = dl->next ) { - if( dl->flow_flags & JDF_FLOW_TYPE_CTL ) continue; + for( df = f->dataflow; df != NULL; df = df->next ) { + if( df->flow_flags & JDF_FLOW_TYPE_CTL ) continue; if(consume_repo){ - coutput(" if( NULL != this_task->data._f_%s.source_repo_entry ) {\n" - " data_repo_entry_used_once( this_task->data._f_%s.source_repo, this_task->data._f_%s.source_repo_entry->ht_item.key );\n" - " }\n", - dl->varname, - dl->varname, dl->varname); + // TODO: This is not correct, only one dep should be released (not dump_parametrized_flow_loop_if_parametrized) + string_arena_t *sa = string_arena_new(128); + dump_parametrized_flow_loop_if_parametrized(df, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + string_arena_t *osa = string_arena_new(64); + + + coutput("%s if( NULL != this_task->data.%s.source_repo_entry ) {\n" + "%s data_repo_entry_used_once( this_task->data.%s.source_repo, this_task->data.%s.source_repo_entry->ht_item.key );\n" + "%s }\n", + INDENTATION_IF_PARAMETRIZED(df), DUMP_DATA_FIELD_NAME_IN_TASK(osa, df), + INDENTATION_IF_PARAMETRIZED(df), DUMP_DATA_FIELD_NAME_IN_TASK(osa, df), DUMP_DATA_FIELD_NAME_IN_TASK(osa, df), + INDENTATION_IF_PARAMETRIZED(df)); + + string_arena_free(osa); + + string_arena_init(sa); + dump_parametrized_flow_loop_end_if_parametrized(df, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + string_arena_free(sa); } if(release_inputs){ - if( dl->flow_flags & (JDF_FLOW_TYPE_READ | JDF_FLOW_TYPE_WRITE) ) { - coutput(" if( NULL != this_task->data._f_%s.data_in ) {\n" - " PARSEC_DATA_COPY_RELEASE(this_task->data._f_%s.data_in);\n" - " }\n", - dl->varname, dl->varname); + if( df->flow_flags & (JDF_FLOW_TYPE_READ | JDF_FLOW_TYPE_WRITE) ) { + // TODO: This is not correct, only one dep should be released (not dump_parametrized_flow_loop_if_parametrized) + string_arena_t *sa = string_arena_new(128); + dump_parametrized_flow_loop_if_parametrized(df, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + string_arena_t *osa = string_arena_new(64); + + coutput("%s if( NULL != this_task->data.%s.data_in ) {\n" + "%s PARSEC_DATA_COPY_RELEASE(this_task->data.%s.data_in);\n" + "%s }\n", + INDENTATION_IF_PARAMETRIZED(df), DUMP_DATA_FIELD_NAME_IN_TASK(osa, df), + INDENTATION_IF_PARAMETRIZED(df), DUMP_DATA_FIELD_NAME_IN_TASK(osa, df), + INDENTATION_IF_PARAMETRIZED(df)); + + string_arena_free(osa); + + string_arena_init(sa); + dump_parametrized_flow_loop_end_if_parametrized(df, " ", sa); + coutput("%s", string_arena_get_string(sa)); + + string_arena_free(sa); } } (void)jdf; /* just to keep the compilers happy regarding the goto to an empty statement */ @@ -7160,7 +9978,7 @@ static void jdf_generate_code_free_hash_table_entry(const jdf_t *jdf, const jdf_ static void jdf_generate_code_release_deps(const jdf_t *jdf, const jdf_function_entry_t *f, const char *name) { - coutput("static int %s(parsec_execution_stream_t *es, %s *this_task, uint32_t action_mask, parsec_remote_deps_t *deps)\n" + coutput("static int %s(parsec_execution_stream_t *es, %s *this_task, parsec_dependency_t action_mask, parsec_remote_deps_t *deps)\n" "{\n" "PARSEC_PINS(es, RELEASE_DEPS_BEGIN, (parsec_task_t *)this_task);" "{\n" @@ -7178,7 +9996,7 @@ static void jdf_generate_code_release_deps(const jdf_t *jdf, const jdf_function_ " arg.ready_lists = alloca(sizeof(parsec_task_t *) * es->virtual_process->parsec_context->nb_vp);\n" " for( __vp_id = 0; __vp_id < es->virtual_process->parsec_context->nb_vp; arg.ready_lists[__vp_id++] = NULL );\n" " (void)__parsec_tp; (void)deps;\n", - name, parsec_get_name(jdf, f, "task_t"), + name, parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename); jdf_generate_code_free_hash_table_entry(jdf, f, 1/*consume_repo*/, 0/*release_inputs*/); @@ -7257,6 +10075,7 @@ static void jdf_generate_code_release_deps(const jdf_t *jdf, const jdf_function_ "\n"); } +// TODO: not finished yet (parametrized flows wont work) static char *jdf_dump_context_assignment(string_arena_t *sa_open, const jdf_t *jdf, const jdf_function_entry_t *sourcef, @@ -7308,10 +10127,37 @@ static char *jdf_dump_context_assignment(string_arena_t *sa_open, nbopen = 0; string_arena_add_string(sa_open, "%s%s%s* ncc = (%s*)&%s;\n", - prefix, indent(nbopen), parsec_get_name(jdf, targetf, "task_t"), parsec_get_name(jdf, targetf, "task_t"), var); + prefix, indent(nbopen), + parsec_get_task_type_name(jdf, targetf), + parsec_get_task_type_name(jdf, targetf), var); string_arena_add_string(sa_open, "%s%s%s.task_class = __parsec_tp->super.super.task_classes_array[%s_%s.task_class_id];\n", prefix, indent(nbopen), var, jdf_basename, targetf->fname); + // If any flow in this task class is parametrized, we set all the ldef's so that make_key can function even if there is no parametrized offset + + // rubish + // if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(targetf)) + // { + // for(int ldef_index=0;ldef_indexnb_max_local_def;++ldef_index) { + // string_arena_add_string(sa_open, "%s%sncc->locals.ldef[%d].value = 0;\n", + // prefix, indent(nbopen), ldef_index); + // } + // if(FLOW_IS_PARAMETRIZED(flow)) { + // // set the iterator + // string_arena_add_string(sa_open, "%s%sncc->locals.ldef[%d].value = %s;\n", + // prefix, indent(nbopen), + // flow->local_variables->ldef_index, + // get_parametrized_flow_iterator_name(flow)); + // } + // } + if(FLOW_IS_PARAMETRIZED(flow)) { + // set the iterator + string_arena_add_string(sa_open, "%s%sncc->locals.ldef[%d].value = %s;\n", + prefix, indent(nbopen), + flow->local_variables->ldef_index, + get_parametrized_flow_iterator_name(flow)); + } + nbparam_given = 0; for(el = call->parameters; el != NULL; el = el->next) { nbparam_given++; @@ -7343,8 +10189,15 @@ static char *jdf_dump_context_assignment(string_arena_t *sa_open, dep_ld = jdf_expr_lv_next(dep->local_defs, dep_ld); continue; /* This local define was already issued as part of the dep */ } - string_arena_add_string(sa_open, "%s%s int %s;\n", prefix, indent(nbopen), ld->alias); - if(JDF_RANGE == ld->op) { + if(JDF_PARAMETRIZED_FLOW_RANGE != ld->op) + { // The range is handled in an upper-level loop in iterate_successors + string_arena_add_string(sa_open, "%s%s int %s;\n", prefix, indent(nbopen), ld->alias); + } + else + { + string_arena_add_string(sa_open, "%s%s // do not declare '%s', it is a parametrized flow range\n", prefix, indent(nbopen), ld->alias); + } + if(JDF_RANGE == ld->op/* || JDF_PARAMETRIZED_FLOW_RANGE == ld->op*/) { string_arena_add_string(sa_open, "%s%sfor( %s = %s;", prefix, indent(nbopen), ld->alias, dump_expr((void**)ld->jdf_ta1, &local_info)); @@ -7356,13 +10209,43 @@ static char *jdf_dump_context_assignment(string_arena_t *sa_open, prefix, indent(nbopen), ld->ldef_index, ld->alias); nbopen++; } else { - string_arena_add_string(sa_open, + if(JDF_PARAMETRIZED_FLOW_RANGE == ld->op) + { + // We do not iterate over the parametrized flow because it is already being looped on in iterate_successors + string_arena_add_string(sa_open, + "%s%s "JDF2C_NAMESPACE"_tmp_locals.ldef[%d].value = %s;\n", + prefix, indent(nbopen), ld->ldef_index, ld->alias); + } + else + { + // string_arena_add_string(sa_open, + // "%s%sncc->locals.ldef[%d].value = %s = %s;\n", + // prefix, indent(nbopen), + // flow->local_variables->ldef_index, + // get_parametrized_flow_iterator_name(flow), dump_expr((void**)ld, &local_info)); + string_arena_add_string(sa_open, "%s%s "JDF2C_NAMESPACE"_tmp_locals.ldef[%d].value = %s = %s;\n", prefix, indent(nbopen), ld->ldef_index, ld->alias, dump_expr((void**)ld, &local_info)); + + // If the call is a referrer, keep the ldef up-to-date + if(CALL_IS_PARAMETRIZED(call) && !strcmp(call->parametrized_offset->alias, ld->alias)) + { + string_arena_add_string(sa_open, "%s%sncc->locals.ldef[%d].value = %s;\n", + prefix, indent(nbopen), + ld->ldef_index, + ld->alias); + } + } } } } + // Iterate if the flow is parametrized + /*dump_parametrized_flow_loop_if_parametrized(flow, " ", sa_open); + if(FLOW_IS_PARAMETRIZED(flow)) { + ++nbopen; + }*/ + for(vl = targetf->locals, i = 0; vl != NULL; vl = vl->next, i++) { for(el = call->parameters, nl = targetf->parameters; @@ -7416,12 +10299,19 @@ static char *jdf_dump_context_assignment(string_arena_t *sa_open, call_ld = jdf_expr_lv_next(call->local_defs, call_ld); continue; /* This local define was alredy issued above as part of the call */ } + if( variable_is_flow_level_util(flow, ld) ) + { + string_arena_add_string(sa_open, "%s%s// skipping local %s because belongs to the flow level\n", + prefix, indent(nbopen), ld->alias); + + continue; + } string_arena_add_string(sa_open, "%s%s {\n" - "%s%s int %s;\n", + "%s%s int %s; // TODO\n", prefix, indent(nbopen), prefix, indent(nbopen), ld->alias); nbopen++; - if(JDF_RANGE == ld->op) { + if(JDF_RANGE == ld->op || JDF_PARAMETRIZED_FLOW_RANGE == ld->op) { string_arena_add_string(sa_open, "%s%s for( %s = %s;", prefix, indent(nbopen), ld->alias, dump_expr((void**)ld->jdf_ta1, &local_info)); @@ -7603,6 +10493,58 @@ static void jdf_check_relatives( jdf_function_entry_t *f, jdf_dep_flags_t flow_t string_arena_init((SA_DATATYPE)); \ } +// Version if something is parametrized in the task class (then, we cannot use flow_dep_mask_out) +#define OUTPUT_PREV_DEPS_PARAMETRIZED(MASK_STR, SA_DATATYPE, SA_DEPS) \ + if( strlen(string_arena_get_string((SA_DEPS))) ) { \ + if( strlen(string_arena_get_string((SA_DATATYPE))) ) { \ + string_arena_add_string(sa_coutput, \ + " %s", \ + string_arena_get_string((SA_DATATYPE))); \ + } \ + string_arena_add_string(sa_coutput, \ + " if( action_mask & %s ) {\n" \ + " %s" \ + " }\n", \ + MASK_STR, string_arena_get_string((SA_DEPS))); \ + string_arena_init((SA_DEPS)); \ + string_arena_init((SA_DATATYPE)); \ + } + +char *dump_flow_offset_for_iterate_successors(string_arena_t *sa, const jdf_function_entry_t *f, const jdf_dataflow_t *flow, const jdf_call_t *call) +{ + string_arena_init(sa); + + // TODO: if flow can be computed at compile time (i.e. no parametrized flow declared before him) + + //jdf_function_entry_t *tarfetf = find_target_function(jdf, call->func_or_mem); + //jdf_flow_t *referred_flow = jdf_get_flow_by_name(f, call->flow); + if(FLOW_IS_PARAMETRIZED(flow)) + { + string_arena_add_string(sa, "spec_%s_%s.out_flow_offset_of%s%s_%s+%s", + jdf_basename, f->fname, call->parametrized_offset!=NULL?"_referrer":"", FLOW_IS_PARAMETRIZED(flow)?"_parametrized":"", JDF_OBJECT_ONAME(call), + get_parametrized_flow_iterator_name(flow)); + } + else + { + string_arena_add_string(sa, "spec_%s_%s.out_flow_offset_of%s%s_%s", + jdf_basename, f->fname, call->parametrized_offset!=NULL?"_referrer":"", FLOW_IS_PARAMETRIZED(flow)?"_parametrized":"", JDF_OBJECT_ONAME(call)); + } + + return string_arena_get_string(sa); +} + +char *dump_dep_offset_for_iterate_successors(string_arena_t *sa, const jdf_function_entry_t *f, const jdf_dataflow_t *flow, const jdf_call_t *call) +{ + string_arena_init(sa); + + // If the call is a referrer to a parametrized flow: + string_arena_add_string(sa, "spec_%s_%s.out_dep_offset_of%s%s_%s+%s", + jdf_basename, f->fname, call->parametrized_offset != NULL?"_referrer":"", FLOW_IS_PARAMETRIZED(flow)?"_parametrized":"", JDF_OBJECT_ONAME(call), call->parametrized_offset->alias); + + + return string_arena_get_string(sa); +} + static void jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, const jdf_function_entry_t *f, @@ -7615,6 +10557,7 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, string_arena_t *sa1 = string_arena_new(64); string_arena_t *sa2 = string_arena_new(64); string_arena_t *sa_ontask = string_arena_new(64); + string_arena_t *osa = string_arena_new(64); string_arena_t *sa_coutput = string_arena_new(1024); string_arena_t *sa_deps = string_arena_new(1024); string_arena_t *sa_datatype = string_arena_new(1024); @@ -7639,6 +10582,9 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, string_arena_t *sa_tmp_type_r = string_arena_new(256); string_arena_t *sa_temp_r = string_arena_new(1024); + string_arena_t *sa_flow_offset = string_arena_new(64); + string_arena_t *sa_dep_offset = string_arena_new(64); + int depnb, last_datatype_idx; assignment_info_t ai; expr_info_t info = EMPTY_EXPR_INFO; @@ -7654,7 +10600,7 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, ai.expr = NULL; coutput("static void\n" "%s(parsec_execution_stream_t *es, const %s *this_task,\n" - " uint32_t action_mask, parsec_ontask_function_t *ontask, void *ontask_arg)\n" + " parsec_dependency_t action_mask, parsec_ontask_function_t *ontask, void *ontask_arg)\n" "{\n" " const __parsec_%s_internal_taskpool_t *__parsec_tp = (const __parsec_%s_internal_taskpool_t*)this_task->taskpool;\n" " parsec_task_t nc; /* generic placeholder for locals */\n" @@ -7663,11 +10609,21 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, " int vpid_dst = -1, rank_src = 0, rank_dst = 0;\n" "%s" " (void)rank_src; (void)rank_dst; (void)__parsec_tp; (void)vpid_dst;\n", - name, parsec_get_name(jdf, f, "task_t"), + name, parsec_get_task_type_name(jdf, f), jdf_basename, jdf_basename, parsec_get_name(jdf, f, "parsec_assignment_t"), parsec_get_name(jdf, f, "parsec_assignment_t"), UTIL_DUMP_LIST(sa1, f->locals, next, dump_local_assignments, &ai, "", " ", "\n", "\n")); + + // If parametrized flows, this won't work on iterate_predecessors +#if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(f) && (flow_type & JDF_DEP_FLOW_IN)) + { + coutput(" parsec_fatal(\"%s is parametrized, parsec does not handle iterate_predecessors of parametrized flows yet\");\n", name); + coutput("}\n"); + return; + } +#endif /* defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) */ coutput(" data_repo_t *successor_repo; parsec_key_t successor_repo_key;"); @@ -7691,6 +10647,7 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, flowtomem = 0; depnb = 0; last_datatype_idx = -1; + string_arena_init(osa); string_arena_init(sa_coutput); string_arena_init(sa_deps); string_arena_init(sa_datatype); @@ -7704,9 +10661,16 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, string_arena_init(sa_type_r); nb_open_ldef = 0; + + dump_parametrized_flow_loop_if_parametrized(fl, " ", sa_coutput); + if(FLOW_IS_PARAMETRIZED(fl)) + { + nb_open_ldef++; + } + string_arena_add_string(sa_coutput, - " data.data = this_task->data._f_%s.data_out;\n", - fl->varname); + "%s data.data = this_task->data.%s.data_out;\n", + INDENTATION_IF_PARAMETRIZED(fl), DUMP_DATA_FIELD_NAME_IN_TASK(osa, fl)); for(dl = fl->deps; dl != NULL; dl = dl->next) { if( !(dl->dep_flags & flow_type) ) continue; @@ -7838,11 +10802,30 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, string_arena_add_string(sa_datatype," }\n"); string_arena_init(sa_ontask); - string_arena_add_string(sa_ontask, - "if( PARSEC_ITERATE_STOP == ontask(es, &nc, (const parsec_task_t *)this_task, &%s, &data, rank_src, rank_dst, vpid_dst," - " successor_repo, successor_repo_key, ontask_arg) )\n" - " return;\n", - JDF_OBJECT_ONAME(dl->guard->calltrue)); + + if(NULL != dl->guard->calltrue->parametrized_offset) + //if(NULL != dl->guard->calltrue->parametrized_offset || FLOW_IS_PARAMETRIZED(fl)) + { + jdf_call_t *call = dl->guard->calltrue; + // if call is parametrized + string_arena_add_string(sa_ontask, + "if( PARSEC_ITERATE_STOP == ontask(es, &nc, " + "(const parsec_task_t *)this_task, this_task->task_class->out[%s]" + "->dep_out[%s]" + ", &data, rank_src, rank_dst, vpid_dst," + " successor_repo, successor_repo_key, ontask_arg) )\n" + " return;\n", + dump_flow_offset_for_iterate_successors(sa_flow_offset, f, fl, call), + dump_dep_offset_for_iterate_successors(sa_dep_offset, f, fl, call)); + } + else + { + string_arena_add_string(sa_ontask, + "if( PARSEC_ITERATE_STOP == ontask(es, &nc, (const parsec_task_t *)this_task, &%s, &data, rank_src, rank_dst, vpid_dst," + " successor_repo, successor_repo_key, ontask_arg) )\n" + " return;\n", + JDF_OBJECT_ONAME(dl->guard->calltrue)); + } if( NULL != dl->local_defs ) { jdf_expr_t *ld; @@ -7850,7 +10833,7 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, assert(NULL != ld->alias); assert(-1 != ld->ldef_index); string_arena_add_string(sa_coutput, "%s int %s;\n", indent(nb_open_ldef), ld->alias); - if(JDF_RANGE == ld->op) { + if(JDF_RANGE == ld->op || JDF_PARAMETRIZED_FLOW_RANGE == ld->op) { string_arena_add_string(sa_coutput, "%s for( %s = %s;", indent(nb_open_ldef), ld->alias, dump_expr((void**)ld->jdf_ta1, &info)); @@ -7868,7 +10851,8 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, } } } - + + switch( dl->guard->guard_type ) { case JDF_GUARD_UNCONDITIONAL: if( NULL != dl->guard->calltrue->var) { @@ -7926,11 +10910,29 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, depnb++; string_arena_init(sa_ontask); - string_arena_add_string(sa_ontask, + + if(NULL != dl->guard->callfalse->parametrized_offset) + //if(NULL != dl->guard->callfalse->parametrized_offset || FLOW_IS_PARAMETRIZED(fl)) + { + jdf_call_t *call = dl->guard->callfalse; + string_arena_add_string(sa_ontask, + "if( PARSEC_ITERATE_STOP == ontask(es, &nc, " + "(const parsec_task_t *)this_task, this_task->task_class->out[%s]" + "->dep_out[%s]" + ", &data, rank_src, rank_dst, vpid_dst," + " successor_repo, successor_repo_key, ontask_arg) )\n" + " return;\n", + dump_flow_offset_for_iterate_successors(sa_flow_offset, f, fl, call), + dump_dep_offset_for_iterate_successors(sa_dep_offset, f, fl, call)); + } + else + { + string_arena_add_string(sa_ontask, "if( PARSEC_ITERATE_STOP == ontask(es, &nc, (const parsec_task_t *)this_task, &%s, &data, rank_src, rank_dst, vpid_dst," " successor_repo, successor_repo_key, ontask_arg) )\n" " return;\n", JDF_OBJECT_ONAME(dl->guard->callfalse)); + } if( NULL != dl->guard->callfalse->var ) { string_arena_add_string(sa_deps, @@ -7947,11 +10949,29 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, } else { depnb++; string_arena_init(sa_ontask); - string_arena_add_string(sa_ontask, + + if(NULL != dl->guard->callfalse->parametrized_offset) + //if(NULL != dl->guard->callfalse->parametrized_offset || FLOW_IS_PARAMETRIZED(fl)) + { + jdf_call_t *call = dl->guard->callfalse; + string_arena_add_string(sa_ontask, + "if( PARSEC_ITERATE_STOP == ontask(es, &nc, " + "(const parsec_task_t *)this_task, this_task->task_class->out[%s]" + "->dep_out[%s]" + ", &data, rank_src, rank_dst, vpid_dst," + " successor_repo, successor_repo_key, ontask_arg) )\n" + " return;\n", + dump_flow_offset_for_iterate_successors(sa_flow_offset, f, fl, call), + dump_dep_offset_for_iterate_successors(sa_dep_offset, f, fl, call)); + } + else + { + string_arena_add_string(sa_ontask, "if( PARSEC_ITERATE_STOP == ontask(es, &nc, (const parsec_task_t *)this_task, &%s, &data, rank_src, rank_dst, vpid_dst," " successor_repo, successor_repo_key, ontask_arg) )\n" " return;\n", JDF_OBJECT_ONAME(dl->guard->callfalse)); + } if( NULL != dl->guard->callfalse->var ) { flowempty = 0; @@ -7977,13 +10997,37 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, break; } depnb++; + /* Dump the previous dependencies */ - OUTPUT_PREV_DEPS((1U << dl->dep_index), sa_datatype, sa_deps); + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(f)) + { + // Get the action mask for this flow as a string + string_arena_t *sa_action_mask = string_arena_new(128); + + // The specific bit is 1<<(dynamic flow id)<<(specialization id) + string_arena_add_string(sa_action_mask, "(1<<(spec_%s_%s.flow_id_of_flow_of_%s_%s_for_%s + %s))", + jdf_basename, f->fname, jdf_basename, f->fname, fl->varname, + FLOW_IS_PARAMETRIZED(fl)?get_parametrized_flow_iterator_name(fl):"0" + ); + + + OUTPUT_PREV_DEPS_PARAMETRIZED(string_arena_get_string(sa_action_mask), sa_datatype, sa_deps); + + string_arena_free(sa_action_mask); + } + else + { + OUTPUT_PREV_DEPS((1U << dl->dep_index), sa_datatype, sa_deps); + } - while(nb_open_ldef > 0) { + while(nb_open_ldef > FLOW_IS_PARAMETRIZED(fl)?1:0) { // If the flow is parametrized, we need to keep the first { (corresponding to the parametrized flow iterator's loop) string_arena_add_string(sa_coutput, "%s }\n", indent(nb_open_ldef)); nb_open_ldef--; } + /*while(nb_open_ldef > 0) { // If the flow is parametrized, we need to keep the first { (corresponding to the parametrized flow iterator's loop) + string_arena_add_string(sa_coutput, "%s }\n", indent(nb_open_ldef)); + nb_open_ldef--; + }*/ } if( (1 == flowempty) && (0 == flowtomem) ) { @@ -7991,12 +11035,48 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, } else if( 1 == flowempty ) { coutput(" /* Flow of data %s has only OUTPUT dependencies to Memory */\n", fl->varname); } else { - coutput(" if( action_mask & 0x%x ) { /* Flow of data %s [%d] */\n" - "%s" - " }\n", - (flow_type & JDF_DEP_FLOW_OUT) ? fl->flow_dep_mask_out : fl->flow_dep_mask_in/*mask*/, fl->varname, fl->flow_index, - string_arena_get_string(sa_coutput)/*IFBODY*/); + + // Get the action mask for this flow as a string + string_arena_t *sa_action_mask = string_arena_new(128); + if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(f)) { + // dynamic masks if any flow/dep is parametrized + string_arena_add_string(sa_action_mask, "spec_%s.dep_mask_%s_of_flow_of_%s_%s_for_%s", + JDF_OBJECT_ONAME(f), + (flow_type & JDF_DEP_FLOW_OUT) ? "out" : "in", + jdf_basename, f->fname, fl->varname); + } + else + { + // static masks if no parametrization in this task class + string_arena_add_string(sa_action_mask, "0x%lxU", (flow_type & JDF_DEP_FLOW_OUT) ? fl->flow_dep_mask_out : fl->flow_dep_mask_in/*mask*/); + } + + if(FLOW_IS_PARAMETRIZED(fl)) { + string_arena_add_string(sa_coutput, " } // end of parametrized flow %s\n", fl->varname); + nb_open_ldef--; + } + assert(0 == nb_open_ldef); + + /*if(FLOW_IS_PARAMETRIZED(fl)) { + + } + else*/ + { + coutput(" if( action_mask & %s ) { /* Flow of data %s [%d] */\n" + "%s" + " }\n", + string_arena_get_string(sa_action_mask), fl->varname, fl->flow_index, + string_arena_get_string(sa_coutput)/*IFBODY*/); + } + /*if(TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(f)) { + coutput(" assert(spec_%s.dep_mask_out_of_flow_of_%s_%s_for_%s == 0x%x);\n", + JDF_OBJECT_ONAME(f), + jdf_basename, f->fname, fl->varname, + fl->flow_dep_mask_in); + }*/ + string_arena_free(sa_action_mask); } + } coutput(" (void)data;(void)nc;(void)es;(void)ontask;(void)ontask_arg;(void)rank_dst;(void)action_mask;\n"); coutput("}\n\n"); @@ -8004,6 +11084,7 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, string_arena_free(sa_ontask); string_arena_free(sa1); string_arena_free(sa2); + string_arena_free(osa); string_arena_free(sa_coutput); string_arena_free(sa_deps); string_arena_free(sa_datatype); @@ -8027,6 +11108,8 @@ jdf_generate_code_iterate_successors_or_predecessors(const jdf_t *jdf, string_arena_free(sa_tmp_type_r); string_arena_free(sa_temp_r); + string_arena_free(sa_flow_offset); + string_arena_free(sa_dep_offset); } /** diff --git a/parsec/interfaces/ptg/ptg-compiler/jdf2c_utils.h b/parsec/interfaces/ptg/ptg-compiler/jdf2c_utils.h index f30b4826a..ad4089941 100644 --- a/parsec/interfaces/ptg/ptg-compiler/jdf2c_utils.h +++ b/parsec/interfaces/ptg/ptg-compiler/jdf2c_utils.h @@ -5,6 +5,331 @@ typedef char *(*dumper_function_t)(void **elt, void *arg); + +/** + * FLOW_IS_PARAMETRIZED: + * Tells whether a flow is parametrized or not. + * @param [IN] flow: the flow to test. + * + * @return a boolean value. + */ +#define FLOW_IS_PARAMETRIZED(flow) \ + ((flow)->local_variables != NULL) + +/** + * GET_PARAMETRIZED_FLOW_ITERATOR_NAME + * @param flow: the flow from which to get the iterator + * + * Returns a string, the name of the iterator + */ +#define GET_PARAMETRIZED_FLOW_ITERATOR_NAME(flow) \ + get_parametrized_flow_iterator_name(flow) + +static inline char *get_parametrized_flow_iterator_name(jdf_dataflow_t const *flow) +{ + assert(FLOW_IS_PARAMETRIZED(flow)); + assert(flow->local_variables->next == NULL); // only one iterator for parametrized flows + + return flow->local_variables->alias; +} + +/** + * INDENTATION_IF_PARAMETRIZED: + * Returns an indentation string if the flow is parametrized. + * @param [IN] flow: said flow. + * + * @return a string containing an indentation if the flow is parametrized, an empty string otherwise. + */ +#define INDENTATION_IF_PARAMETRIZED(flow) \ + ((FLOW_IS_PARAMETRIZED(flow)) ? " " : "") + +/** + * DUMP_ARRAY_OFFSET_IF_PARAMETRIZED: + * Tells whether a flow is parametrized or not. + * @param [IN] sa: the string arena to use. + * @param [IN] flow: the flow to test. + * + * @return an empty string if not parametrized, [var] else (var being the name of the iterator variable). + */ +#define DUMP_ARRAY_OFFSET_IF_PARAMETRIZED(sa, flow) \ + util_dump_array_offset_if_parametrized(sa, flow) + +/** + * util_dump_array_offset_if_parametrized: + * function used by the DUMP_ARRAY_OFFSET_IF_PARAMETRIZED* macros. Do not use directly. + */ +static inline char* +util_dump_array_offset_if_parametrized(string_arena_t *sa, const jdf_dataflow_t *flow) +{ + // reinit sa + string_arena_init(sa); + + if (FLOW_IS_PARAMETRIZED(flow)) { + string_arena_add_string(sa, "[%s]", get_parametrized_flow_iterator_name(flow)); + } + + return string_arena_get_string(sa); +} + +/** + * @brief Dumps the proper access to the data, wether the flow is parametrized or not + * + */ +#define DUMP_DATA_FIELD_NAME_IN_TASK(sa, flow)\ + util_dump_data_field_name_in_task(sa, flow) + +static inline char *util_dump_data_field_name_in_task(string_arena_t *sa, const jdf_dataflow_t *flow) +{ + string_arena_init(sa); + + if( FLOW_IS_PARAMETRIZED(flow) ) { + string_arena_add_string(sa, "parametrized__f_%s(%s)", flow->varname, get_parametrized_flow_iterator_name(flow)); + } else { + string_arena_add_string(sa, "_f_%s", flow->varname); + } + + return string_arena_get_string(sa); +} + +/** + * @brief Dumps the flow_id's variable (when the task class has a parametrized flow or a referrer) + * + */ +#define DUMP_FLOW_ID_VARIABLE(sa, jdf_basename, function, flow)\ + util_dump_flow_id_variable(sa, jdf_basename, function, flow) + +static inline char *util_dump_flow_id_variable(string_arena_t *sa, const char *jdf_basename, const jdf_function_entry_t *function, const jdf_dataflow_t *flow) +{ + string_arena_init(sa); + + // // if(flow->flow_flags & JDF_FLOW_TYPE_WRITE) + // // { + // string_arena_add_string(sa, "(spec_%s.flow_id_of_flow_of_%s_%s_for_%s + %s)", + // JDF_OBJECT_ONAME(function), jdf_basename, function->fname, flow->varname, get_parametrized_flow_iterator_name(flow)); + // // } + // // else + // // { + // // string_arena_add_string(sa, "DUNNO_HOW_TO_GET_ACTION_MASK_FOR_THIS_FLOW"); + // // } + + if( FLOW_IS_PARAMETRIZED(flow) ) { + string_arena_add_string(sa, "(spec_%s.flow_id_of_flow_of_%s_%s_for_%s + %s)", + JDF_OBJECT_ONAME(function), jdf_basename, function->fname, flow->varname, get_parametrized_flow_iterator_name(flow)); + } + else { + string_arena_add_string(sa, "spec_%s.flow_id_of_flow_of_%s_%s_for_%s", + JDF_OBJECT_ONAME(function), jdf_basename, function->fname, flow->varname); + } + + return string_arena_get_string(sa); +} + +/** + * @brief Dumps an expression that gives the number of flows in a task class, including each specialization of a parametrized flow + * + */ +#define DUMP_NUMBER_OF_FLOWS_IN_TASK_CLASS(sa, jdf_basename, function)\ + util_dump_number_of_flows_in_task_class(sa, jdf_basename, function) + +static inline char *util_dump_number_of_flows_in_task_class(string_arena_t *sa, const char *jdf_basename, const jdf_function_entry_t *function) +{ + string_arena_init(sa); + + string_arena_add_string(sa, "("); + + // For each flow + for(jdf_dataflow_t *flow = function->dataflow; flow != NULL; flow = flow->next) { + if( FLOW_IS_PARAMETRIZED(flow) ) { + string_arena_add_string(sa, " + spec_%s.nb_specializations_of_parametrized_flow_of_%s_%s_for_%s", + JDF_OBJECT_ONAME(function), jdf_basename, function->fname, flow->varname); + } else { + string_arena_add_string(sa, " + 1"); + } + } + + string_arena_add_string(sa, ")"); + + return string_arena_get_string(sa); +} + +/** + * VARIABLE_IS_FLOW_LEVEL + * Tells whether a variable is a flow level variable or not. + * @param [IN] var: the variable to test. + * @param [IN] flow: the flow to test. + * + * @return a boolean value. + */ +#define VARIABLE_IS_FLOW_LEVEL(flow, var) \ + variable_is_flow_level_util(flow, var) + +static inline int variable_is_flow_level_util(const jdf_dataflow_t *flow, const jdf_expr_t *var) +{ + for(jdf_expr_t *flow_variable=flow->local_variables; flow_variable!=NULL; flow_variable=flow_variable->next) { + if (strcmp(flow_variable->alias, var->alias) == 0) { + return 1; + } + } + + return 0; +} + +/** + * JDF_ANY_FLOW_IS_PARAMETRIZED: + * Tells whether any flow is parametrized or not. + * Used to avoid code overloading if no paramtrized flow is present. + * @param [IN] jdf: the jdf to test. + * + * @return a boolean value. + */ +#define JDF_ANY_FLOW_IS_PARAMETRIZED(jdf) \ + jdf_any_flow_is_parametrized_util(jdf) + +static inline int jdf_any_flow_is_parametrized_util(const jdf_t *jdf) +{ + for( jdf_function_entry_t* f = jdf->functions; NULL != f; f = f->next ) { + for( jdf_dataflow_t* df = f->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + return 1; + } + } + } + + return 0; +} + +/** + * CALL_IS_PARAMETRIZED: + * + * Tells whether a call is parametrized or not. + * + * @param [IN] call: the call to test. + * + * @return a boolean value. + */ +#define CALL_IS_PARAMETRIZED(call) \ + call_is_parametrized_util(call) + +static inline int call_is_parametrized_util(const jdf_call_t *call) +{ + return NULL != call->parametrized_offset; +} + +/** + * FLOW_ANY_DEP_IS_REFERRER + * + * Tells whether any dependency of a flow is a referrer. + * + * @param [IN] flow: the flow to test. + * + * @return a boolean value. + */ +#define FLOW_ANY_DEP_IS_REFERRER(flow) \ + flow_any_dep_is_referrer_util(flow) + +static inline int flow_any_dep_is_referrer_util(const jdf_dataflow_t *flow) +{ + for( jdf_dep_t *dep = flow->deps; NULL != dep; dep = dep->next ) { + for( int target_call=0; target_call<2; ++target_call ) { + assert(dep->guard->guard_type==JDF_GUARD_UNCONDITIONAL || dep->guard->guard_type==JDF_GUARD_BINARY || dep->guard->guard_type==JDF_GUARD_TERNARY); + if(dep->guard->guard_type!=JDF_GUARD_TERNARY && target_call==1) + { // callfalse is only relevant for JDF_GUARD_UNCONDITIONAL and JDF_GUARD_BINARY + continue; + } + jdf_call_t *call = target_call?dep->guard->callfalse:dep->guard->calltrue; + assert(call); + + if( CALL_IS_PARAMETRIZED(call) ) + { + return 1; + } + } + } + + return 0; +} + +/** + * FLOW_IS_PARAMETRIZED_OR_ANY_DEP_IS_REFERRER + * + * Tells whether a flow is parametrized or not, or if any of its dependencies is a referrer. + * + * @param [IN] flow: the flow to test. + * + * @return a boolean value. + */ +#define FLOW_IS_PARAMETRIZED_OR_ANY_DEP_IS_REFERRER(flow) \ + flow_is_parametrized_or_any_dep_is_referrer_util(flow) + +static inline int flow_is_parametrized_or_any_dep_is_referrer_util(const jdf_dataflow_t *flow) +{ + return FLOW_IS_PARAMETRIZED(flow) || FLOW_ANY_DEP_IS_REFERRER(flow); +} + +/** + * TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER: + * Tells whether any flow is parametrized or if one of the deps is a referrer. + * + * @param [IN] tc: the task class to test. + * + * @return a boolean value. + */ +#define TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED_OR_REFERRER(tc) \ + task_class_any_flow_is_parametrized_or_referrer_util(tc) + +static inline int task_class_any_flow_is_parametrized_or_referrer_util(const jdf_function_entry_t *tc) +{ + for( jdf_dataflow_t* df = tc->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED_OR_ANY_DEP_IS_REFERRER(df) ) { + return 1; + } + } + + return 0; +} + +/** + * TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED + * Tells whether any flow is parametrized + * + * @param [IN] tc: the task class to test. + * + * @return a boolean value. + */ +#define TASK_CLASS_ANY_FLOW_IS_PARAMETRIZED(tc) \ + task_class_any_flow_is_parametrized_util(tc) + +static inline int task_class_any_flow_is_parametrized_util(const jdf_function_entry_t *tc) +{ + for( jdf_dataflow_t* df = tc->dataflow; NULL != df; df = df->next ) { + if( FLOW_IS_PARAMETRIZED(df) ) { + return 1; + } + } + + return 0; +} + + +/** + * STRING_IS_IN: + * Tells whether a string is in a list of strings. + * + */ +#define STRING_IS_IN(string, arr, arr_size) \ + string_is_in_util(string, arr, arr_size) + +static inline int string_is_in_util(const char *string, const char **arr, int arr_size) +{ + for( int i=0; ilocal_variable %type local_variables %type partitioning +%type flow_specifier %type dataflow_list %type dataflow %type named_expr %type named_expr_list +%type array_offset +%type named_array_offset_or_nothing %type dependencies %type dependency %type guarded_call @@ -641,17 +645,18 @@ simulation_cost: | { $$ = NULL; } ; -partitioning: COLON VAR OPEN_PAR expr_list CLOSE_PAR +partitioning: COLON VAR { named_expr_push_scope(); } named_array_offset_or_nothing OPEN_PAR expr_list CLOSE_PAR { jdf_data_entry_t* data; jdf_call_t *c = new(jdf_call_t); int nbparams; c->var = NULL; + c->parametrized_offset = $4; c->func_or_mem = $2; data = jdf_find_or_create_data(¤t_jdf, $2); - c->parameters = $4; - JDF_COUNT_LIST_ENTRIES($4, jdf_expr_t, next, nbparams); + c->parameters = $6; + JDF_COUNT_LIST_ENTRIES($6, jdf_expr_t, next, nbparams); if( data->nbparams != -1 ) { if( data->nbparams != nbparams ) { jdf_fatal(current_lineno, "Data %s used with %d parameters at line %d while used with %d parameters line %d\n", @@ -662,7 +667,8 @@ partitioning: COLON VAR OPEN_PAR expr_list CLOSE_PAR data->nbparams = nbparams; } $$ = c; - JDF_OBJECT_LINENO($$) = JDF_OBJECT_LINENO($4); + JDF_OBJECT_LINENO($$) = JDF_OBJECT_LINENO($6); + named_expr_pop_scope(); } ; @@ -685,7 +691,47 @@ optional_flow_flags : | { $$ = JDF_FLOW_TYPE_READ | JDF_FLOW_TYPE_WRITE; } ; -dataflow: optional_flow_flags VAR dependencies +/* +PROPERTIES_ON { named_expr_push_scope(); } named_expr_list PROPERTIES_OFF expr_simple + { + $$ = $5; + named_expr_pop_scope(); + } +*/ + +flow_specifier: { named_expr_push_scope(); } array_offset + { + jdf_flow_specifier_t *f = new(jdf_flow_specifier_t); + f->variables = $2; + if( NULL != f->variables->next ) { + // We can only handle parametrized flow with one variable + jdf_fatal(current_lineno, "Flow %s cannot have more than one variable\n", f->variables->alias); + YYERROR; + } + if( JDF_RANGE != f->variables->op ) { + // Parametrized flows must have a range + jdf_fatal(current_lineno, "Flow %s must be a range\n", f->variables->alias); + YYERROR; + } + f->variables->op = JDF_PARAMETRIZED_FLOW_RANGE; // Ranges in parametrized flows are treated differently + $$ = f; + + //named_expr_pop_scope(); + } + | + { + jdf_flow_specifier_t *f = new(jdf_flow_specifier_t); + f->variables = NULL; + $$ = f; + + /* We still create a new scope for the (inexisting) named range + * as the scope will be popped unconditionally */ + named_expr_push_scope(); + //named_expr_pop_scope(); + } + ; + +dataflow: optional_flow_flags VAR flow_specifier dependencies { named_expr_pop_scope(); } { for(jdf_global_entry_t* g = current_jdf.globals; g != NULL; g = g->next) { if( !strcmp(g->name, $2) ) { @@ -695,16 +741,19 @@ dataflow: optional_flow_flags VAR dependencies } } + jdf_flow_specifier_t *flow_specifier = $3; + jdf_dataflow_t *flow = new(jdf_dataflow_t); flow->flow_flags = $1; flow->varname = $2; - flow->deps = $3; + flow->local_variables = flow_specifier->variables; + flow->deps = $4; $$ = flow; - if( NULL == $3) { + if( NULL == $4) { JDF_OBJECT_LINENO($$) = current_lineno; } else { - JDF_OBJECT_LINENO($$) = JDF_OBJECT_LINENO($3); + JDF_OBJECT_LINENO($$) = JDF_OBJECT_LINENO($4); } } ; @@ -732,6 +781,42 @@ named_expr_list: VAR ASSIGNMENT expr_range } ; +named_array_offset_or_nothing: array_offset + { + $$ = $1; + } + | { + $$ = NULL; + } + ; + +/* +array_offset_or_nothing: array_offset + { + $$ = $1; + } + | { + $$ = NULL; + } + ; +*/ + +array_offset: PROPERTIES_ON named_expr_list PROPERTIES_OFF + { +#if !defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) + jdf_fatal(current_lineno, "Flow cannot be parametrized (line %d). Set the PARSEC_ALLOW_PARAMETRIZED_FLOWS flag to enable them.\n", + JDF_OBJECT_LINENO($2)); + YYERROR; +#endif + + $$ = $2; + } + /*| + { + $$ = NULL; + }*/ + ; + dependencies: dependency dependencies { $1->next = $2; @@ -754,6 +839,8 @@ dependency: ARROW named_expr guarded_call properties jdf_def_list_t* property_data = $4; d->local_defs = $2; + // Add the local definitions of the previous scope (the iterator of the parametrized flow if any) + expr = jdf_find_property($4, "type", &property); expr_remote = jdf_find_property($4, "type_remote", &property_remote); @@ -865,6 +952,7 @@ guarded_call: call jdf_guarded_call_t *g = new(jdf_guarded_call_t); g->guard_type = JDF_GUARD_UNCONDITIONAL; g->guard = NULL; + //g->guard = ($1->calltrue->parametrized_offset); // NULL if not a referrer of a parametrized flow g->calltrue = $1; g->callfalse = NULL; $$ = g; @@ -878,6 +966,26 @@ guarded_call: call g->guard = $1; g->calltrue = $3; g->callfalse = NULL; + /*if(g->calltrue->parametrized_offset) // wrong approach, we work in jdf2c to fix the parametrized conds + { + // goal: cond -> (iterator == expr) && cond + + jdf_expr_t *iterator = malloc(sizeof(jdf_expr)); + memcpy(iterator, g->calltrue->parametrized_offset, sizeof(jdf_expr)); + iterator->op = JDF_CST; + + jdf_expr_t *equal_expr = malloc(sizeof(jdf_expr)); + equal_expr->op = JDF_EQ; + equal_expr->jdf_ba1 = iterator; + equal_expr->jdf_ba2 = g->calltrue->parametrized_offset->jdf_ba1; + + jdf_expr_t *and_expr = malloc(sizeof(jdf_expr)); + and_expr->op = JDF_AND; + and_expr->jdf_ba1 = equal_expr; + and_expr->jdf_ba2 = $1; + + g->guard = and_expr; + }*/ $$ = g; assert( 0 != JDF_OBJECT_LINENO($1) ); JDF_OBJECT_LINENO($$) = JDF_OBJECT_LINENO($1); @@ -895,33 +1003,35 @@ guarded_call: call } ; -call: named_expr VAR VAR OPEN_PAR expr_list_range CLOSE_PAR +call: named_expr VAR named_array_offset_or_nothing VAR OPEN_PAR expr_list_range CLOSE_PAR { jdf_call_t *c = new(jdf_call_t); c->var = $2; - c->local_defs = $1; - c->func_or_mem = $3; - c->parameters = $5; + c->parametrized_offset = $3; + c->local_defs = $3?$3:$1; // If we want local_defs to contain the parametrized_offset, we need to indicate $3 and not $1 + + c->func_or_mem = $4; + c->parameters = $6; $$ = c; - JDF_OBJECT_LINENO($$) = JDF_OBJECT_LINENO($5); + JDF_OBJECT_LINENO($$) = JDF_OBJECT_LINENO($6); assert( 0 != JDF_OBJECT_LINENO($$) ); named_expr_pop_scope(); } - | VAR OPEN_PAR expr_list_range CLOSE_PAR + | VAR { named_expr_push_scope(); } named_array_offset_or_nothing OPEN_PAR expr_list_range CLOSE_PAR { jdf_data_entry_t* data; jdf_call_t *c = new(jdf_call_t); int nbparams; c->var = NULL; + c->parametrized_offset = c->local_defs = $3; c->func_or_mem = $1; - c->parameters = $3; - c->local_defs = NULL; - JDF_OBJECT_LINENO(c) = JDF_OBJECT_LINENO($3); + c->parameters = $5; + JDF_OBJECT_LINENO(c) = JDF_OBJECT_LINENO($5); $$ = c; assert( 0 != JDF_OBJECT_LINENO($$) ); data = jdf_find_or_create_data(¤t_jdf, $1); - JDF_COUNT_LIST_ENTRIES($3, jdf_expr_t, next, nbparams); + JDF_COUNT_LIST_ENTRIES($5, jdf_expr_t, next, nbparams); if( data->nbparams != -1 ) { if( data->nbparams != nbparams ) { jdf_fatal(current_lineno, "Data %s used with %d parameters at line %d while used with %d parameters line %d\n", @@ -931,12 +1041,14 @@ call: named_expr VAR VAR OPEN_PAR expr_list_range CLOSE_PAR } else { data->nbparams = nbparams; } - JDF_OBJECT_LINENO(data) = JDF_OBJECT_LINENO($3); + JDF_OBJECT_LINENO(data) = JDF_OBJECT_LINENO($5); + named_expr_pop_scope(); } | DATA_NEW { jdf_call_t *c = new(jdf_call_t); c->var = NULL; + c->parametrized_offset = NULL; c->local_defs = NULL; c->func_or_mem = strdup(PARSEC_WRITE_MAGIC_NAME); c->parameters = NULL; @@ -947,6 +1059,7 @@ call: named_expr VAR VAR OPEN_PAR expr_list_range CLOSE_PAR { jdf_call_t *c = new(jdf_call_t); c->var = NULL; + c->parametrized_offset = NULL; c->local_defs = NULL; c->func_or_mem = strdup(PARSEC_NULL_MAGIC_NAME); c->parameters = NULL; diff --git a/parsec/mca/device/device.c b/parsec/mca/device/device.c index a8d7e326d..9836ca8cd 100644 --- a/parsec/mca/device/device.c +++ b/parsec/mca/device/device.c @@ -109,6 +109,7 @@ int parsec_get_best_device( parsec_task_t* this_task, double ratio ) /* If we reach here, we cannot yet decide which device to run on based on the WRITE * constraints, so let's pick the data for a READ flow. */ + if(!this_task->task_class->in[i]) break; data_index = this_task->task_class->in[i]->flow_index; if( this_task->data[data_index].data_in->original->preferred_device > 1 ) { prefer_index = this_task->data[data_index].data_in->original->preferred_device; diff --git a/parsec/mca/device/transfer_gpu.c b/parsec/mca/device/transfer_gpu.c index 1ad93fa9b..fbcb8cc95 100644 --- a/parsec/mca/device/transfer_gpu.c +++ b/parsec/mca/device/transfer_gpu.c @@ -52,7 +52,7 @@ affinity_of_gpu_d2h_task( parsec_gpu_d2h_task_t* this_task, static void iterate_successors_of_gpu_d2h_task( parsec_execution_stream_t* es, const parsec_gpu_d2h_task_t* this_task, - uint32_t action_mask, + parsec_dependency_t action_mask, parsec_ontask_function_t * ontask, void *ontask_arg ) { (void)es; (void)this_task; (void)action_mask; (void)ontask; (void)ontask_arg; @@ -61,7 +61,7 @@ iterate_successors_of_gpu_d2h_task( parsec_execution_stream_t* es, static void iterate_predecessors_of_gpu_d2h_task( parsec_execution_stream_t* es, const parsec_gpu_d2h_task_t* this_task, - uint32_t action_mask, + parsec_dependency_t action_mask, parsec_ontask_function_t * ontask, void *ontask_arg ) { (void)es; (void)this_task; (void)action_mask; (void)ontask; (void)ontask_arg; @@ -70,7 +70,7 @@ iterate_predecessors_of_gpu_d2h_task( parsec_execution_stream_t* es, static int release_deps_of_gpu_d2h_task( parsec_execution_stream_t* es, parsec_gpu_d2h_task_t* this_task, - uint32_t action_mask, + parsec_dependency_t action_mask, parsec_remote_deps_t* deps ) { (void)es; (void)this_task; (void)action_mask; (void)deps; diff --git a/parsec/parsec.c b/parsec/parsec.c index 186330f6c..1aed713bf 100644 --- a/parsec/parsec.c +++ b/parsec/parsec.c @@ -1390,6 +1390,10 @@ parsec_check_IN_dependencies_with_mask(const parsec_taskpool_t *tp, active = (1 << flow->flow_index); } break; + /* + active = (1 << flow->flow_index); + assert( PARSEC_LOCAL_DATA_TASK_CLASS_ID == dep->task_class_id ); + */ } } } @@ -1579,12 +1583,12 @@ parsec_update_deps_with_counter(parsec_taskpool_t *tp, if( 0 == *deps ) { dep_new_value = parsec_check_IN_dependencies_with_counter(tp, task) - 1; - if( parsec_atomic_cas_int32( deps, 0, dep_new_value ) == 1 ) + if( parsec_atomic_cas_int64( deps, 0, dep_new_value ) == 1 ) dep_cur_value = dep_new_value; else - dep_cur_value = parsec_atomic_fetch_dec_int32( deps ) - 1; + dep_cur_value = parsec_atomic_fetch_dec_int64( deps ) - 1; } else { - dep_cur_value = parsec_atomic_fetch_dec_int32( deps ) - 1; + dep_cur_value = parsec_atomic_fetch_dec_int64( deps ) - 1; } PARSEC_DEBUG_VERBOSE(10, parsec_debug_output, "Activate counter dependency for %s leftover %d (excluding current)", tmp, dep_cur_value); @@ -1626,14 +1630,14 @@ parsec_update_deps_with_counter_count_task(parsec_taskpool_t *tp, if( 0 == *deps ) { dep_new_value = parsec_check_IN_dependencies_with_counter(tp, task) - 1; - if( parsec_atomic_cas_int32( deps, 0, dep_new_value ) == 1 ) { + if( parsec_atomic_cas_int64( deps, 0, dep_new_value ) == 1 ) { dep_cur_value = dep_new_value; tp->tdm.module->taskpool_addto_nb_tasks(tp, 1); } else { - dep_cur_value = parsec_atomic_fetch_dec_int32( deps ) - 1; + dep_cur_value = parsec_atomic_fetch_dec_int64( deps ) - 1; } } else { - dep_cur_value = parsec_atomic_fetch_dec_int32( deps ) - 1; + dep_cur_value = parsec_atomic_fetch_dec_int64( deps ) - 1; } PARSEC_DEBUG_VERBOSE(10, parsec_debug_output, "Activate counter dependency for %s leftover %d (excluding current)", tmp, dep_cur_value); @@ -1698,14 +1702,14 @@ parsec_update_deps_with_mask(parsec_taskpool_t *tp, #endif } - dep_cur_value = parsec_atomic_fetch_or_int32( deps, dep_new_value ) | dep_new_value; + dep_cur_value = parsec_atomic_fetch_or_int64( deps, dep_new_value ) | dep_new_value; #if defined(PARSEC_DEBUG_PARANOID) if( (dep_cur_value & tc->dependencies_goal) == tc->dependencies_goal ) { int success; parsec_dependency_t tmp_mask; tmp_mask = *deps; - success = parsec_atomic_cas_int32(deps, + success = parsec_atomic_cas_int64(deps, tmp_mask, (tmp_mask | PARSEC_DEPENDENCIES_TASK_DONE)); if( !success || (tmp_mask & PARSEC_DEPENDENCIES_TASK_DONE) ) { parsec_fatal("Task %s scheduled twice (second time by %s)!!!", @@ -1764,7 +1768,7 @@ parsec_update_deps_with_mask_count_task(parsec_taskpool_t *tp, #endif } - dep_cur_value = parsec_atomic_fetch_or_int32( deps, dep_new_value ) | dep_new_value; + dep_cur_value = parsec_atomic_fetch_or_int64( deps, dep_new_value ) | dep_new_value; if( (dep_cur_value & (~dep_new_value)) == 0 ) { tp->tdm.module->taskpool_addto_nb_tasks(tp, 1); } else { @@ -1776,7 +1780,7 @@ parsec_update_deps_with_mask_count_task(parsec_taskpool_t *tp, int success; parsec_dependency_t tmp_mask; tmp_mask = *deps; - success = parsec_atomic_cas_int32(deps, + success = parsec_atomic_cas_int64(deps, tmp_mask, (tmp_mask | PARSEC_DEPENDENCIES_TASK_DONE)); if( !success || (tmp_mask & PARSEC_DEPENDENCIES_TASK_DONE) ) { parsec_fatal("Task %s scheduled twice (second time by %s)!!!", diff --git a/parsec/parsec_internal.h b/parsec/parsec_internal.h index 3beb1310f..2638e5690 100644 --- a/parsec/parsec_internal.h +++ b/parsec/parsec_internal.h @@ -144,7 +144,7 @@ struct parsec_taskpool_s { parsec_context_t* context; /**< The PaRSEC context on which this taskpool was enqueued */ parsec_termdet_monitor_t tdm; /**< Termination detection structures and pointer to module */ parsec_startup_fn_t startup_hook; /**< Pointer to the function that generates initial tasks */ - const parsec_task_class_t** task_classes_array; /**< Array of task classes that build this DAG */ + parsec_task_class_t** task_classes_array; /**< Array of task classes that build this DAG */ #if defined(PARSEC_PROF_TRACE) const int* profiling_array; /**< Array of profiling keys to start/stop each of the task classes * The array is indexed on the same index as task_classes_array */ @@ -238,7 +238,7 @@ typedef enum { typedef int (parsec_release_deps_t)(struct parsec_execution_stream_s*, parsec_task_t*, - uint32_t, + parsec_dependency_t, parsec_remote_deps_t*); #if defined(PARSEC_SIM) typedef int (parsec_sim_cost_fct_t)(const parsec_task_t *task); @@ -260,7 +260,7 @@ typedef parsec_ontask_iterate_t (parsec_ontask_function_t)(struct parsec_executi */ typedef void (parsec_traverse_function_t)(struct parsec_execution_stream_s *, const parsec_task_t *, - uint32_t, + parsec_dependency_t, parsec_ontask_function_t *, void *); @@ -405,8 +405,8 @@ struct parsec_task_class_s { parsec_dependency_t dependencies_goal; const parsec_symbol_t *params[MAX_LOCAL_COUNT]; const parsec_symbol_t *locals[MAX_LOCAL_COUNT]; - const parsec_flow_t *in[MAX_PARAM_COUNT]; - const parsec_flow_t *out[MAX_PARAM_COUNT]; + const parsec_flow_t *in[MAX_DATAFLOWS_PER_TASK]; + const parsec_flow_t *out[MAX_DATAFLOWS_PER_TASK]; const parsec_expr_t *priority; const parsec_property_t *properties; /**< {NULL, NULL} terminated array of properties holding all function-specific properties expressions */ @@ -578,7 +578,7 @@ extern int device_delegate_begin, device_delegate_end; * Dependencies management. */ typedef struct { - uint32_t action_mask; + parsec_dependency_t action_mask; uint32_t output_usage; data_repo_entry_t *output_entry; /* Current task repo entry */ data_repo_t *output_repo; /* Current task repo */ diff --git a/parsec/remote_dep.h b/parsec/remote_dep.h index b42699a1d..4e070947c 100644 --- a/parsec/remote_dep.h +++ b/parsec/remote_dep.h @@ -27,15 +27,15 @@ typedef union dep_cmd_u dep_cmd_t; typedef unsigned long remote_dep_datakey_t; -#define PARSEC_ACTION_DEPS_MASK 0x00FFFFFF -#define PARSEC_ACTION_RELEASE_LOCAL_DEPS 0x01000000 -#define PARSEC_ACTION_RELEASE_LOCAL_REFS 0x02000000 -#define PARSEC_ACTION_GET_REPO_ENTRY 0x04000000 -#define PARSEC_ACTION_RESHAPE_ON_RELEASE 0x08000000 -#define PARSEC_ACTION_SEND_INIT_REMOTE_DEPS 0x10000000 -#define PARSEC_ACTION_SEND_REMOTE_DEPS 0x20000000 -#define PARSEC_ACTION_RECV_INIT_REMOTE_DEPS 0x40000000 -#define PARSEC_ACTION_RESHAPE_REMOTE_ON_RELEASE 0x80000000 +#define PARSEC_ACTION_DEPS_MASK 0x00FFFFFFFFFFFFFF +#define PARSEC_ACTION_RELEASE_LOCAL_DEPS 0x0100000000000000 +#define PARSEC_ACTION_RELEASE_LOCAL_REFS 0x0200000000000000 +#define PARSEC_ACTION_GET_REPO_ENTRY 0x0400000000000000 +#define PARSEC_ACTION_RESHAPE_ON_RELEASE 0x0800000000000000 +#define PARSEC_ACTION_SEND_INIT_REMOTE_DEPS 0x1000000000000000 +#define PARSEC_ACTION_SEND_REMOTE_DEPS 0x2000000000000000 +#define PARSEC_ACTION_RECV_INIT_REMOTE_DEPS 0x4000000000000000 +#define PARSEC_ACTION_RESHAPE_REMOTE_ON_RELEASE 0x8000000000000000 #define PARSEC_ACTION_RELEASE_REMOTE_DEPS (PARSEC_ACTION_SEND_INIT_REMOTE_DEPS | PARSEC_ACTION_SEND_REMOTE_DEPS) typedef enum { diff --git a/parsec/task_class.c b/parsec/task_class.c new file mode 100644 index 000000000..4f03164f1 --- /dev/null +++ b/parsec/task_class.c @@ -0,0 +1,744 @@ +/* + * Copyright (c) 2012-2019 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + */ + +#include "parsec/task_class.h" + +// Reminder: definitions: + +// /** +// * @brief Opaque structure representing a Task Class +// */ +// typedef struct parsec_task_class_s parsec_task_class_t; + +// typedef struct parsec_flow_s parsec_flow_t; +// typedef struct parsec_dep_s parsec_dep_t; + +// struct parsec_task_class_s { +// const char *name; + +// uint16_t flags; +// uint8_t task_class_id; /**< index in the dependency and in the function array */ + +// uint8_t nb_flows; +// uint8_t nb_parameters; +// uint8_t nb_locals; + +// uint8_t task_class_type; + +// parsec_dependency_t dependencies_goal; +// const parsec_symbol_t *params[MAX_LOCAL_COUNT]; +// const parsec_symbol_t *locals[MAX_LOCAL_COUNT]; +// const parsec_flow_t *in[MAX_DATAFLOWS_PER_TASK]; +// const parsec_flow_t *out[MAX_DATAFLOWS_PER_TASK]; +// const parsec_expr_t *priority; +// const parsec_property_t *properties; /**< {NULL, NULL} terminated array of properties holding all function-specific properties expressions */ + +// parsec_data_ref_fn_t *initial_data; /**< Populates an array of data references, of maximal size MAX_PARAM_COUNT */ +// parsec_data_ref_fn_t *final_data; /**< Populates an array of data references, of maximal size MAX_PARAM_COUNT */ +// parsec_data_ref_fn_t *data_affinity; /**< Populates an array of data references, of size 1 */ +// parsec_key_fn_t *key_functions; +// parsec_functionkey_fn_t *make_key; +// parsec_printtask_fn_t *task_snprintf; +// #if defined(PARSEC_SIM) +// parsec_sim_cost_fct_t *sim_cost_fct; +// #endif +// parsec_datatype_lookup_t *get_datatype; +// parsec_hook_t *prepare_input; +// const __parsec_chore_t *incarnations; +// parsec_hook_t *prepare_output; + +// parsec_find_dependency_fn_t *find_deps; +// parsec_update_dependency_fn_t *update_deps; + +// parsec_traverse_function_t *iterate_successors; +// parsec_traverse_function_t *iterate_predecessors; +// parsec_release_deps_t *release_deps; +// parsec_hook_t *complete_execution; +// parsec_new_task_function_t *new_task; +// parsec_hook_t *release_task; +// parsec_hook_t *fini; +// }; + +// struct parsec_flow_s { +// char *name; +// uint8_t sym_type; +// uint8_t flow_flags; +// uint8_t flow_index; /**< The input index of the flow. This index is used +// * while computing the mask. */ +// parsec_dependency_t flow_datatype_mask; /**< The bitmask of dep_datatype_index of all deps */ + +// // if parametrized flows, we need to be able to modify dep indices +// #if defined(PARSEC_ALLOW_PARAMETRIZED_FLOWS) +// parsec_dep_t *dep_in[MAX_DEP_IN_COUNT]; +// parsec_dep_t *dep_out[MAX_DEP_OUT_COUNT]; +// #else +// parsec_dep_t const *dep_in[MAX_DEP_IN_COUNT]; +// parsec_dep_t const *dep_out[MAX_DEP_OUT_COUNT]; +// #endif +// }; + +// struct parsec_dep_s { +// parsec_expr_t const *cond; /**< The runtime-evaluable condition on this dependency */ +// parsec_expr_t const *ctl_gather_nb; /**< In case of control gather, the runtime-evaluable number of controls to expect */ +// uint8_t task_class_id; /**< Index of the target parsec function in the object function array */ +// uint8_t dep_index; /**< Output index of the dependency. This is used to store the flow +// * before transfering it to the successors. */ +// uint8_t dep_datatype_index; /**< Index of the output datatype. */ +// parsec_flow_t const *flow; /**< Pointer to the flow pointed to/from this dependency */ +// parsec_flow_t const *belongs_to; /**< The flow this dependency belongs tp */ +// parsec_data_lookup_func_t direct_data; /**< Lookup the data associated with this dep, if (and only if) +// * this dep is a direct memory access */ +// }; + +bool parsec_helper_flow_is_in_flow_array(const parsec_flow_t *flow, parsec_flow_t *flow_array[], int flow_array_size) +{ + for (int i = 0; i < flow_array_size; i++) + { + if (flow == flow_array[i]) + { + return true; + } + } + return false; +} + +bool parsec_helper_dep_is_in_flow_array(const parsec_dep_t *dep, parsec_dep_t *dep_array[], int dep_array_size) +{ + for (int i = 0; i < dep_array_size; i++) + { + if (dep == dep_array[i]) + { + return true; + } + } + return false; +} + +/** __parsec_LBM_shift_all_flow_reference_after + * + * Shift all the flows after "pivot_flow" by "shift" + * If in_out==0, shift the input flows, otherwise shift the output flows + * + */ +void parsec_shift_all_flows_after(parsec_task_class_t *tc, const parsec_flow_t *pivot_flow, int shift) +{ + int i, j; + //int flow_in_out; + int pivot_index_in, pivot_index_out; + int last_flow_index_in, last_flow_index_out; + int found_pivot_in=0, found_pivot_out=0; + int pivot_flow_index = pivot_flow->flow_index; + parsec_flow_t *flow; + parsec_dep_t *dep; + + // use an array to keep track of the flows we already treated + parsec_flow_t *shifted_flows[MAX_DATAFLOWS_PER_TASK]; + int shifted_flows_size = 0; + + // Determine which array should be used (in or out) depending on in_out + //parsec_flow_t **flow_array = (parsec_flow_t **) ((in_out) ? (tc->out) : (tc->in)); + parsec_dep_t **dep_array; + + // The flows will be shifted both in th "in" and "out" arrays + for (int in_out = 0; in_out < 2; ++in_out) { + const int max_dep_count = (in_out) ? MAX_DEP_OUT_COUNT : MAX_DEP_IN_COUNT; + + // find the pivot flow + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; ++i) + { + if(pivot_flow == ((in_out) ? (tc->out) : (tc->in))[i]) + break; // pivot flow found + if(!((in_out) ? (tc->out) : (tc->in))[i]) + break; // pivot not found + } + if(pivot_flow == ((in_out) ? (tc->out) : (tc->in))[i]) + { + if(in_out) + { + found_pivot_out = 1; + pivot_index_out = i; + } + else + { + found_pivot_in = 1; + pivot_index_in = i; + } + + // - Update all the dep_index > pivot_index (MODIFICATION: DONT TO THIS) + // - find last_flow_index (needed for performing the actual shift at the end) + for (i = (in_out?pivot_index_out:pivot_index_in) + 1; i < MAX_DATAFLOWS_PER_TASK; i++) + { + flow = ((in_out) ? (tc->out) : (tc->in))[i]; + if(!flow) + break; // end of the array + + dep_array = (in_out) ? flow->dep_out : flow->dep_in; + + for(j=0; jdep_index > pivot_index) // MODIFICATION: DONT TO THIS + // dep->dep_index += shift*(i-pivot_index); + } + if(!flow) + break; // end of the array + } + //((in_out) ? last_flow_index_out : last_flow_index_in) = i - 1; + if(in_out) + last_flow_index_out = i - 1; + else + last_flow_index_in = i - 1; + } + } + + for(int in_out = 0; in_out < 2; ++in_out) + { + if(in_out&&found_pivot_out || !in_out&&found_pivot_in) + { // The pivot flow was found in this in_out + int pivot_index = (in_out) ? pivot_index_out : pivot_index_in; + int last_flow_index = (in_out) ? last_flow_index_out : last_flow_index_in; + // - Shift the flows + // - Update the flow_index of the flows + for (i = last_flow_index; i > pivot_index; i--) + { + flow = ((in_out) ? (tc->out) : (tc->in))[i]; + ((in_out) ? (tc->out) : (tc->in))[i+shift] = flow; + if(!parsec_helper_flow_is_in_flow_array(flow, shifted_flows, shifted_flows_size)) + { + flow->flow_index += shift; + shifted_flows[shifted_flows_size] = flow; + shifted_flows_size++; + } + } + } + else + { // The pivot flow was not found in this in_out, so we just update the flow_index + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + flow = ((in_out) ? (tc->out) : (tc->in))[i]; + if(!flow) + break; // end of the array + if(!parsec_helper_flow_is_in_flow_array(flow, shifted_flows, shifted_flows_size)) + { + if(flow->flow_index > pivot_flow_index) + { + flow->flow_index += shift; + } + shifted_flows[shifted_flows_size] = flow; + shifted_flows_size++; + } + } + } + } + +/* + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + if(pivot_flow == tc->in[i]) + break; + } + //if(i < MAX_DATAFLOWS_PER_TASK) { + for(;iin[i]->dep[j]->dep_index += shift; + } + } + //} +*/ + + + + + + + +/* + // Increase the IDs of every flow that is greater than the ID of pivot_flow + for (flow_in_out = 0; flow_in_out < 2; ++flow_in_out) + { + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + flow = (parsec_flow_t *)(flow_in_out ? tc->out[i] : tc->in[i]); + if (parsec_helper_flow_is_in_flow_array(flow, treated_flows, treated_flows_size)) + { + continue; + } + + if (flow) + { + if (flow->flow_index > pivot_flow->flow_index) + { + flow->flow_index += shift; + } + + treated_flows[treated_flows_size] = flow; + ++treated_flows_size; + } + else + { + break; + } + } + } + + /* We perform the shift on both the in and out flows of the task class + * The pivot flow can have different indices in the in and out arrays + * + * Note: We displace all the flows following the pivot flow in the in and out array + * But this is just for convience, to get the parametrized subflows next to each other + *//* + for (flow_in_out = 0; flow_in_out < 2; ++flow_in_out) + { + + // Look for the pivot flow + pivot_index = -1; + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + flow = (parsec_flow_t *)(flow_in_out ? tc->out[i] : tc->in[i]); + + if (!flow) + { + break; + } + + if (flow == pivot_flow) + { + pivot_index = i; + break; + } + } + + // If the pivot was not found in this flow_in_out, skip the shift + if (pivot_index == -1) + { + continue; + } + + // Find the last non-null flow + for (i = pivot_index; i < MAX_DATAFLOWS_PER_TASK; i++) + { + flow = (parsec_flow_t *)(flow_in_out ? tc->out[i] : tc->in[i]); + + if (!flow) + { + break; + } + } + int last_flow_index = i - 1; + + // Shift all the flows after the pivot + for (i = last_flow_index; i > pivot_index; i--) + { + flow = (parsec_flow_t *)(flow_in_out ? tc->out[i] : tc->in[i]); + + assert(flow); // We should not have a NULL flow here + // assert(flow->flow_index == i); // The flow index can acutally be anything + assert(i + shift < MAX_DATAFLOWS_PER_TASK); // We should not overflow the array + + // Shift the flow + (flow_in_out ? tc->out : tc->in)[i + shift] = flow; + } + }*/ +} + +void parsec_shift_all_deps_after(parsec_task_class_t *tc, parsec_flow_t *flow, parsec_dep_t *pivot_dep, int dep_in_out, int shift) +{ + // Should be rewritten like parsec_update_dep_index_after_dep + + int pivot_dep_index; + (void) tc; + + // Look for the pivot dep + pivot_dep_index = -1; + for (int i = 0; i < (dep_in_out?MAX_DEP_OUT_COUNT:MAX_DEP_IN_COUNT); i++) + { + parsec_dep_t *dep = (parsec_dep_t *)(dep_in_out ? flow->dep_out[i] : flow->dep_in[i]); + + if (!dep) + { + break; + } + + if (dep == pivot_dep) + { + pivot_dep_index = i; + break; + } + } + + // If the pivot was not found in this flow_in_out, skip the shift + if (pivot_dep_index == -1) + { + assert(0); + return; + } + + assert((dep_in_out ? flow->dep_out[pivot_dep_index] : flow->dep_in[pivot_dep_index]) == pivot_dep); // From there, the pivot dep should be in the array + + // Find the last non-null dep + int last_dep_index; + for (last_dep_index = pivot_dep_index + 1; last_dep_index < (dep_in_out?MAX_DEP_OUT_COUNT:MAX_DEP_IN_COUNT); ++last_dep_index) + { + parsec_dep_t *dep = (parsec_dep_t *)(dep_in_out ? flow->dep_out[last_dep_index] : flow->dep_in[last_dep_index]); + + if (!dep) + { + break; + } + } + last_dep_index--; + + // Shift all the deps after the pivot + for (int i = last_dep_index; i > pivot_dep_index; i--) + { + parsec_dep_t *dep = (parsec_dep_t *)(dep_in_out ? flow->dep_out[i] : flow->dep_in[i]); + + assert(dep); // We should not have a NULL dep here + // assert(dep->dep_index == i); // The dep index can acutally be anything + assert(i + shift < (dep_in_out?MAX_DEP_OUT_COUNT:MAX_DEP_IN_COUNT)); // We should not overflow the array + + // Shift the dep + (dep_in_out ? flow->dep_out : flow->dep_in)[i + shift] = dep; + } +} + +void parsec_update_dep_index_after_dep(parsec_task_class_t *tc, parsec_flow_t *flow, int dep_in_out, parsec_dep_t *pivot_dep, int shift) +{ + // This function assumes that the dep_index increases + // parsec_shift_all_deps_after should be rewritten assuming this too + + int i; + parsec_dep_t *dep; + + for (i = 0; i < (dep_in_out ? MAX_DEP_OUT_COUNT : MAX_DEP_IN_COUNT); i++) + { + dep = (parsec_dep_t *)(dep_in_out ? flow->dep_out[i] : flow->dep_in[i]); + if (!dep) + { + break; + } + + if (dep->dep_index > pivot_dep->dep_index) + { + dep->dep_index += shift; + } + } +} + +/* Prints the task class information (for debugging purposes) + * It will print the basic task information, its flows and their deps + */ +void parsec_debug_dump_task_class_at_exec(parsec_task_class_t *tc) +{ + int i, j; + int flow_in_out, dep_in_out; + parsec_flow_t *flow; + parsec_dep_t *dep; + + // flows can appear twice in a task class (if both in and out) + parsec_flow_t *treated_flows[MAX_DATAFLOWS_PER_TASK]; + int treated_flows_size = 0; + + parsec_debug_verbose(1, parsec_debug_output, "###### PRINTING TASK CLASS %s ######", tc->name); + + parsec_debug_verbose(1, parsec_debug_output, "## Task Class %s (%p) has %d flows, %d parameters, %d locals", + tc->name, (void *)tc, tc->nb_flows, tc->nb_parameters, tc->nb_locals); + + parsec_debug_verbose(1, parsec_debug_output, "## dependencies_goal = %x", tc->dependencies_goal); + + for (flow_in_out = 0; flow_in_out < 2; ++flow_in_out) + { + parsec_debug_verbose(1, parsec_debug_output, "## %s flows:", flow_in_out ? "out" : "in"); + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + flow = (parsec_flow_t *)(flow_in_out ? tc->out[i] : tc->in[i]); + + if (flow/* && !parsec_helper_flow_is_in_flow_array(flow, treated_flows, treated_flows_size)*/) + { + parsec_debug_verbose(1, parsec_debug_output, " X flow %s (addr=%p, id=%d, flow_datatype_mask=%p, flow_flags=%p)", + flow->name, (void *)flow, flow->flow_index, flow->flow_datatype_mask, flow->flow_flags); + //for (dep_in_out = 0; dep_in_out < 2; ++dep_in_out) + dep_in_out = flow_in_out; + { + for (j = 0; j < (dep_in_out ? MAX_DEP_OUT_COUNT : MAX_DEP_IN_COUNT); j++) + { + dep = (parsec_dep_t *)(dep_in_out ? flow->dep_out[j] : flow->dep_in[j]); + if (!dep) + { + continue; + } + + if (PARSEC_LOCAL_DATA_TASK_CLASS_ID == dep->task_class_id) + { + parsec_debug_verbose(1, parsec_debug_output, " %s dep [%d] (addr=%p) of flow %s linked with data collection", + dep_in_out ? "->" : "<-", j, dep, flow->name); + } + else if (dep->flow) + { + parsec_debug_verbose(1, parsec_debug_output, " %s dep [%d] (addr=%p) of flow %s has dep_id=%d and goes to flow %s (id=%d) of task class %d", + dep_in_out ? "->" : "<-", j, dep, flow->name, dep->dep_index, dep->flow->name, + dep->flow->flow_index, dep->task_class_id); + } + else + { + parsec_debug_verbose(1, parsec_debug_output, "## WARNING ## , parsec_debug_dump_task_class_at_exec does not know this type of dependency"); + continue; + } + parsec_debug_verbose(1, parsec_debug_output, "\t\tdatatype=%d\tdirect_data=%p\tdep_datatype_index=%d\tdep_index=%d\ttask_class_id=%d", + dep->dep_datatype_index, (void *)dep->direct_data, dep->dep_datatype_index, dep->dep_index, dep->task_class_id); + } + } + + treated_flows[treated_flows_size] = flow; + ++treated_flows_size; + } + } + } +} + +/* Checks if the task class is valid (for debugging purposes) + */ +void parsec_check_sanity_of_task_class(parsec_task_class_t *tc, bool check_dep_index) +{ + int i, j; + int flow_in_out; + parsec_dep_t *dep; + + // flows can appear twice in a task class (if both in and out) + parsec_flow_t *treated_flows[MAX_DATAFLOWS_PER_TASK]; + int treated_flows_size = 0; + + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + for (flow_in_out = 0; flow_in_out < 2; ++flow_in_out) + { + const parsec_flow_t *flow = (parsec_flow_t *)(flow_in_out ? tc->out[i] : tc->in[i]); + + if (flow && !parsec_helper_flow_is_in_flow_array(flow, treated_flows, treated_flows_size)) + { + // TODO ? Is there anything to assert? + + treated_flows[treated_flows_size] = flow; + ++treated_flows_size; + } + } + } + + // for each flow and each dep, check that: + // - belongs_to and flow : != 0xdeadbeef and != NULL + for(int in_out=0; in_out<2; ++in_out) { + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + parsec_flow_t *flow = (parsec_flow_t *)(in_out ? tc->out[i] : tc->in[i]); + if(!flow) continue; + for(int j=0;j<(in_out?MAX_DEP_OUT_COUNT:MAX_DEP_IN_COUNT);++j) { + dep = (parsec_dep_t *)(in_out ? flow->dep_out[j] : flow->dep_in[j]); + if(!dep) continue; + assert(dep->belongs_to != (void*)0xdeadbeef); + assert(dep->belongs_to != NULL); + assert(dep->flow != (void*)0xdeadbeef); + assert(dep->flow != NULL || dep->task_class_id == PARSEC_LOCAL_DATA_TASK_CLASS_ID); + } + } + } + + // Check the coherency of the flow flags + if(check_dep_index) + { + for(int in_out=0; in_out<2; ++in_out) { + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + const parsec_flow_t *flow = tc->out[i]; + + if (!flow) + { + break; + } + + // For each output dep of the flow ... + for (j = 0; j < (in_out ? MAX_DEP_OUT_COUNT : MAX_DEP_IN_COUNT); j++) + { + dep = (parsec_dep_t *)(in_out ? flow->dep_out[j] : flow->dep_in[j]); + if (!dep) + { + break; + } + + if(in_out == 1) + { + // All out dependencies should be in the flow datatype mask + assert((1 << dep->dep_datatype_index) & flow->flow_datatype_mask); + // assert((1 << dep->dep_index) & flow->flow_datatype_mask); + + // All out dependencies should be mappable in the flow datatype mask + assert(dep->dep_datatype_index < sizeof(flow->flow_datatype_mask) * 8); + } + + assert(dep->dep_index < (in_out ? MAX_DEP_OUT_COUNT : MAX_DEP_IN_COUNT)); + } + } + } + } + + assert(tc->nb_flows == treated_flows_size); +} + +parsec_flow_t *parsec_helper_copy_flow(parsec_flow_t *flow_to, const parsec_flow_t *flow_from) +{ + int flow_in_out; + + assert(flow_to); + memcpy(flow_to, flow_from, sizeof(parsec_flow_t)); + + // Copy the dependencies + int i; + for (flow_in_out = 0; flow_in_out < 2; ++flow_in_out) + { + for (i = 0; i < (flow_in_out ? MAX_DEP_OUT_COUNT : MAX_DEP_IN_COUNT); i++) + { + parsec_dep_t *dep = (parsec_dep_t *)(flow_in_out ? flow_to->dep_out[i] : flow_to->dep_in[i]); + + if (!dep) + { + break; + } + + // Not copying the dep should be fine: + /*parsec_dep_t *new_dep = (parsec_dep_t *)malloc(sizeof(parsec_dep_t)); + assert(new_dep); + memcpy(new_dep, dep, sizeof(parsec_dep_t)); + (flow_in_out ? flow_to->dep_out : flow_to->dep_in)[i] = new_dep;*/ + } + } + + return flow_to; +} + +parsec_dep_t *parsec_helper_copy_dep(parsec_dep_t * dep_to, const parsec_dep_t * dep_from) +{ + //parsec_dep_t *new_dep = (parsec_dep_t *)malloc(sizeof(parsec_dep_t)); + assert(dep_to); + memcpy(dep_to, dep_from, sizeof(parsec_dep_t)); + return dep_to; +} + +int parsec_helper_dep_is_in_flow(const parsec_flow_t *flow, const parsec_dep_t *dep, int in_out) +{ + int i; + for (i = 0; i < (in_out ? MAX_DEP_OUT_COUNT : MAX_DEP_IN_COUNT); i++) + { + if (dep == (in_out ? flow->dep_out[i] : flow->dep_in[i])) + { + return 1; + } + } + return 0; +} + +int parsec_helper_get_dep_index_in_flow(const parsec_flow_t *flow, const parsec_dep_t *dep, int in_out) +{ + int i; + for (i = 0; i < (in_out ? MAX_DEP_OUT_COUNT : MAX_DEP_IN_COUNT); i++) + { + if (dep == (in_out ? flow->dep_out[i] : flow->dep_in[i])) + { + return i; + } + } + assert(0); + return -1; +} + +int parsec_helper_get_dep_index(const parsec_task_class_t *tc, const parsec_dep_t *dep, int in_out) +{ + int i; + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + parsec_flow_t *flow = (parsec_flow_t *)(in_out ? tc->out[i] : tc->in[i]); + if (!flow) + { + break; + } + + if (parsec_helper_dep_is_in_flow(flow, dep, in_out)) + { + return parsec_helper_get_dep_index_in_flow(flow, dep, in_out); + } + } + + assert(0); + return -1; +} + +int parsec_helper_get_flow_index_that_contains_dep(const parsec_task_class_t *tc, const parsec_dep_t *dep, int in_out) +{ + int i; + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + const parsec_flow_t *flow = (in_out ? tc->out[i] : tc->in[i]); + + if (!flow) + { + break; + } + + if (parsec_helper_dep_is_in_flow(flow, dep, in_out)) + { + return i; + } + } + + assert(0); + return -1; +} + +int parsec_helper_get_flow_index_in_or_out(const parsec_task_class_t *tc, const parsec_flow_t *flow) +{ + /*int i = parsec_helper_get_flow_index(tc, flow, 1); + if(i != -1) + { + return i; + } + // If the flow was not found, it is a read-only flow, let's affect it a new index + i = parsec_helper_get_flow_index(tc, flow, 0); + assert(i != -1); + // Add the number of out flows to the index to make it unique + int nb_out_flows = parsec_helper_get_flow_index(tc, NULL, 1); + assert(nb_out_flows != -1); + i += nb_out_flows; + return i;*/ + int i = parsec_helper_get_flow_index(tc, flow, 1); + i = ((i == -1) ? parsec_helper_get_flow_index(tc, flow, 0) : i); + assert(i != -1); + return i; +} + +int parsec_helper_get_flow_index(const parsec_task_class_t *tc, const parsec_flow_t *flow, int in_out) +{ + int i; + for (i = 0; i < MAX_DATAFLOWS_PER_TASK; i++) + { + const parsec_flow_t *_flow = (in_out ? tc->out[i] : tc->in[i]); + + if (flow == _flow) + { + return i; + } + + if (!_flow) + { + break; + } + } + + //assert(0); + return -1; +} diff --git a/parsec/task_class.h b/parsec/task_class.h new file mode 100644 index 000000000..83b95acbe --- /dev/null +++ b/parsec/task_class.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012-2019 The University of Tennessee and The University + * of Tennessee Research Foundation. All rights + * reserved. + */ + +#ifndef PARSEC_TASK_CLASS_H_HAS_BEEN_INCLUDED +#define PARSEC_TASK_CLASS_H_HAS_BEEN_INCLUDED + +#include "parsec/parsec_config.h" +#include "parsec/interfaces/interface.h" +#include "parsec_internal.h" + +// The shift functions creates spaces in the relevant arrays +void parsec_shift_all_flows_after(parsec_task_class_t *tc, const parsec_flow_t *pivot_flow, int shift); +void parsec_shift_all_deps_after(parsec_task_class_t *tc, parsec_flow_t *flow, parsec_dep_t *pivot_dep, int dep_in_out, int shift); +void parsec_update_dep_index_after_dep(parsec_task_class_t *tc, parsec_flow_t *flow, int dep_in_out, parsec_dep_t *pivot_dep, int shift); + +// in all flows fl (fl!=flow), increase deps by shift +//void parsec_update_dep_index_in_other_flows(parsec_task_class_t *tc, parsec_flow_t *flow, int dep_in_out, int dep_index, int shift); + +// flow_array should be const, but it creates a warning in the generated code +bool parsec_helper_flow_is_in_flow_array(const parsec_flow_t *flow, parsec_flow_t *flow_array[], int flow_array_size); +bool parsec_helper_dep_is_in_flow_array(const parsec_dep_t *dep, parsec_dep_t *dep_array[], int dep_array_size); + +void parsec_debug_dump_task_class_at_exec(parsec_task_class_t *tc); +void parsec_check_sanity_of_task_class(parsec_task_class_t *tc, bool check_dep_index); + +// Copy a flow (including its deps) and returns a pointer to the new flow +parsec_flow_t *parsec_helper_copy_flow(parsec_flow_t *flow_to, const parsec_flow_t *flow_from); +parsec_dep_t *parsec_helper_copy_dep(parsec_dep_t * dep_to, const parsec_dep_t * dep_from); + +int parsec_helper_dep_is_in_flow(const parsec_flow_t *flow, const parsec_dep_t *dep, int in_out); +int parsec_helper_get_dep_index_in_flow(const parsec_flow_t *flow, const parsec_dep_t *dep, int in_out); +int parsec_helper_get_dep_index(const parsec_task_class_t *tc, const parsec_dep_t *dep, int in_out); +int parsec_helper_get_flow_index_that_contains_dep(const parsec_task_class_t *tc, const parsec_dep_t *dep, int in_out); +int parsec_helper_get_flow_index_in_or_out(const parsec_task_class_t *tc, const parsec_flow_t *flow); +int parsec_helper_get_flow_index(const parsec_task_class_t *tc, const parsec_flow_t *flow, int in_out); + +#endif /* PARSEC_TASK_CLASS_H_HAS_BEEN_INCLUDED */ diff --git a/tests/dsl/ptg/choice/choice2.jdf b/tests/dsl/ptg/choice/choice2.jdf index e9c25d2f1..8807a561f 100644 --- a/tests/dsl/ptg/choice/choice2.jdf +++ b/tests/dsl/ptg/choice/choice2.jdf @@ -19,7 +19,7 @@ RW D <- D Selector(k, k) -> %{ return (k < NT) && idecision(pos) == 1; %} ? D TA(k, k) -> %{ return (k < NT) && idecision(pos) == 2; %} ? D TB(k, k) RW C <- decision( pos ) [type_remote=DECISION] - -> A LChoice( k, 0 .. P-1 ) [type_remote=DECISION] + -> A2 LChoice( k, 0 .. P-1 ) [type_remote=DECISION] BODY { @@ -71,7 +71,7 @@ first = %{ : decision( k*P + p ) -READ A <- C GenChoice( k ) [type_remote=DECISION] +READ A2 <- C GenChoice( k ) [type_remote=DECISION] RW C <- decision( k*P + p ) [type_remote=DECISION] -> decision( k*P + p ) [type_remote=DECISION] CTL ct <- (k > 0) ? ct LChoice(k-1, P)