PIPS
task_mapping.c
Go to the documentation of this file.
1 /*
2 
3  $Id$
4 
5  Copyright 1989-2017 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23  */
24 #ifdef HAVE_CONFIG_H
25 #include "pips_config.h"
26 #endif
27 
28 /**
29  * Pass: TASK_MAPPING
30  * Debug mode: MPI_GENERATION_DEBUG_LEVEL
31  * Resource generated:
32  * - DBR_TASK
33  *
34  */
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 
39 #include "genC.h"
40 #include "linear.h"
41 
42 #include "resources.h"
43 #include "database.h"
44 #include "ri.h"
45 #include "ri-util.h"
46 #include "pipsdbm.h"
47 
48 #include "misc.h"
49 
50 #include "properties.h"
51 
52 #include "task_private.h"
53 #include "task_parallelization.h"
54 #include "prettyprint.h"
55 /*
56  * Generate function:
57  * parallel_task_mapping_undefined_p(void)
58  * reset_parallel_task_mapping(void)
59  * error_reset_parallel_task_mapping(void)
60  * set_parallel_task_mapping(statement_task o)
61  * get_parallel_task_mapping(void)
62  * init_parallel_task_mapping(void)
63  * close_parallel_task_mapping(void)
64  * store_parallel_task_mapping(statement k, task v)
65  * update_parallel_task_mapping(statement k, task v)
66  * load_parallel_task_mapping(statement k)
67  * delete_parallel_task_mapping(statement k)
68  * bound_parallel_task_mapping_p(statement k)
69  * store_or_update_parallel_task_mapping(statement k, task v)
70  */
71 GENERIC_GLOBAL_FUNCTION(parallel_task_mapping, statement_task)
72 
73 void print_task(task t) {
74  if(task_undefined_p(t))
75  fprintf(stderr, "Undefined task\n");
76  // For debugging with gdb, dynamic type checking
77  else if(task_domain_number(t)!=task_domain)
78  (void) fprintf(stderr,"Arg. \"t\"is not a task.\n");
79  else {
80  fprintf(stderr, "%s", task_to_string(t, false));
81  }
82 }
83 
84 string task_to_string(task t, bool pretty_print) {
85  char tid[10+4];
86  string tprivate = "";
87  char tcluster[18+4];
88  char tsync[23+5];
89  snprintf(tid, 10+4, "task_id=%"_intFMT"\n", task_id(t));
90  snprintf(tcluster, 18+4, "task_on_cluster=%"_intFMT"\n", task_on_cluster(t));
91  snprintf(tsync, 23+5, "task_synchronization=%s\n", task_synchronization(t)?"true":"false");
92  tprivate = "task_private_data={";
94  pips_debug(8, "%s", entity_name(ep));
95  tprivate = concatenate(tprivate, pretty_print?entity_user_name(ep):entity_name(ep), "; ", (char *) NULL);
96  }
97  tprivate = strdup(concatenate(tprivate, "}\n", (char *) NULL));
98  return concatenate(tid, tprivate, tcluster, tsync, (char *) NULL);
99 }
100 
101 
102 /******************************************************
103  * PRAGMA MANAGEMENT : BEGIN *
104  ******************************************************/
105 #define PRAGMA_DISTRIBUTED "distributed"
106 
107 /**
108  * ctx_pragma_t:
109  * on_cluster on which cluster the pragma may be run (=-1 if run on all cluster)
110  * synchro if the communication between cluster are synchro (true) or asynchro(false)
111  * if on_cluster=-1 we don't care about the value of synchro
112  * d_... if it's a default value or value ask by user
113  */
114 typedef struct ctx_pragma {
115  //string begin;
118  bool synchro;
119  bool d_synchro;
121 
122 static void print_ctx_pragma(const ctx_pragma_t ctx) {
123  fprintf(stderr, "pragma info:\n");
124  fprintf(stderr, "on_cluster=%d\n", ctx.on_cluster);
125  fprintf(stderr, "synchro=%s\n", ctx.synchro?"true":"false");
126 }
127 
128 /**
129  * init a ctx_pragma_t
130  * by default
131  * ctx.on_cluster = -1 run on all cluster
132  * ctx.synchro = true com synchro
133  */
135  ctx_pragma_t ctx;
136  ctx.on_cluster = -1;
137  ctx.d_on_cluster = true;
138  ctx.synchro = true;
139  ctx.d_synchro = true;
140  return ctx;
141 }
142 // Not use
143 ///**
144 // * create a ctx_pragma_t with the parameter
145 // */
146 //static ctx_pragma_t make_ctx_pragma(int cluster, bool synchro) {
147 // ctx_pragma_t ctx;
148 // ctx.on_cluster = cluster;
149 // ctx.d_on_cluster = false;
150 // ctx.synchro = synchro;
151 // ctx.d_synchro = false;
152 // return ctx;
153 //}
154 
155 /**
156  * generate a error message about the for the parameter of the pragma to use
157  */
158 static string pragma_parameter_unknown_message(string s) {
159  return concatenate("\nUnknown ", s, " parameter.\n"
160  "Allowed parameters are:\n"
161  "\ton_cluster=n with n a positive number\n"
162  "\tnowait|wait\n", NULL);
163 }
164 
165 /**
166  * Test if the pragma is a PRAGMA_DISTRIBUTED
167  * check the first element f the pragma
168  * \param p pragma to check
169  * \return true if p is a PRAGMA_DISTRIBUTED
170  */
172  bool r = false;
173  if(pragma_string_p(p)) {
174  if(strncasecmp(PRAGMA_DISTRIBUTED, pragma_string(p), strlen(PRAGMA_DISTRIBUTED)) == 0) {
175  r = true;
176  }
177  }
178  else if(pragma_expression_p(p)) {
179  list expr = pragma_expression(p);
180  // The list is reversed !
181  expression begin = EXPRESSION(CAR(gen_last(expr)));
182  if(expression_call_p(begin)) {
183  entity called = call_function(expression_call(begin));
184  if(strncasecmp(PRAGMA_DISTRIBUTED, entity_local_name(called), strlen(PRAGMA_DISTRIBUTED)) == 0) {
185  r = true;
186  }
187  }
188  }
189  else {
190  pips_internal_error("We don't know how to handle this kind of pragma !\n");
191  }
192  return r;
193 }
194 
195 /**
196  * parse the pragma to generate a ctx_pragma_t
197  * need to checked that the pragma sended is a PRAGMA_DISTRIBUTED before
198  * \param p pragma to be parsed
199  * \return a ctx_pragma_t with the value of the pragma
200  */
203  pips_debug(6, "begin\n parse pragma %p\n", p);
204 
205  if(pragma_string_p(p)) {
206  list lst = strsplit(pragma_string(p), " ");
207  //start at the second parameter so CDR(lst)
208  FOREACH(STRING, str, CDR(lst)) {
209  if(strncasecmp(str, "on_cluster=", 11) == 0) {
210  list cluster = strsplit(str, "=");
211  if (gen_length(cluster) == 2) {
212  string cluster_number = STRING(gen_nth(1, cluster));
213  //TODO a better function than atoi may be use, atoi doesn't manage error, strtol too much work is need, remake a custom function?
214  ctx.on_cluster = atoi(cluster_number);
215  ctx.d_on_cluster = false;
216  } else {
217  pips_user_warning("unexpected value for parameter on_cluster: %s\n", str);
218  }
219  }
220  else if(strncasecmp(str, "nowait", 7) == 0) {
221  ctx.synchro = false;
222  ctx.d_synchro = false;
223  }
224  else if(strncasecmp(str, "wait", 5) == 0) {
225  ctx.synchro = true;
226  ctx.d_synchro = false;
227  }
228  else {
230  }
231  }
232  }
233  //This case normally never appear.
234  else if(pragma_expression_p(p)) {
235  pips_user_warning("Parse pragma expressions for pragma %s not implemented. This case normally never appear.\n", PRAGMA_DISTRIBUTED);
236  }
237  else {
238  pips_internal_error("We don't know how to handle this kind of pragma !\n");
239  }
240 
241  pips_debug(6, "end\n");
242  return ctx;
243 }
244 
245 /**
246  * Merge value of 2 ctx_pragma_t,
247  * the 2 ctx_pragma_t can't conflict on value
248  * \param ctx1 ctx_pragma_t to merge
249  * \param ctx2 ctx_pragma_t to merge
250  * \return a new ctx_pragma_t with value of ctx1 and ctx2
251  */
254 
255  if (!ctx1.d_on_cluster) {
256  ctx.d_on_cluster = false;
257  ctx.on_cluster = ctx1.on_cluster;
258  if (!(!ctx2.d_on_cluster && ctx1.on_cluster==ctx2.on_cluster)) {
259  pips_user_error("conflict between value ask by the user in pragma about on_cluster %d and %d\n", ctx1.on_cluster, ctx2.on_cluster);
260  }
261  } else if (!ctx2.d_on_cluster) {
262  ctx.d_on_cluster = false;
263  ctx.on_cluster = ctx2.on_cluster;
264  }
265 
266  if (!ctx1.d_synchro) {
267  ctx.d_synchro = false;
268  ctx.synchro = ctx1.synchro;
269  if (!(!ctx2.d_synchro && ctx1.synchro==ctx2.synchro)) {
270  pips_user_error("conflict between value ask by the user in pragma about synchro(wait/nowait) %d and %d\n", ctx1.synchro, ctx2.synchro);
271  }
272  } else if (!ctx2.d_synchro) {
273  ctx.d_synchro = false;
274  ctx.synchro = ctx2.synchro;
275  }
276 
277  return ctx;
278 }
279 
280 //static bool print_pragma(statement s) {
281 // print_statement(s);
282 // pips_debug(0, "have pragma:\n");
283 // if (statement_with_pragma_p(s)) {
284 // list lpragmas = statement_pragmas(s);
285 // FOREACH(PRAGMA, p, lpragmas) {
286 // if (pragma_string_p(p)) {
287 // pips_debug(0, "pragma is a string = \n %s\n", pragma_string(p));
288 // }
289 // else if (pragma_expression_p(p)) {
290 // pips_debug(0, "pragma is a expressions = \n");
291 // print_expressions(pragma_expression(p));
292 // }
293 // else if (pragma_undefined_p(p)) {
294 // pips_debug(0, "pragma is undefined !!!!!!!!!\n");
295 // }
296 // else {
297 // pips_debug(0, "pragma NEVER OCCUR !!!!!!!!!\n");
298 // }
299 // }
300 // }
301 // return true;
302 //}
303 /******************************************************
304  * PRAGMA MANAGEMENT : END *
305  ******************************************************/
306 
307 /**
308  * ctx_task_t:
309  * pragma information from the pragma
310  * task_id id of the task
311  * private list of entity, private variables for the task
312  */
313 typedef struct ctx_task {
315  int task_id;
316  list private;
318 
319 static void print_ctx_task(const ctx_task_t ctx) {
321  fprintf(stderr, "task_id=%d\n", ctx.task_id);
322  fprintf(stderr, "private list entities:\n");
323  FOREACH(ENTITY, e, ctx.private) {
325  fprintf(stderr, "\n");
326  }
327 }
328 
329 /**
330  * compute what it must be add in the private entity list
331  * essentially internal declaration of the statement
332  * \param st statement to check
333  * \param ctx context where private list is store and update
334  */
336  if (declaration_statement_p(st)) {
337  // declarations list of entity declared
338  list declarations = statement_declarations(st);
339  ctx->private = gen_nconc(ctx->private, gen_copy_seq(declarations));
340  }
341 }
342 
343 /**
344  * assign a task for the statement st
345  * \param st statement to be assigned
346  * \param ctx context where information about the task are store
347  */
349  task t;
350  if (ctx->pragma.on_cluster == -1)
351  t = make_task(ctx->task_id, NIL, ctx->pragma.on_cluster, ctx->pragma.synchro);
352  else
353  t = make_task(ctx->task_id, gen_copy_seq(ctx->private), ctx->pragma.on_cluster, ctx->pragma.synchro);
355  ifdebug(4) {
356  pips_debug(4, "associate statement %p to task %p\n", st, load_parallel_task_mapping(st));
357  pips_debug(4, "statement:\n");
358  print_statement(st);
359  pips_debug(4, "task:\n");
361  }
362 }
363 
364 /**
365  * compute the task mapping requires the module statement as param
366  * only parse pragma on fisrt level statement of the module
367  * then recurse on all sub-statement to assign the task
368  * \param module_statement module statement to work on
369  */
372  pips_internal_error("module_statement have to be the statement of the module/function\n");
373  return false;
374  }
375 
376  int task_number = 0;
377  // FOREACH statement of the module/function,
379  //init a a pragma context (execution on all cluster
380  ctx_pragma_t ctxp = init_ctx_pragma();
381  //check if statement st have a pragma, if true modify pragma context in consequences
382  if (statement_with_pragma_p(st)) {
383  list lpragmas = statement_pragmas(st);
384  FOREACH(PRAGMA, p, lpragmas) {
387  ctxp = ctx_pragma_merge(ctxp, ctxp_temp);
388  }
389  }
390  }
391 
392  //init the task context
393  ctx_task_t ctx;
394  ctx.task_id = task_number;
395  ctx.pragma = ctxp;
396  ctx.private = NIL;
397 
398  ifdebug(2) {
399  pips_debug(2, "work on statement:\n");
400  print_statement(st);
401  print_ctx_task(ctx);
402  }
403 
404  //make the job
405  //first compute_private_entity_list to recursively add private entity
406  //second assign_statement_task_mapping to assign a task to each statement
407  //can't make the 2 gen_curse into 1 because I want the full private list variable before the assignment of task to statement
410 
411  task_number++;
412  }
413 
414  // only present in case of gen_recurse with module_statement to not have seg fault
415  // But normally will never be useful
416  ctx_task_t ctx;
417  ctx.task_id = -1;
418  ctx.pragma = init_ctx_pragma();
419  ctx.private = NIL;
420  //no need
421  //compute_private_entity_list(module_statement, &ctx);
423 
424  return true;
425 }
426 
427 /**
428  * PIPS pass
429  */
430 bool task_mapping(const char* module_name) {
431  entity module;
433  bool good_result_p = true;
434 
435  debug_on("MPI_GENERATION_DEBUG_LEVEL");
436  pips_debug(1, "begin\n");
437 
438  //-- configure environment --//
441 
443  db_get_memory_resource(DBR_CODE, module_name, true) );
445 
446  pips_assert("Statement should be OK before...",
448 
450 
451  //-- get dependencies --//
452  // nothing except code and entity done before.
453 
454  //TODO look to add parameter in private list?
455  // look module is type functionnal -> list parameter convert to list entitty
456 
457  //-- Make the job -- //
459  // gen_recurse(module_statement, statement_domain, gen_true, print_pragma);
460 
461  //useless, normally we don't modify the code
462  //pips_assert("Statement should be OK after...",
463  // statement_consistent_p(module_statement));
464 
465  //-- Save modified code to database --//
466  // DB_PUT_MEMORY_RESOURCE(DBR_CODE, strdup(module_name), module_statement);
468  // DB_PUT_MEMORY_RESOURCE(DBR_CALLEES, module_name,
469  // compute_callees(module_statement));
470 
474 
475  pips_debug(1, "end\n");
476  debug_off();
477 
478  return (good_result_p);
479 }
480 
float a2sf[2] __attribute__((aligned(16)))
USER generates a user error (i.e., non fatal) by printing the given MSG according to the FMT.
Definition: 3dnow.h:3
bool statement_consistent_p(statement p)
Definition: ri.c:2195
task make_task(intptr_t a1, list a2, intptr_t a3, bool a4)
Definition: task_private.c:109
static statement module_statement
Definition: alias_check.c:125
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
#define gen_context_recurse(start, ctxt, domain_number, flt, rwt)
Definition: genC.h:285
#define STRING(x)
Definition: genC.h:87
void reset_current_module_entity(void)
Reset the current module entity.
Definition: static.c:97
void reset_current_module_statement(void)
Reset the current module statement.
Definition: static.c:221
statement set_current_module_statement(statement)
Set the current module statement.
Definition: static.c:165
statement get_current_module_statement(void)
Get the current module statement.
Definition: static.c:208
entity set_current_module_entity(entity)
static.c
Definition: static.c:66
entity get_current_module_entity(void)
Get the entity of the current module.
Definition: static.c:85
bool gen_true2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2785
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
size_t gen_length(const list l)
Definition: list.c:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
list gen_last(list l)
Return the last element of a list.
Definition: list.c:578
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
gen_chunk gen_nth(int n, const list l)
to be used as ENTITY(gen_nth(3, l))...
Definition: list.c:710
string db_get_memory_resource(const char *rname, const char *oname, bool pure)
Return the pointer to the resource, whatever it is.
Definition: database.c:755
#define DB_PUT_MEMORY_RESOURCE(res_name, own_name, res_val)
conform to old interface.
Definition: pipsdbm-local.h:66
sequence statement_sequence(statement)
Get the sequence of a statement sequence.
Definition: statement.c:1328
bool statement_sequence_p(statement)
Statement classes induced from instruction type.
Definition: statement.c:335
bool statement_with_pragma_p(statement)
Test if a statement has some pragma.
Definition: statement.c:3836
list statement_pragmas(statement)
get the list of pragma of a statement s
Definition: statement.c:3851
bool declaration_statement_p(statement)
Had to be optimized according to Beatrice Creusillet.
Definition: statement.c:224
#define debug_on(env)
Definition: misc-local.h:157
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_user_warning
Definition: misc-local.h:146
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define pips_internal_error
Definition: misc-local.h:149
#define debug_off()
Definition: misc-local.h:160
#define pips_user_error
Definition: misc-local.h:147
list strsplit(const char *, const char *)
Definition: string.c:318
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
#define GENERIC_GLOBAL_FUNCTION(name, type)
#define _intFMT
Definition: newgen_types.h:57
static char * module
Definition: pips.c:74
void print_entity_variable(entity e)
print_entity_variable(e)
Definition: entity.c:56
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
const char * entity_user_name(entity e)
Since entity_local_name may contain PIPS special characters such as prefixes (label,...
Definition: entity.c:487
const char * entity_local_name(entity e)
entity_local_name modified so that it does not core when used in vect_fprint, since someone thought t...
Definition: entity.c:453
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
bool expression_call_p(expression e)
Definition: expression.c:415
call expression_call(expression e)
Definition: expression.c:445
#define PRAGMA(x)
PRAGMA.
Definition: ri.h:1991
#define pragma_expression_p(x)
Definition: ri.h:2034
#define pragma_string(x)
Definition: ri.h:2033
#define call_function(x)
Definition: ri.h:709
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define pragma_string_p(x)
Definition: ri.h:2031
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define pragma_expression(x)
Definition: ri.h:2036
#define entity_name(x)
Definition: ri.h:2790
#define sequence_statements(x)
Definition: ri.h:2360
#define statement_declarations(x)
Definition: ri.h:2460
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
#define ifdebug(n)
Definition: sg.c:47
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
ctx_pragma_t: on_cluster on which cluster the pragma may be run (=-1 if run on all cluster) synchro i...
Definition: task_mapping.c:114
bool d_synchro
Definition: task_mapping.c:119
bool d_on_cluster
Definition: task_mapping.c:117
ctx_task_t: pragma information from the pragma task_id id of the task private list of entity,...
Definition: task_mapping.c:313
list private
Definition: task_mapping.c:316
ctx_pragma_t pragma
Definition: task_mapping.c:314
struct ctx_pragma ctx_pragma_t
ctx_pragma_t: on_cluster on which cluster the pragma may be run (=-1 if run on all cluster) synchro i...
static ctx_pragma_t pragma_parse_PRAGMA_DISTRIBUTED(pragma p)
parse the pragma to generate a ctx_pragma_t need to checked that the pragma sended is a PRAGMA_DISTRI...
Definition: task_mapping.c:201
static bool make_task_mapping(__attribute__((unused)) entity module, statement module_statement)
compute the task mapping requires the module statement as param only parse pragma on fisrt level stat...
Definition: task_mapping.c:370
static void assign_statement_task_mapping(statement st, ctx_task_t *ctx)
assign a task for the statement st
Definition: task_mapping.c:348
static string pragma_parameter_unknown_message(string s)
‍**
Definition: task_mapping.c:158
static void compute_private_entity_list(statement st, ctx_task_t *ctx)
compute what it must be add in the private entity list essentially internal declaration of the statem...
Definition: task_mapping.c:335
bool task_mapping(const char *module_name)
PIPS pass.
Definition: task_mapping.c:430
struct ctx_task ctx_task_t
ctx_task_t: pragma information from the pragma task_id id of the task private list of entity,...
#define PRAGMA_DISTRIBUTED
Definition: task_mapping.c:105
static ctx_pragma_t init_ctx_pragma()
init a ctx_pragma_t by default ctx.on_cluster = -1 run on all cluster ctx.synchro = true com synchro
Definition: task_mapping.c:134
static ctx_pragma_t ctx_pragma_merge(ctx_pragma_t ctx1, ctx_pragma_t ctx2)
Merge value of 2 ctx_pragma_t, the 2 ctx_pragma_t can't conflict on value.
Definition: task_mapping.c:252
static void print_ctx_pragma(const ctx_pragma_t ctx)
Definition: task_mapping.c:122
string task_to_string(task t, bool pretty_print)
Definition: task_mapping.c:84
void print_task(task t)
Pass: TASK_MAPPING Debug mode: MPI_GENERATION_DEBUG_LEVEL Resource generated:
Definition: task_mapping.c:73
static void print_ctx_task(const ctx_task_t ctx)
Definition: task_mapping.c:319
static bool pragma_PRAGMA_DISTRIBUTED_p(pragma p)
Test if the pragma is a PRAGMA_DISTRIBUTED check the first element f the pragma.
Definition: task_mapping.c:171
task load_parallel_task_mapping(statement)
void store_or_update_parallel_task_mapping(statement, task)
void init_parallel_task_mapping(void)
void reset_parallel_task_mapping(void)
statement_task get_parallel_task_mapping(void)
#define task_synchronization(x)
Definition: task_private.h:121
#define task_id(x)
Definition: task_private.h:115
#define task_undefined_p(x)
Definition: task_private.h:90
#define task_domain_number(x)
Definition: task_private.h:113
#define task_on_cluster(x)
Definition: task_private.h:119
#define task_domain
newgen_statement_task_domain_defined
Definition: task_private.h:32
#define task_private_data(x)
Definition: task_private.h:117