malleabilityManager.c 36.9 KB
Newer Older
1
#include <pthread.h>
2
#include <string.h>
3
4
//#include "malleabilityManager.h"
#include "MAM.h"
5
#include "malleabilityStates.h"
6
#include "malleabilityDataStructures.h"
7
#include "malleabilityTypes.h"
iker_martin's avatar
iker_martin committed
8
#include "malleabilityZombies.h"
9
#include "malleabilityTimes.h"
10
#include "malleabilityRMS.h"
11
#include "MAM_Init_Configuration.h"
12
#include "spawn_methods/GenericSpawn.h"
13
14
15
16
17
#include "CommDist.h"

#define MALLEABILITY_USE_SYNCHRONOUS 0
#define MALLEABILITY_USE_ASYNCHRONOUS 1

18
void MAM_Commit(int *mam_state);
19
20
21
22

void send_data(int numP_children, malleability_data_t *data_struct, int is_asynchronous);
void recv_data(int numP_parents, malleability_data_t *data_struct, int is_asynchronous);

23

24
25
int MAM_St_rms(int *mam_state);
int MAM_St_spawn_start();
26
27
28
29
30
31
32
33
34
35
36
int MAM_St_spawn_pending(int wait_completed);
int MAM_St_red_start();
int MAM_St_red_pending(int *mam_state, int wait_completed);
int MAM_St_user_pending(int *mam_state, int wait_completed, void (*user_function)(void *), void *user_args);
int MAM_St_user_completed();
int MAM_St_spawn_adapt_pending(int wait_completed);
int MAM_St_spawn_adapted(int *mam_state);
int MAM_St_red_completed(int *mam_state);
int MAM_St_completed(int *mam_state);


37
void Children_init(void (*user_function)(void *), void *user_args);
38
39
int spawn_step();
int start_redistribution();
40
int check_redistribution(int wait_completed);
41
int end_redistribution();
iker_martin's avatar
iker_martin committed
42
int shrink_redistribution();
43
44

int thread_creation();
45
int thread_check(int wait_completed);
46
void* thread_async_work();
47

48
void print_comms_state();
49
void malleability_comms_update(MPI_Comm comm);
50

51
int MAM_I_convert_key(char *key);
52
void MAM_I_create_user_struct(int is_children_group);
53

54
55
56
57
58
malleability_data_t *rep_s_data;
malleability_data_t *dist_s_data;
malleability_data_t *rep_a_data;
malleability_data_t *dist_a_data;

59
60
mam_user_reconf_t *user_reconf;

61
/*
62
63
64
65
66
67
68
69
 * Inicializa la reserva de memoria para el modulo de maleabilidad
 * creando todas las estructuras necesarias y copias de comunicadores
 * para no interferir en la aplicación.
 *
 * Si es llamada por un grupo de procesos creados de forma dinámica,
 * inicializan la comunicacion con sus padres. En este caso, al terminar 
 * la comunicacion los procesos hijo estan preparados para ejecutar la
 * aplicacion.
70
 */
71
int MAM_Init(int root, MPI_Comm *comm, char *name_exec, void (*user_function)(void *), void *user_args) {
72
73
74
75
  MPI_Comm dup_comm, thread_comm;

  mall_conf = (malleability_config_t *) malloc(sizeof(malleability_config_t));
  mall = (malleability_t *) malloc(sizeof(malleability_t));
76
77
78
79
80
81
82
83
  user_reconf = (mam_user_reconf_t *) malloc(sizeof(mam_user_reconf_t));

  MPI_Comm_rank(*comm, &(mall->myId));
  MPI_Comm_size(*comm, &(mall->numP));

  #if USE_MAL_DEBUG
    DEBUG_FUNC("Initializing MaM", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(*comm);
  #endif
84

85
86
87
88
89
  rep_s_data = (malleability_data_t *) malloc(sizeof(malleability_data_t));
  dist_s_data = (malleability_data_t *) malloc(sizeof(malleability_data_t));
  rep_a_data = (malleability_data_t *) malloc(sizeof(malleability_data_t));
  dist_a_data = (malleability_data_t *) malloc(sizeof(malleability_data_t));

90
91
92
93
  MPI_Comm_dup(*comm, &dup_comm);
  MPI_Comm_dup(*comm, &thread_comm);
  MPI_Comm_set_name(dup_comm, "MAM_MAIN");
  MPI_Comm_set_name(thread_comm, "MAM_THREAD");
94
95

  mall->root = root;
iker_martin's avatar
iker_martin committed
96
  mall->root_parents = root;
97
  mall->zombie = 0;
98
  mall->comm = dup_comm;
99
  mall->thread_comm = thread_comm;
100
101
  mall->user_comm = comm; 
  mall->tmp_comm = MPI_COMM_NULL;
102

103
  mall->name_exec = name_exec;
104
  mall->nodelist = NULL;
105
106
107
108
109
110

  rep_s_data->entries = 0;
  rep_a_data->entries = 0;
  dist_s_data->entries = 0;
  dist_a_data->entries = 0;

111
  state = MALL_NOT_STARTED;
112

113
  MAM_Init_configuration();
114
  zombies_service_init();
115
  init_malleability_times();
116
  MAM_Def_main_datatype();
117

118
119
  // Si son el primer grupo de procesos, obtienen los datos de los padres
  MPI_Comm_get_parent(&(mall->intercomm));
120
  if(mall->intercomm != MPI_COMM_NULL) { 
121
    Children_init(user_function, user_args);
122
    return MALLEABILITY_CHILDREN;
123
  }
124

125
126
  MAM_check_hosts();
  MAM_Check_configuration();
iker_martin's avatar
iker_martin committed
127

128
129
130
131
132
  #if USE_MAL_BARRIERS && USE_MAL_DEBUG
    if(mall->myId == mall->root)
      printf("MaM: Using barriers to record times.\n");
  #endif

133
  #if USE_MAL_DEBUG
134
    DEBUG_FUNC("MaM has been initialized correctly as parents", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(*comm);
135
136
  #endif

137
  return MALLEABILITY_NOT_CHILDREN;
138
139
}

140
141
142
143
144
/*
 * Elimina toda la memoria reservado por el modulo
 * de maleabilidad y asegura que los zombies
 * despierten si los hubiese.
 */
145
void MAM_Finalize() {	  
146
147
148
149
150
151
152
153
154
155
  free_malleability_data_struct(rep_s_data);
  free_malleability_data_struct(rep_a_data);
  free_malleability_data_struct(dist_s_data);
  free_malleability_data_struct(dist_a_data);

  free(rep_s_data);
  free(rep_a_data);
  free(dist_s_data);
  free(dist_a_data);

156
  MAM_Free_main_datatype();
157
  free_malleability_times();
158
159
  if(mall->comm != MPI_COMM_WORLD && mall->comm != MPI_COMM_NULL) MPI_Comm_free(&(mall->comm));
  if(mall->thread_comm != MPI_COMM_WORLD && mall->thread_comm != MPI_COMM_NULL) MPI_Comm_free(&(mall->thread_comm));
160
  if(mall->intercomm != MPI_COMM_WORLD && mall->intercomm != MPI_COMM_NULL) { MPI_Comm_disconnect(&(mall->intercomm)); } //FIXME Error en OpenMPI + Merge
161
162
  free(mall);
  free(mall_conf);
163
  free(user_reconf);
iker_martin's avatar
iker_martin committed
164
165
166
167

  zombies_awake();
  zombies_service_free();

168
  state = MALL_UNRESERVED;
169
170
}

171
172
/* 
 * TODO Reescribir
173
174
175
176
 * Comprueba el estado de la maleabilidad. Intenta avanzar en la misma
 * si es posible. Funciona como una máquina de estados.
 * Retorna el estado de la maleabilidad concreto y modifica el argumento
 * "mam_state" a uno generico.
177
 *
178
179
 * El argumento "wait_completed" se utiliza para esperar a la finalización de
 * las tareas llevadas a cabo por parte de MAM.
180
181
 *
 */
182
int MAM_Checkpoint(int *mam_state, int wait_completed, void (*user_function)(void *), void *user_args) {
183
  int call_checkpoint = 0;
184

185
  //TODO This could be changed to an array with the functions to call in each case
186
187
  switch(state) {
    case MALL_UNRESERVED:
188
      *mam_state = MAM_UNRESERVED;
189
190
      break;
    case MALL_NOT_STARTED:
191
192
193
194
      call_checkpoint = MAM_St_rms(mam_state);
      break;
    case MALL_RMS_COMPLETED:
      call_checkpoint = MAM_St_spawn_start();
195
      break;
196

197
    case MALL_SPAWN_PENDING: // Comprueba si el spawn ha terminado
198
    case MALL_SPAWN_SINGLE_PENDING:
199
      call_checkpoint = MAM_St_spawn_pending(wait_completed);
200
      break;
201

202
203
    case MALL_SPAWN_ADAPT_POSTPONE:
    case MALL_SPAWN_COMPLETED:
204
      call_checkpoint = MAM_St_red_start();
205
      break;
206

207
    case MALL_DIST_PENDING:
208
      call_checkpoint = MAM_St_red_pending(mam_state, wait_completed);
209
210
      break;

211
212
    case MALL_USER_PENDING:
      call_checkpoint = MAM_St_user_pending(mam_state, wait_completed, user_function, user_args);
213
      break;
214

215
216
    case MALL_USER_COMPLETED:
      call_checkpoint = MAM_St_user_completed();
217
      break;
218

219
220
    case MALL_SPAWN_ADAPT_PENDING:
      call_checkpoint = MAM_St_spawn_adapt_pending(wait_completed);
221
222
      break;

223
224
225
    case MALL_SPAWN_ADAPTED:
    case MALL_DIST_COMPLETED:
      call_checkpoint = MAM_St_completed(mam_state);
226
227
      break;
  }
228

229
230
  if(call_checkpoint) { MAM_Checkpoint(mam_state, wait_completed, user_function, user_args); }
  if(state > MALL_NOT_STARTED && state < MALL_COMPLETED) *mam_state = MAM_PENDING;
231
232
233
  return state;
}

234
235
236
/*
 * TODO
 */
237
238
239
240
241
242
243
244
void MAM_Resume_redistribution(int *mam_state) {
  state = MALL_USER_COMPLETED;
  *mam_state = MAM_PENDING;
}

/*
 * TODO
 */
245
void MAM_Commit(int *mam_state) {
246
  int zombies = 0;
247
  #if USE_MAL_DEBUG
248
    if(mall->myId == mall->root){ DEBUG_FUNC("Trying to commit", mall->myId, mall->numP); } fflush(stdout);
249
250
  #endif

251
252
253
  // Get times before commiting
  if(mall_conf->spawn_method == MALL_SPAWN_BASELINE) {
    // This communication is only needed when a root process will become a zombie
254
    malleability_times_broadcast(mall->root_collectives);
255
  }
256

257
  // Free unneded communicators
258
259
  if(mall->tmp_comm != MPI_COMM_WORLD && mall->tmp_comm != MPI_COMM_NULL) MPI_Comm_free(&(mall->tmp_comm));
  if(*(mall->user_comm) != MPI_COMM_WORLD && *(mall->user_comm) != MPI_COMM_NULL) MPI_Comm_free(mall->user_comm);
260
261
262
263
264
265
266
267

  // Zombies treatment
  if(mall_conf->spawn_method == MALL_SPAWN_MERGE) {
    MPI_Allreduce(&mall->zombie, &zombies, 1, MPI_INT, MPI_MAX, mall->comm);
    if(zombies) {
      zombies_collect_suspended(mall->comm);
    }
  }
268

269
  // Zombies KILL
270
  if(mall->zombie) {
271
    #if USE_MAL_DEBUG >= 2
272
273
      DEBUG_FUNC("Is terminating as zombie", mall->myId, mall->numP); fflush(stdout);
    #endif
274
    MAM_Finalize();
275
    MPI_Finalize();
276
277
278
    exit(0);
  }

279
280
281
282
  // Reset/Free communicators
  if(mall_conf->spawn_method == MALL_SPAWN_MERGE) { malleability_comms_update(mall->intercomm); }
  if(mall->intercomm != MPI_COMM_NULL && mall->intercomm != MPI_COMM_WORLD) { MPI_Comm_disconnect(&(mall->intercomm)); } //FIXME Error en OpenMPI + Merge

iker_martin's avatar
iker_martin committed
283
284
  MPI_Comm_rank(mall->comm, &mall->myId);
  MPI_Comm_size(mall->comm, &mall->numP);
285
286
  mall->root = mall_conf->spawn_method == MALL_SPAWN_BASELINE ? mall->root : mall->root_parents;
  mall->root_parents = mall->root;
287
  state = MALL_NOT_STARTED;
288
  if(mam_state != NULL) *mam_state = MAM_COMPLETED;
289

290
  // Set new communicator
291
292
  if(mall_conf->spawn_method == MALL_SPAWN_BASELINE) { *(mall->user_comm) = MPI_COMM_WORLD; }
  else if(mall_conf->spawn_method == MALL_SPAWN_MERGE) { MPI_Comm_dup(mall->comm, mall->user_comm); }
293
  #if USE_MAL_DEBUG
294
    if(mall->myId == mall->root) DEBUG_FUNC("Reconfiguration has been commited", mall->myId, mall->numP); fflush(stdout);
295
  #endif
296
297
298
299
300

  #if USE_MAL_BARRIERS
    MPI_Barrier(mall->comm);
  #endif
  mall_conf->times->malleability_end = MPI_Wtime();
301
302
}

303
304
305
306
307
308
309
int MAM_Get_Reconf_Info(mam_user_reconf_t *reconf_info) {
  if(state != MALL_USER_PENDING) return MALL_DENIED;

  *reconf_info = *user_reconf;
  return 0;
}

310
311
void MAM_Retrieve_times(double *sp_time, double *sy_time, double *asy_time, double *mall_time) {
  MAM_I_retrieve_times(sp_time, sy_time, asy_time, mall_time);
312
313
314
315
316
317
318
319
320
}

/*
 * Anyade a la estructura concreta de datos elegida
 * el nuevo set de datos "data" de un total de "total_qty" elementos.
 *
 * Los datos variables se tienen que anyadir cuando quieran ser mandados, no antes
 *
 * Mas informacion en la funcion "add_data".
321
 *
322
 */
323
void malleability_add_data(void *data, size_t total_qty, MPI_Datatype type, int is_replicated, int is_constant) {
324
  size_t total_reqs = 0;
325

326
  if(is_constant) { //Async
327
    if(is_replicated) {
328
      total_reqs = 1;
329
      add_data(data, total_qty, type, total_reqs, rep_a_data);
330
    } else {
331
      if(mall_conf->red_method  == MALL_RED_BASELINE) {
332
        total_reqs = 1;
333
      } else if(mall_conf->red_method  == MALL_RED_POINT || mall_conf->red_method  == MALL_RED_RMA_LOCK || mall_conf->red_method  == MALL_RED_RMA_LOCKALL) {
334
        total_reqs = mall->numC;
335
336
      } 
      if(MAM_Contains_strat(MAM_RED_STRATEGIES, MAM_STRAT_RED_WAIT_TARGETS, NULL)) {
337
338
        total_reqs++;
      }
339
340
341
      
      add_data(data, total_qty, type, total_reqs, dist_a_data);
    }
342
  } else { //Sync
343
344
345
346
347
    if(is_replicated) {
      add_data(data, total_qty, type, total_reqs, rep_s_data);
    } else {
      add_data(data, total_qty, type, total_reqs, dist_s_data);
    }
348
349
350
  }
}

351
352
353
354
355
356
357
358
/*
 * Modifica en la estructura concreta de datos elegida en el indice "index"
 * con el set de datos "data" de un total de "total_qty" elementos.
 *
 * Los datos variables se tienen que modificar cuando quieran ser mandados, no antes
 *
 * Mas informacion en la funcion "modify_data".
 */
359
void malleability_modify_data(void *data, size_t index, size_t total_qty, MPI_Datatype type, int is_replicated, int is_constant) {
360
361
  size_t total_reqs = 0;

362
363
  if(is_constant) {
    if(is_replicated) {
364
      total_reqs = 1;
365
366
367
      modify_data(data, index, total_qty, type, total_reqs, rep_a_data); //FIXME total_reqs==0 ??? 
    } else {    
      if(mall_conf->red_method  == MALL_RED_BASELINE) {
368
        total_reqs = 1;
369
      } else if(mall_conf->red_method  == MALL_RED_POINT || mall_conf->red_method  == MALL_RED_RMA_LOCK || mall_conf->red_method  == MALL_RED_RMA_LOCKALL) {
370
371
        total_reqs = mall->numC;
      }
372
      if(MAM_Contains_strat(MAM_RED_STRATEGIES, MAM_STRAT_RED_WAIT_TARGETS, NULL)) {
373
374
        total_reqs++;
      }
375
      
376
      modify_data(data, index, total_qty, type, total_reqs, dist_a_data);
377
    }
378
379
380
381
382
383
  } else {
    if(is_replicated) {
      modify_data(data, index, total_qty, type, total_reqs, rep_s_data);
    } else {
      modify_data(data, index, total_qty, type, total_reqs, dist_s_data);
    }
384
385
386
  }
}

387
388
389
390
/*
 * Devuelve el numero de entradas para la estructura de descripcion de 
 * datos elegida.
 */
391
void malleability_get_entries(size_t *entries, int is_replicated, int is_constant){
392
393
394
  
  if(is_constant) {
    if(is_replicated) {
395
      *entries = rep_a_data->entries;
396
    } else {
397
      *entries = dist_a_data->entries;
398
399
400
    }
  } else {
    if(is_replicated) {
401
      *entries = rep_s_data->entries;
402
    } else {
403
      *entries = dist_s_data->entries;
404
405
406
407
408
409
410
411
412
413
414
    }
  }
}

/*
 * Devuelve el elemento de la lista "index" al usuario.
 * La devolución es en el mismo orden que lo han metido los padres
 * con la funcion "malleability_add_data()".
 * Es tarea del usuario saber el tipo de esos datos.
 * TODO Refactor a que sea automatico
 */
415
void malleability_get_data(void **data, size_t index, int is_replicated, int is_constant) {
416
417
418
419
  malleability_data_t *data_struct;

  if(is_constant) {
    if(is_replicated) {
420
      data_struct = rep_a_data;
421
    } else {
422
      data_struct = dist_a_data;
423
424
425
    }
  } else {
    if(is_replicated) {
426
      data_struct = rep_s_data;
427
    } else {
428
      data_struct = dist_s_data;
429
430
431
    }
  }

432
  *data = data_struct->arrays[index];
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
}


//======================================================||
//================PRIVATE FUNCTIONS=====================||
//================DATA COMMUNICATION====================||
//======================================================||
//======================================================||

/*
 * Funcion generalizada para enviar datos desde los hijos.
 * La asincronizidad se refiere a si el hilo padre e hijo lo hacen
 * de forma bloqueante o no. El padre puede tener varios hilos.
 */
void send_data(int numP_children, malleability_data_t *data_struct, int is_asynchronous) {
448
  size_t i;
449
  void *aux_send, *aux_recv;
450
451
452

  if(is_asynchronous) {
    for(i=0; i < data_struct->entries; i++) {
453
      aux_send = data_struct->arrays[i];
454
      aux_recv = NULL;
455
      async_communication_start(aux_send, &aux_recv, data_struct->qty[i], data_struct->types[i], mall->numP, numP_children, MALLEABILITY_NOT_CHILDREN,  
456
		      mall->intercomm, &(data_struct->requests[i]), &(data_struct->request_qty[i]), &(data_struct->windows[i]));
457
      if(aux_recv != NULL) data_struct->arrays[i] = aux_recv;
458
459
460
    }
  } else {
    for(i=0; i < data_struct->entries; i++) {
461
      aux_send = data_struct->arrays[i];
462
      aux_recv = NULL;
463
      sync_communication(aux_send, &aux_recv, data_struct->qty[i], data_struct->types[i], mall->numP, numP_children, MALLEABILITY_NOT_CHILDREN, mall->intercomm);
464
      if(aux_recv != NULL) data_struct->arrays[i] = aux_recv;
465
466
467
468
469
470
471
472
473
474
    }
  }
}

/*
 * Funcion generalizada para recibir datos desde los hijos.
 * La asincronizidad se refiere a si el hilo padre e hijo lo hacen
 * de forma bloqueante o no. El padre puede tener varios hilos.
 */
void recv_data(int numP_parents, malleability_data_t *data_struct, int is_asynchronous) {
475
  size_t i;
476
  void *aux, *aux_s = NULL;
477
478
479

  if(is_asynchronous) {
    for(i=0; i < data_struct->entries; i++) {
480
      aux = data_struct->arrays[i];
481
      async_communication_start(aux_s, &aux, data_struct->qty[i], data_struct->types[i], mall->numP, numP_parents, MALLEABILITY_CHILDREN,
482
		      mall->intercomm, &(data_struct->requests[i]), &(data_struct->request_qty[i]), &(data_struct->windows[i]));
483
      data_struct->arrays[i] = aux;
484
485
486
    }
  } else {
    for(i=0; i < data_struct->entries; i++) {
487
      aux = data_struct->arrays[i];
488
      sync_communication(aux_s, &aux, data_struct->qty[i], data_struct->types[i], mall->numP, numP_parents, MALLEABILITY_CHILDREN, mall->intercomm);
489
      data_struct->arrays[i] = aux;
490
491
492
493
    }
  }
}

494
495
496
497
498
499

//======================================================||
//================PRIVATE FUNCTIONS=====================||
//====================MAM STAGES========================||
//======================================================||
//======================================================||
500
501
502
503
//======================================================||
//======================================================||
//======================================================||
//======================================================||
504

505
int MAM_St_rms(int *mam_state) {
506
  *mam_state = MAM_NOT_STARTED;
507
  state = MALL_RMS_COMPLETED;
508
509
510
511
512
513
514
515
  reset_malleability_times();
  // Comprobar si se tiene que realizar un redimensionado
      
  #if USE_MAL_BARRIERS
    MPI_Barrier(mall->comm);
  #endif
  mall_conf->times->malleability_start = MPI_Wtime();
  //if(CHECK_RMS()) {return MALL_DENIED;}
516
517
  return 1;
}
518

519
int MAM_St_spawn_start() {
520
521
522
523
524
525
526
527
528
529
530
531
  state = spawn_step();
  //FIXME Esto es necesario pero feo
  if(mall_conf->spawn_method == MALL_SPAWN_MERGE && mall->myId >= mall->numC){ mall->zombie = 1; }
  else if(mall_conf->spawn_method == MALL_SPAWN_BASELINE){ mall->zombie = 1; }

  if (state == MALL_SPAWN_COMPLETED || state == MALL_SPAWN_ADAPT_POSTPONE){
    return 1;
  }
  return 0;
}

int MAM_St_spawn_pending(int wait_completed) {
532
533
534
  fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
  if(mall->myId == 0)printf("TEST END\n");
  fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
535
536
537
538
539
540
541
542
543
544
545
546
  state = check_spawn_state(&(mall->intercomm), mall->comm, wait_completed);
  if (state == MALL_SPAWN_COMPLETED || state == MALL_SPAWN_ADAPTED) {
    #if USE_MAL_BARRIERS
      MPI_Barrier(mall->comm);
    #endif
    mall_conf->times->spawn_time = MPI_Wtime() - mall_conf->times->malleability_start;
    return 1;
  }
  return 0;
}

int MAM_St_red_start() {
547
548
549
550
551
552
  if(MAM_Contains_strat(MAM_SPAWN_STRATEGIES, MAM_STRAT_SPAWN_INTERCOMM, NULL)) {
    mall->root_collectives = mall->myId == mall->root ? MPI_ROOT : MPI_PROC_NULL;
  } else {
    mall->root_collectives = mall->root;
  }

553
554
555
556
557
  state = start_redistribution();
  return 1;
}

int MAM_St_red_pending(int *mam_state, int wait_completed) {
558
  if(MAM_Contains_strat(MAM_RED_STRATEGIES, MAM_STRAT_RED_PTHREAD, NULL)) {
559
560
561
562
563
564
    state = thread_check(wait_completed);
  } else {
    state = check_redistribution(wait_completed);
  }

  if(state != MALL_DIST_PENDING) { 
565
    if(MAM_Contains_strat(MAM_SPAWN_STRATEGIES, MAM_STRAT_SPAWN_INTERCOMM, NULL)) {
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
      MPI_Intercomm_merge(mall->intercomm, MALLEABILITY_NOT_CHILDREN, &mall->tmp_comm); //El que pone 0 va primero
    } else {
      MPI_Comm_dup(mall->intercomm, &mall->tmp_comm);
    }
    MPI_Comm_set_name(mall->tmp_comm, "MAM_USER_TMP");
    state = MALL_USER_PENDING;
    *mam_state = MAM_USER_PENDING;
    return 1;
  }
  return 0;
}

int MAM_St_user_pending(int *mam_state, int wait_completed, void (*user_function)(void *), void *user_args) {
  #if USE_MAL_DEBUG
    if(mall->myId == mall->root) DEBUG_FUNC("Starting USER redistribution", mall->myId, mall->numP); fflush(stdout);
  #endif
  if(user_function != NULL) {
    MAM_I_create_user_struct(MALLEABILITY_NOT_CHILDREN);
    do {
      user_function(user_args);
    } while(wait_completed && state == MALL_USER_PENDING);
  } else {
    MAM_Resume_redistribution(mam_state);
  }

  if(state != MALL_USER_PENDING) {
    #if USE_MAL_DEBUG
      if(mall->myId == mall->root) DEBUG_FUNC("Ended USER redistribution", mall->myId, mall->numP); fflush(stdout);
    #endif
    return 1;
  }
  return 0;
}

int MAM_St_user_completed() {
  state = end_redistribution();
  return 1;
}

int MAM_St_spawn_adapt_pending(int wait_completed) {
  #if USE_MAL_BARRIERS
    MPI_Barrier(mall->comm);
  #endif
  mall_conf->times->spawn_start = MPI_Wtime();
  unset_spawn_postpone_flag(state);
  state = check_spawn_state(&(mall->intercomm), mall->comm, wait_completed);

613
  if(!MAM_Contains_strat(MAM_SPAWN_STRATEGIES, MAM_STRAT_SPAWN_PTHREAD, NULL)) {
614
615
616
617
618
619
620
621
622
623
    #if USE_MAL_BARRIERS
      MPI_Barrier(mall->comm);
    #endif
    mall_conf->times->spawn_time = MPI_Wtime() - mall_conf->times->malleability_start;
    return 1;
  }
  return 0;
}

int MAM_St_completed(int *mam_state) {
624
  MAM_Commit(mam_state);
625
626
627
628
  return 0;
}


629
630
631
632
633
//======================================================||
//================PRIVATE FUNCTIONS=====================||
//=====================CHILDREN=========================||
//======================================================||
//======================================================||
634
635
636
637
//======================================================||
//======================================================||
//======================================================||
//======================================================||
638
639
640
641
642
643
/*
 * Inicializacion de los datos de los hijos.
 * En la misma se reciben datos de los padres: La configuracion
 * de la ejecucion a realizar; y los datos a recibir de los padres
 * ya sea de forma sincrona, asincrona o ambas.
 */
644
void Children_init(void (*user_function)(void *), void *user_args) {
645
  size_t i;
646

647
648
649
650
  #if USE_MAL_DEBUG
    DEBUG_FUNC("MaM will now initialize children", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
  #endif

iker_martin's avatar
iker_martin committed
651
  malleability_connect_children(mall->comm, &(mall->intercomm));
652
  if(mall_conf->spawn_method == MALL_SPAWN_MERGE) { // For Merge Method, these processes will be added
iker_martin's avatar
iker_martin committed
653
654
    MPI_Comm_rank(mall->intercomm, &mall->myId);
    MPI_Comm_size(mall->intercomm, &mall->numP);
655
  }
656
  mall->root_collectives = mall->root_parents;
657

658
  #if USE_MAL_DEBUG
659
    DEBUG_FUNC("Targets have completed spawn step", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
660
661
  #endif

662
  comm_data_info(rep_a_data, dist_a_data, MALLEABILITY_CHILDREN);
663
  if(dist_a_data->entries || rep_a_data->entries) { // Recibir datos asincronos
664
665
666
    #if USE_MAL_DEBUG >= 2
      DEBUG_FUNC("Children start asynchronous redistribution", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
    #endif
667
668
669
    #if USE_MAL_BARRIERS
      MPI_Barrier(mall->intercomm);
    #endif
670

671
    if(MAM_Contains_strat(MAM_RED_STRATEGIES, MAM_STRAT_RED_PTHREAD, NULL)) {
iker_martin's avatar
iker_martin committed
672
      recv_data(mall->num_parents, dist_a_data, MALLEABILITY_USE_SYNCHRONOUS);
673
      for(i=0; i<rep_a_data->entries; i++) {
674
        MPI_Bcast(rep_a_data->arrays[i], rep_a_data->qty[i], rep_a_data->types[i], mall->root_collectives, mall->intercomm);
675
      } 
676
    } else {
iker_martin's avatar
iker_martin committed
677
      recv_data(mall->num_parents, dist_a_data, MALLEABILITY_USE_ASYNCHRONOUS); 
678

679
      for(i=0; i<rep_a_data->entries; i++) {
680
        MPI_Ibcast(rep_a_data->arrays[i], rep_a_data->qty[i], rep_a_data->types[i], mall->root_collectives, mall->intercomm, &(rep_a_data->requests[i][0]));
681
      } 
682
      #if USE_MAL_DEBUG >= 2
683
        DEBUG_FUNC("Targets started asynchronous redistribution", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
684
      #endif
685
686

      int post_ibarrier = 0; 
687
688
689
690
      // FIXME No permite el uso de ibarrier ahora mismo. Realmente solo hace falta un ibarrier para todos
      for(i=0; i<rep_a_data->entries; i++) {
        async_communication_wait(mall->intercomm, rep_a_data->requests[i], rep_a_data->request_qty[i], post_ibarrier);
      }
691
      if(MAM_Contains_strat(MAM_RED_STRATEGIES, MAM_STRAT_RED_WAIT_TARGETS, NULL)) { post_ibarrier=1; }
692
      for(i=0; i<dist_a_data->entries; i++) {
693
        async_communication_wait(mall->intercomm, dist_a_data->requests[i], dist_a_data->request_qty[i], post_ibarrier);
694
      }
695
      #if USE_MAL_DEBUG >= 2
696
        DEBUG_FUNC("Targets waited for all asynchronous redistributions", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
697
      #endif
698
      for(i=0; i<dist_a_data->entries; i++) {
699
        async_communication_end(dist_a_data->requests[i], dist_a_data->request_qty[i], &(dist_a_data->windows[i]));
700
      }
701
      for(i=0; i<rep_a_data->entries; i++) {
702
        async_communication_end(rep_a_data->requests[i], rep_a_data->request_qty[i], &(rep_a_data->windows[i]));
703
      }
704
    }
705

706
707
708
    #if USE_MAL_BARRIERS
      MPI_Barrier(mall->intercomm);
    #endif
709
    mall_conf->times->async_end= MPI_Wtime(); // Obtener timestamp de cuando termina comm asincrona
710
  }
711
  #if USE_MAL_DEBUG
712
    DEBUG_FUNC("Targets have completed asynchronous data redistribution step", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
713
  #endif
714

715
  if(MAM_Contains_strat(MAM_SPAWN_STRATEGIES, MAM_STRAT_SPAWN_INTERCOMM, NULL)) {
716
717
718
719
720
721
722
723
724
725
726
    MPI_Intercomm_merge(mall->intercomm, MALLEABILITY_CHILDREN, &mall->tmp_comm); //El que pone 0 va primero
  } else {
    MPI_Comm_dup(mall->intercomm, &mall->tmp_comm);
  }
  MPI_Comm_set_name(mall->tmp_comm, "MAM_USER_TMP");
  if(user_function != NULL) {
    state = MALL_USER_PENDING;
    MAM_I_create_user_struct(MALLEABILITY_CHILDREN);
    user_function(user_args);
  }

727
  comm_data_info(rep_s_data, dist_s_data, MALLEABILITY_CHILDREN);
728
  if(dist_s_data->entries || rep_s_data->entries) { // Recibir datos sincronos
729
730
731
    #if USE_MAL_BARRIERS
      MPI_Barrier(mall->intercomm);
    #endif
iker_martin's avatar
iker_martin committed
732
    recv_data(mall->num_parents, dist_s_data, MALLEABILITY_USE_SYNCHRONOUS);
733
734

    for(i=0; i<rep_s_data->entries; i++) {
735
      MPI_Bcast(rep_s_data->arrays[i], rep_s_data->qty[i], rep_s_data->types[i], mall->root_collectives, mall->intercomm);
736
    } 
737
738
739
    #if USE_MAL_BARRIERS
      MPI_Barrier(mall->intercomm);
    #endif
740
    mall_conf->times->sync_end = MPI_Wtime(); // Obtener timestamp de cuando termina comm sincrona
741
  }
742
  #if USE_MAL_DEBUG
743
    DEBUG_FUNC("Targets have completed synchronous data redistribution step", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
744
  #endif
745

746
  MAM_Commit(NULL);
747

748
  #if USE_MAL_DEBUG
749
    DEBUG_FUNC("MaM has been initialized correctly for new ranks", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
750
  #endif
751
752
753
754
755
756
757
}

//======================================================||
//================PRIVATE FUNCTIONS=====================||
//=====================PARENTS==========================||
//======================================================||
//======================================================||
758
759
//======================================================||
//======================================================||
760
761
762
763
764
765

/*
 * Se encarga de realizar la creacion de los procesos hijos.
 * Si se pide en segundo plano devuelve el estado actual.
 */
int spawn_step(){
766
767
768
  #if USE_MAL_BARRIERS
    MPI_Barrier(mall->comm);
  #endif
769
  mall_conf->times->spawn_start = MPI_Wtime();
770
 
iker_martin's avatar
iker_martin committed
771
  state = init_spawn(mall->thread_comm, &(mall->intercomm));
772

773
  if(!MAM_Contains_strat(MAM_SPAWN_STRATEGIES, MAM_STRAT_SPAWN_PTHREAD, NULL)) {
774
775
776
      #if USE_MAL_BARRIERS
        MPI_Barrier(mall->comm);
      #endif
777
      mall_conf->times->spawn_time = MPI_Wtime() - mall_conf->times->malleability_start;
778
779
780
781
  }
  return state;
}

782

783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
/*
 * Comienza la redistribucion de los datos con el nuevo grupo de procesos.
 *
 * Primero se envia la configuracion a utilizar al nuevo grupo de procesos y a continuacion
 * se realiza el envio asincrono y/o sincrono si lo hay.
 *
 * En caso de que haya comunicacion asincrona, se comienza y se termina la funcion 
 * indicando que se ha comenzado un envio asincrono.
 *
 * Si no hay comunicacion asincrono se pasa a realizar la sincrona si la hubiese.
 *
 * Finalmente se envian datos sobre los resultados a los hijos y se desconectan ambos
 * grupos de procesos.
 */
int start_redistribution() {
798
  size_t i;
799

800
  if(mall->intercomm == MPI_COMM_NULL) {
801
802
    // Si no tiene comunicador creado, se debe a que se ha pospuesto el Spawn
    //   y se trata del spawn Merge Shrink
803
    MPI_Comm_dup(mall->comm, &(mall->intercomm));
804
  }
805

806
  comm_data_info(rep_a_data, dist_a_data, MALLEABILITY_NOT_CHILDREN);
807
  if(dist_a_data->entries || rep_a_data->entries) { // Enviar datos asincronos
808
809
810
    #if USE_MAL_BARRIERS
      MPI_Barrier(mall->intercomm);
    #endif
811
    mall_conf->times->async_start = MPI_Wtime();
812
    if(MAM_Contains_strat(MAM_RED_STRATEGIES, MAM_STRAT_RED_PTHREAD, NULL)) {
813
814
815
      return thread_creation();
    } else {
      send_data(mall->numC, dist_a_data, MALLEABILITY_USE_ASYNCHRONOUS);
816
      for(i=0; i<rep_a_data->entries; i++) { //FIXME Ibarrier does not work with rep_a_data
817
        MPI_Ibcast(rep_a_data->arrays[i], rep_a_data->qty[i], rep_a_data->types[i], mall->root_collectives, mall->intercomm, &(rep_a_data->requests[i][0]));
818
      } 
819
      return MALL_DIST_PENDING; 
820
821
    }
  } 
822
  return MALL_USER_PENDING;
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
}


/*
 * Comprueba si la redistribucion asincrona ha terminado. 
 * Si no ha terminado la funcion termina indicandolo, en caso contrario,
 * se continua con la comunicacion sincrona, el envio de resultados y
 * se desconectan los grupos de procesos.
 *
 * Esta funcion permite dos modos de funcionamiento al comprobar si la
 * comunicacion asincrona ha terminado.
 * Si se utiliza el modo "MAL_USE_NORMAL" o "MAL_USE_POINT", se considera 
 * terminada cuando los padres terminan de enviar.
 * Si se utiliza el modo "MAL_USE_IBARRIER", se considera terminada cuando
 * los hijos han terminado de recibir.
838
 * //FIXME Modificar para que se tenga en cuenta rep_a_data
839
 */
840
int check_redistribution(int wait_completed) {
841
  int completed, local_completed, all_completed, post_ibarrier;
842
  size_t i, req_qty;
843
  MPI_Request *req_completed;
844
  MPI_Win window;
845
  post_ibarrier = 0;
846
  local_completed = 1;
847
  #if USE_MAL_DEBUG >= 2
848
    DEBUG_FUNC("Sources are testing for all asynchronous redistributions", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
849
  #endif
850

851
  if(wait_completed) {
852
    if(MAM_Contains_strat(MAM_RED_STRATEGIES, MAM_STRAT_RED_WAIT_TARGETS, NULL)) {
853
      if(mall_conf->spawn_method == MALL_SPAWN_BASELINE || mall->myId >= mall->numC) {
854
855
856
857
858
859
860
861
        post_ibarrier=1;
      }
    }
    for(i=0; i<dist_a_data->entries; i++) {
      req_completed = dist_a_data->requests[i];
      req_qty = dist_a_data->request_qty[i];
      async_communication_wait(mall->intercomm, req_completed, req_qty, post_ibarrier);
    }
862
863
864
865
866
    for(i=0; i<rep_a_data->entries; i++) {
      req_completed = rep_a_data->requests[i];
      req_qty = rep_a_data->request_qty[i];
      async_communication_wait(mall->intercomm, req_completed, req_qty, 0); //FIXME Ibarrier does not work with rep_a_data
    }
867
868
869
870
  } else {
    for(i=0; i<dist_a_data->entries; i++) {
      req_completed = dist_a_data->requests[i];
      req_qty = dist_a_data->request_qty[i];
871
      completed = async_communication_check(MALLEABILITY_NOT_CHILDREN, mall->intercomm, req_completed, req_qty);
872
873
      local_completed = local_completed && completed;
    }
874
875
876
    for(i=0; i<rep_a_data->entries; i++) { //FIXME Ibarrier does not work with rep_a_data
      req_completed = rep_a_data->requests[i];
      req_qty = rep_a_data->request_qty[i];
877
      completed = async_communication_check(MALLEABILITY_NOT_CHILDREN, mall->intercomm, req_completed, req_qty);
878
879
      local_completed = local_completed && completed;
    }
880
881
882
883
884
885
    #if USE_MAL_DEBUG >= 2
      DEBUG_FUNC("Sources will now check a global decision", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
    #endif

    MPI_Allreduce(&local_completed, &all_completed, 1, MPI_INT, MPI_MIN, mall->comm);
    if(!all_completed) return MALL_DIST_PENDING; // Continue only if asynchronous send has ended 
886
887
  }

888
  #if USE_MAL_DEBUG >= 2
889
    DEBUG_FUNC("Sources sent asynchronous redistributions", mall->myId, mall->numP); fflush(stdout); MPI_Barrier(MPI_COMM_WORLD);
890
  #endif
891

892
893
894
895
  for(i=0; i<dist_a_data->entries; i++) {
    req_completed = dist_a_data->requests[i];
    req_qty = dist_a_data->request_qty[i];
    window = dist_a_data->windows[i];
896
    async_communication_end(req_completed, req_qty, &window);
897
  }
898
899
900
901
  for(i=0; i<rep_a_data->entries; i++) {
    req_completed = rep_a_data->requests[i];
    req_qty = rep_a_data->request_qty[i];
    window = rep_a_data->windows[i];
902
    async_communication_end(req_completed, req_qty, &window);
903
  }
904

905
906
907
  #if USE_MAL_BARRIERS
    MPI_Barrier(mall->intercomm);
  #endif
908
  if(mall_conf->spawn_method == MALL_SPAWN_MERGE) mall_conf->times->async_end = MPI_Wtime(); // Merge method only
909
  return MALL_USER_PENDING;
910
911
912
913
914
915
916
917
918
919
920
921
}


/*
 * Termina la redistribución de los datos con los hijos, comprobando
 * si se han realizado iteraciones con comunicaciones en segundo plano
 * y enviando cuantas iteraciones se han realizado a los hijos.
 *
 * Además se realizan las comunicaciones síncronas se las hay.
 * Finalmente termina enviando los datos temporales a los hijos.
 */ 
int end_redistribution() {
922
  size_t i;
923
  int local_state;
924

925
  comm_data_info(rep_s_data, dist_s_data, MALLEABILITY_NOT_CHILDREN);
926
  if(dist_s_data->entries || rep_s_data->entries) { // Enviar datos sincronos
927
928
929
    #if USE_MAL_BARRIERS
      MPI_Barrier(mall->intercomm);
    #endif
930
    mall_conf->times->sync_start = MPI_Wtime();
931
932
933
    send_data(mall->numC, dist_s_data, MALLEABILITY_USE_SYNCHRONOUS);

    for(i=0; i<rep_s_data->entries; i++) {
934
      MPI_Bcast(rep_s_data->arrays[i], rep_s_data->qty[i], rep_s_data->types[i], mall->root_collectives, mall->intercomm);
935
    } 
936
937
938
    #if USE_MAL_BARRIERS
      MPI_Barrier(mall->intercomm);
    #endif
939
    if(mall_conf->spawn_method == MALL_SPAWN_MERGE) mall_conf->times->sync_end = MPI_Wtime(); // Merge method only
940
  }
iker_martin's avatar
iker_martin committed
941

942
  local_state = MALL_DIST_COMPLETED;
943
944
  if(mall_conf->spawn_method == MALL_SPAWN_MERGE && mall->numP > mall->numC) { // Merge Shrink
    local_state = MALL_SPAWN_ADAPT_PENDING;
945
  }
946

947
  return local_state;
948
949
950
951
952
953
954
955
956
}

// TODO MOVER A OTRO LADO??
//======================================================||
//================PRIVATE FUNCTIONS=====================||
//===============COMM PARENTS THREADS===================||
//======================================================||
//======================================================||

957
958

int comm_state; //FIXME Usar un handler
959
960
961
962
/*
 * Crea una hebra para ejecutar una comunicación en segundo plano.
 */
int thread_creation() {
963
  comm_state = MALL_DIST_PENDING;
964
965
966
967
968
  if(pthread_create(&(mall->async_thread), NULL, thread_async_work, NULL)) {
    printf("Error al crear el hilo\n");
    MPI_Abort(MPI_COMM_WORLD, -1);
    return -1;
  }
969
  return comm_state;
970
971
972
973
974
975
976
977
}

/*
 * Comprobación por parte de una hebra maestra que indica
 * si una hebra esclava ha terminado su comunicación en segundo plano.
 *
 * El estado de la comunicación es devuelto al finalizar la función. 
 */
978
int thread_check(int wait_completed) {
979
  int all_completed = 0;
980

981
982
983
984
985
986
987
988
  if(wait_completed && comm_state == MALL_DIST_PENDING) {
    if(pthread_join(mall->async_thread, NULL)) {
      printf("Error al esperar al hilo\n");
      MPI_Abort(MPI_COMM_WORLD, -1);
      return -2;
    } 
  }

989
  // Comprueba que todos los hilos han terminado la distribucion (Mismo valor en commAsync)
990
  MPI_Allreduce(&comm_state, &all_completed, 1, MPI_INT, MPI_MAX, mall->comm);
991
992
  if(all_completed != MALL_DIST_COMPLETED) return MALL_DIST_PENDING; // Continue only if asynchronous send has ended 
  //FIXME No se tiene en cuenta el estado MALL_APP_ENDED
993
994
995
996
997
998

  if(pthread_join(mall->async_thread, NULL)) {
    printf("Error al esperar al hilo\n");
    MPI_Abort(MPI_COMM_WORLD, -1);
    return -2;
  } 
999
1000
1001
1002

  #if USE_MAL_BARRIERS
    MPI_Barrier(mall->intercomm);
  #endif
1003
  if(mall_conf->spawn_method == MALL_SPAWN_MERGE) mall_conf->times->async_end = MPI_Wtime(); // Merge method only
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
  return end_redistribution();
}


/*
 * Función ejecutada por una hebra.
 * Ejecuta una comunicación síncrona con los hijos que
 * para el usuario se puede considerar como en segundo plano.
 *
 * Cuando termina la comunicación la hebra maestra puede comprobarlo
 * por el valor "commAsync".
 */
1016
void* thread_async_work() {
1017
1018
  size_t i;

1019
  send_data(mall->numC, dist_a_data, MALLEABILITY_USE_SYNCHRONOUS);
1020
  for(i=0; i<rep_a_data->entries; i++) {
1021
    MPI_Bcast(rep_a_data->arrays[i], rep_a_data->qty[i], rep_a_data->types[i], mall->root_collectives, mall->intercomm);
1022
  } 
1023
  comm_state = MALL_DIST_COMPLETED;
1024
1025
  pthread_exit(NULL);
}
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037


//==============================================================================
/*
 * Muestra por pantalla el estado actual de todos los comunicadores
 */
void print_comms_state() {
  int tester;
  char *test = malloc(MPI_MAX_OBJECT_NAME * sizeof(char));

  MPI_Comm_get_name(mall->comm, test, &tester);
  printf("P%d Comm=%d Name=%s\n", mall->myId, mall->comm, test);
1038
1039
  MPI_Comm_get_name(*(mall->user_comm), test, &tester);
  printf("P%d Comm=%d Name=%s\n", mall->myId, *(mall->user_comm), test);
1040
1041
1042
1043
1044
1045
  if(mall->intercomm != MPI_COMM_NULL) {
    MPI_Comm_get_name(mall->intercomm, test, &tester);
    printf("P%d Comm=%d Name=%s\n", mall->myId, mall->intercomm, test);
  }
  free(test);
}
1046

1047
1048
1049
/*
 * Función solo necesaria en Merge
 */
1050
1051
1052
1053
1054
1055
1056
void malleability_comms_update(MPI_Comm comm) {
  if(mall->thread_comm != MPI_COMM_WORLD) MPI_Comm_free(&(mall->thread_comm));
  if(mall->comm != MPI_COMM_WORLD) MPI_Comm_free(&(mall->comm));

  MPI_Comm_dup(comm, &(mall->thread_comm));
  MPI_Comm_dup(comm, &(mall->comm));

1057
1058
1059
1060
1061
1062
1063
  MPI_Comm_set_name(mall->thread_comm, "MAM_THREAD");
  MPI_Comm_set_name(mall->comm, "MAM_MAIN");
}

/*
 * TODO Por hacer
 */
1064
void MAM_I_create_user_struct(int is_children_group) {
1065
1066
1067
  user_reconf->comm = mall->tmp_comm;

  if(is_children_group) {
1068
    user_reconf->rank_state = MAM_PROC_NEW_RANK;
iker_martin's avatar
iker_martin committed
1069
1070
1071
    user_reconf->numS = mall->num_parents;
    if(mall_conf->spawn_method == MALL_SPAWN_BASELINE) user_reconf->numT = mall->numP;
    else user_reconf->numT = mall->num_parents + mall->numP;
1072
1073
1074
  } else {
    user_reconf->numS = mall->numP;
    user_reconf->numT = mall->numC;
1075
1076
    if(mall->zombie) user_reconf->rank_state = MAM_PROC_ZOMBIE;
    else user_reconf->rank_state = MAM_PROC_CONTINUE;
1077
1078
  }
}