Main.c 21.5 KB
Newer Older
1
2
3
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
iker_martin's avatar
iker_martin committed
4
5
#include <fcntl.h>
#include <sys/stat.h>
6
#include <pthread.h>
7
#include "computing_func.h"
8
#include "../IOcodes/read_ini.h"
9
#include "../IOcodes/results.h"
iker_martin's avatar
iker_martin committed
10
11
#include "../malleability/ProcessDist.h"
#include "../malleability/CommDist.h"
12
13
14

#define ROOT 0

iker_martin's avatar
iker_martin committed
15
16
17
int work();
void Sons_init();

18
int checkpoint(int iter, int state, MPI_Request **comm_req);
19
int TC(int numS, int comm_type);
20
int start_redistribution(int iter, int numS, MPI_Request **comm_req);
21
int check_redistribution(int iter, MPI_Request **comm_req);
22
23
24
int end_redistribution(int iter);

int thread_creation();
25
int thread_check(int iter);
26
void* thread_async_work(void* void_arg);
iker_martin's avatar
iker_martin committed
27

28
void iterate(double *matrix, int n, int async_comm);
29

30
void init_group_struct(char *argv[], int argc, int myId, int numP);
31
void init_application();
32
void obtain_op_times();
33
34
void free_application_data();

35
void print_general_info(int myId, int grp, int numP);
36
int print_final_results();
iker_martin's avatar
iker_martin committed
37
int create_out_file(char *nombre, int *ptr, int newstdout);
38

iker_martin's avatar
iker_martin committed
39
40
41
42
typedef struct {
  int myId;
  int numP;
  int grp;
43
  int iter_start;
44
  int argc;
iker_martin's avatar
iker_martin committed
45

46
47
  int numS; // Cantidad de procesos hijos
  int commAsync;
iker_martin's avatar
iker_martin committed
48
  MPI_Comm children, parents;
49
50

  char *compute_comm_array;
iker_martin's avatar
iker_martin committed
51
  char **argv;
52
  char *sync_array, *async_array;
iker_martin's avatar
iker_martin committed
53
54
} group_data;

55
56
57
58
59
60
typedef struct {
  int myId, numP, numS, adr;
  MPI_Comm children;
  char *sync_array;
} thread_data;

iker_martin's avatar
iker_martin committed
61
62
configuration *config_file;
group_data *group;
63
results_data *results;
64
int run_id = 0; // Utilizado para diferenciar más fácilmente ejecuciones en el análisis
65

66
67
pthread_t async_thread; // TODO Cambiar de sitio?

68
int main(int argc, char *argv[]) {
69
    int numP, myId, res;
iker_martin's avatar
iker_martin committed
70
    int req;
71

72
    MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &req);
73
    MPI_Comm_size(MPI_COMM_WORLD, &numP);
iker_martin's avatar
iker_martin committed
74
75
    MPI_Comm_rank(MPI_COMM_WORLD, &myId);

76
77
78
79
    if(req != MPI_THREAD_MULTIPLE) {
      printf("No se ha obtenido la configuración de hilos necesaria\nSolicitada %d -- Devuelta %d\n", req, MPI_THREAD_MULTIPLE);
    }

80
    init_group_struct(argv, argc, myId, numP);
81
82
83
84
85
86
87

    MPI_Comm_get_parent(&(group->parents));
    if(group->parents == MPI_COMM_NULL ) { // Si son el primer grupo de procesos, recogen la configuracion inicial
      init_application();
    } else { // Si son procesos hijos deben comunicarse con las padres
      Sons_init();
    }
iker_martin's avatar
iker_martin committed
88

89
90
91
    if(group->grp == 0) {
      MPI_Barrier(MPI_COMM_WORLD);
      results->exec_start = MPI_Wtime();
92
    }
93

94
    res = work();
95

96
97
98
    if(res) { // Se he llegado al final de la aplicacion
      MPI_Barrier(MPI_COMM_WORLD);
      results->exec_time = MPI_Wtime() - results->exec_start;
99
    }
100
101
102
    print_final_results();

    free_application_data();
103
104
105
106
107
    MPI_Finalize();
    return 0;
}

/*
108
109
110
111
112
113
114
115
116
 * Función de trabajo principal.
 *
 * Incializa los datos para realizar el computo y a continuacion
 * pasa a realizar "maxiter" iteraciones de computo.
 *
 * Terminadas las iteraciones realiza el redimensionado de procesos.
 * Si el redimensionado se realiza de forma asincrona se 
 * siguen realizando iteraciones de computo hasta que termine la 
 * comunicacion asincrona y realizar entonces la sincrona.
117
118
119
120
 *
 * Si el grupo de procesos es el ultimo que va a ejecutar, se devuelve
 * el valor 1 para indicar que no se va a seguir trabajando con nuevos grupos
 * de procesos. En caso contrario se devuelve 0.
121
 */
iker_martin's avatar
iker_martin committed
122
int work() {
123
  int iter, maxiter, state, res;
124
  double *matrix;
125
  MPI_Request *async_comm;
126

iker_martin's avatar
iker_martin committed
127
  maxiter = config_file->iters[group->grp];
128
  //initMatrix(&matrix, config_file->matrix_tam);
129
  state = MAL_COMM_UNINITIALIZED;
iker_martin's avatar
iker_martin committed
130

131
  res = 0;
132
  //if(group->myId == ROOT) printf("Iter_start %d\n", group->iter_start);
133
  for(iter=group->iter_start; iter < maxiter; iter++) {
134
    iterate(matrix, config_file->matrix_tam, state);
135
  }
136
  state = checkpoint(iter, state, &async_comm);
137
  
138
  iter = 0;
139
  while(state == MAL_ASYNC_PENDING || state == COMM_IN_PROGRESS) {
140
    iterate(matrix, config_file->matrix_tam, state);
141
    iter++;
142
    state = checkpoint(iter, state, &async_comm);
143
  }
144
  
145
146
  if(config_file->resizes - 1 == group->grp) res=1;
  return res;
147
148
}

149
150
151
152
153
154
155
156
/*
 * Se realiza el redimensionado de procesos por parte de los padres.
 *
 * Se crean los nuevos procesos con la distribucion fisica elegida y
 * a continuacion se transmite la informacion a los mismos.
 *
 * Si hay datos asincronos a transmitir, primero se comienza a
 * transmitir estos y se termina la funcion. Se tiene que comprobar con
157
 * llamando a la función de nuevo que se han terminado de enviar
158
159
160
161
162
163
 *
 * Si hay ademas datos sincronos a enviar, no se envian aun.
 *
 * Si solo hay datos sincronos se envian tras la creacion de los procesos
 * y finalmente se desconectan los dos grupos de procesos.
 */
164
165
166
167
168
169
int checkpoint(int iter, int state, MPI_Request **comm_req) {
  
  if(state == MAL_COMM_UNINITIALIZED) {
    // Comprobar si se tiene que realizar un redimensionado
    if(config_file->iters[group->grp] > iter || config_file->resizes == group->grp + 1) {return MAL_COMM_UNINITIALIZED;}

170
    group->numS = config_file->procs[group->grp +1];
171
    int comm_type = COMM_SPAWN_PTHREAD; // TODO Pasar a CONFIG
172

173
174
175
    state = TC(group->numS, comm_type);

    if (state == COMM_FINISHED){
176
      state = start_redistribution(0, group->numS, comm_req);
177
178
179
    }

  } else if(state == COMM_IN_PROGRESS) { // Comprueba si el spawn ha terminado y comienza la redistribucion
180
    state = check_slurm_comm(group->myId, ROOT, group->numP, &(group->children));
181

182
183
    if (state == COMM_FINISHED) {  
        results->spawn_time[group->grp] = MPI_Wtime() - results->spawn_start;
184
      state = start_redistribution(iter, group->numS, comm_req);
185
    }
186

187
  } else if(state == MAL_ASYNC_PENDING) {
188
189
190
191
192
    if(config_file->aib == MAL_USE_THREAD) {
      state = thread_check(iter);
    } else {
      state = check_redistribution(iter, comm_req);
    }
193
  }
iker_martin's avatar
iker_martin committed
194

195
196
  return state;
}
iker_martin's avatar
iker_martin committed
197

198
199
/*
 * Se encarga de realizar la creacion de los procesos hijos.
200
 * Si se pide en segundo plano devuelve el estado actual.
201
 */
202
int TC(int numS, int comm_type){
203
204
  // Inicialización de la comunicación con SLURM
  int dist = config_file->phy_dist[group->grp +1];
205
  int comm_state;
iker_martin's avatar
iker_martin committed
206

207
208
209
210
      results->spawn_start = MPI_Wtime();
  comm_state = init_slurm_comm(group->argv, group->myId, numS, ROOT, dist, comm_type, MPI_COMM_WORLD, &(group->children));
  if(comm_type == COMM_SPAWN_SERIAL)
      results->spawn_time[group->grp] = MPI_Wtime() - results->spawn_start;
211
212
213
214
  else if(comm_type == COMM_SPAWN_PTHREAD) {
      results->spawn_thread_time[group->grp] = MPI_Wtime() - results->spawn_start;
      results->spawn_start = MPI_Wtime();
  }
215
  return comm_state;
216
}
iker_martin's avatar
iker_martin committed
217

218
219
220
221
222
223
224
225
226
227
228
229
230
231
/*
 * 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.
 */
232
int start_redistribution(int iter, int numS, MPI_Request **comm_req) {
iker_martin's avatar
iker_martin committed
233
234
235
236
237
  int rootBcast = MPI_PROC_NULL;
  if(group->myId == ROOT) rootBcast = MPI_ROOT;

  // Enviar a los hijos que grupo de procesos son
  MPI_Bcast(&(group->grp), 1, MPI_INT, rootBcast, group->children);
238
  MPI_Bcast(&run_id, 1, MPI_INT, rootBcast, group->children);
iker_martin's avatar
iker_martin committed
239
240
  send_config_file(config_file, rootBcast, group->children);

241
  if(config_file->adr > 0) {
242
    results->async_start = MPI_Wtime();
243
244
245
246
247
248
    if(config_file->aib == MAL_USE_THREAD) {
      return thread_creation();
    } else {
      send_async(group->async_array, config_file->adr, group->myId, group->numP, ROOT, group->children, group->numS, comm_req, config_file->aib);
      return MAL_ASYNC_PENDING;
    }
249
  } 
250
  return end_redistribution(iter);
251
252
253
254
255
256
257
258
259
260
}

/*
 * Crea una hebra para ejecutar una comunicación en segundo plano.
 */
int thread_creation() {
  if(pthread_create(&async_thread, NULL, thread_async_work, NULL)) {
    printf("Error al crear el hilo\n");
    MPI_Abort(MPI_COMM_WORLD, -1);
    return -1;
iker_martin's avatar
iker_martin committed
261
  }
262
263
  return MAL_ASYNC_PENDING;
}
264

265
266
267
268
269
270
/*
 * 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. 
 */
271
int thread_check(int iter) {
272
  int all_completed = 0;
iker_martin's avatar
iker_martin committed
273

274
275
276
277
278
279
280
281
282
283
  // Comprueba que todos los hilos han terminado la distribucion (Mismo valor en commAsync)
  MPI_Allreduce(&group->commAsync, &all_completed, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
  if(all_completed != MAL_COMM_COMPLETED) return MAL_ASYNC_PENDING; // Continue only if asynchronous send has ended 

  if(pthread_join(async_thread, NULL)) {
    printf("Error al esperar al hilo\n");
    MPI_Abort(MPI_COMM_WORLD, -1);
    return -2;
  } 
  return end_redistribution(iter);
284
285
286
287
288
289
290
291
292
293
294
295
296
297
}

/*
 * 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".
 */
void* thread_async_work(void* void_arg) {
  send_sync(group->async_array, config_file->adr, group->myId, group->numP, ROOT, group->children, group->numS);
  group->commAsync = MAL_COMM_COMPLETED;
  pthread_exit(NULL);
iker_martin's avatar
iker_martin committed
298
299
}

300
/*
301
 * @deprecated
302
303
304
305
306
307
308
 * 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.
309
310
 * Si se utiliza el modo "MAL_USE_NORMAL" o "MAL_USE_POINT", se considera 
 * terminada cuando los padres terminan de enviar.
311
312
313
 * Si se utiliza el modo "MAL_USE_IBARRIER", se considera terminada cuando
 * los hijos han terminado de recibir.
 */
314
int check_redistribution(int iter, MPI_Request **comm_req) {
315
  int completed, all_completed, test_err;
316
  MPI_Request *req_completed;
iker_martin's avatar
iker_martin committed
317

318
319
320
321
322
323
324
325
326
327
  if (config_file->aib == MAL_USE_POINT) {
    test_err = MPI_Testall(group->numS, *comm_req, &completed, MPI_STATUSES_IGNORE);
  } else {
    if(config_file->aib == MAL_USE_NORMAL) {
      req_completed = &(*comm_req)[0];
    } else if (config_file->aib == MAL_USE_IBARRIER) {
      req_completed = &(*comm_req)[1];
    }
    test_err = MPI_Test(req_completed, &completed, MPI_STATUS_IGNORE);
  }
328
 
329
  if (test_err != MPI_SUCCESS && test_err != MPI_ERR_PENDING) {
330
    printf("P%d aborting -- Test Async\n", group->myId);
331
332
333
334
    MPI_Abort(MPI_COMM_WORLD, test_err);
  }

  MPI_Allreduce(&completed, &all_completed, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD);
335
  if(!all_completed) return MAL_ASYNC_PENDING; // Continue only if asynchronous send has ended 
336
  
337
338
339

  if(config_file->aib == MAL_USE_IBARRIER) {
    MPI_Wait(&(*comm_req)[0], MPI_STATUS_IGNORE); // Indicar como completado el envio asincrono
340
    //Para la desconexión de ambos grupos de procesos es necesario indicar a MPI que esta comm
341
    //ha terminado, aunque solo se pueda llegar a este punto cuando ha terminado
342
  }
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  free(*comm_req);
  return end_redistribution(iter);
}


/*
 * 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(int iter) {
  int rootBcast = MPI_PROC_NULL;
  if(group->myId == ROOT) rootBcast = MPI_ROOT;

  if(iter > 0) { // Mandar a los hijos iteracion en la que comenzar
    MPI_Bcast(&iter, 1, MPI_INT, rootBcast, group->children);
  }
363
  if(config_file->sdr > 0) { // Realizar envio sincrono
364
      results->sync_start = MPI_Wtime();
365
    send_sync(group->sync_array, config_file->sdr, group->myId, group->numP, ROOT, group->children, group->numS);
366
367
  }

368
  send_results(results, rootBcast, config_file->resizes, group->children);
369
370
371
  // Desconectar intercomunicador con los hijos
  MPI_Comm_disconnect(&(group->children));
  return MAL_COMM_COMPLETED;
iker_martin's avatar
iker_martin committed
372
373
}

374
375
376
377
378
379
/*
 * 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.
 */
iker_martin's avatar
iker_martin committed
380
381
382
383
void Sons_init() {

  // Enviar a los hijos que grupo de procesos son
  MPI_Bcast(&(group->grp), 1, MPI_INT, ROOT, group->parents);
384
  MPI_Bcast(&run_id, 1, MPI_INT, ROOT, group->parents);
iker_martin's avatar
iker_martin committed
385
386
387
388
  group->grp++;

  config_file = recv_config_file(ROOT, group->parents);
  int numP_parents = config_file->procs[group->grp -1];
389
  init_results_data(&results, config_file->resizes - 1, config_file->iters[group->grp]);
iker_martin's avatar
iker_martin committed
390

391
392
393
394
  if(config_file->comm_tam) {
    group->compute_comm_array = malloc(config_file->comm_tam * sizeof(char));
  }
  if(config_file->adr) { // Recibir datos asincronos
395
396
397
398
399
400
    if(config_file->aib == MAL_USE_NORMAL || config_file->aib == MAL_USE_IBARRIER || config_file->aib == MAL_USE_POINT) {
      recv_async(&(group->async_array), config_file->adr, group->myId, group->numP, ROOT, group->parents, numP_parents, config_file->aib);
    } else if (config_file->aib == MAL_USE_THREAD) {
      recv_sync(&(group->async_array), config_file->adr, group->myId, group->numP, ROOT, group->parents, numP_parents);
    }

401
      results->async_time[group->grp] = MPI_Wtime();
402
403
    MPI_Bcast(&(group->iter_start), 1, MPI_INT, ROOT, group->parents);
  }
404
    MPI_Bcast(&(group->iter_start), 1, MPI_INT, ROOT, group->parents); //FIXME Quitar -- Que tenga en cuenta Pthread y async
405
  if(config_file->sdr) { // Recibir datos sincronos
iker_martin's avatar
iker_martin committed
406
    recv_sync(&(group->sync_array), config_file->sdr, group->myId, group->numP, ROOT, group->parents, numP_parents);
407
    results->sync_time[group->grp] = MPI_Wtime();
iker_martin's avatar
iker_martin committed
408
  }
409
410
411

  // Guardar los resultados de esta transmision
  recv_results(results, ROOT, config_file->resizes, group->parents);
412
  if(config_file->sdr) { // Si no hay datos sincronos, el tiempo es 0
413
414
415
416
    results->sync_time[group->grp]  = MPI_Wtime() - results->sync_start;
  } else {
    results->sync_time[group->grp]  = 0;
  }
417
  if(config_file->adr) { // Si no hay datos asincronos, el tiempo es 0
418
419
420
421
    results->async_time[group->grp]  = MPI_Wtime() - results->async_start;
  } else {
    results->async_time[group->grp]  = 0;
  }
iker_martin's avatar
iker_martin committed
422
423
424
425
426
427
428
429
430
431
432
433
434

  // Desconectar intercomunicador con los hijos
  MPI_Comm_disconnect(&(group->parents));
}


/////////////////////////////////////////
/////////////////////////////////////////
//COMPUTE FUNCTIONS
/////////////////////////////////////////
/////////////////////////////////////////


435
436
/*
 * Simula la ejecucción de una iteración de computo en la aplicación
437
 * que dura al menos un tiempo de "time" segundos.
438
 */
439
void iterate(double *matrix, int n, int async_comm) {
440
  double start_time, actual_time;
iker_martin's avatar
iker_martin committed
441
  double time = config_file->general_time * config_file->factors[group->grp];
442
  double Top = config_file->Top;
443
  int i, operations = 0;
444
  double aux = 0;
445
446

  start_time = actual_time = MPI_Wtime();
447
448
449
450
451

  operations = time / Top;
  for(i=0; i < operations; i++) {
    aux += computePiSerial(n);
  }
452
453
454
455
456

  if(config_file->comm_tam) {
    MPI_Bcast(group->compute_comm_array, config_file->comm_tam, MPI_CHAR, ROOT, MPI_COMM_WORLD);
  }

457
  actual_time = MPI_Wtime(); // Guardar tiempos
458
459
  // TODO Que diferencie entre ambas en el IO
  if(async_comm == MAL_ASYNC_PENDING || async_comm == COMM_IN_PROGRESS) { // Se esta realizando una redistribucion de datos asincrona
460
461
462
    operations=0;
  }

463
464
465
466

  if(results->iter_index == results->iters_size) { // Aumentar tamaño de ambos vectores de resultados
    realloc_results_iters(results, results->iters_size + 100);
  }
467
468
469
  results->iters_time[results->iter_index] = actual_time - start_time;
  results->iters_type[results->iter_index] = operations;
  results->iter_index = results->iter_index + 1;
470

471
}
472

473
474
//======================================================||
//======================================================||
475
//=============INIT/FREE/PRINT FUNCTIONS================||
476
477
478
//======================================================||
//======================================================||

479
480
481
482
/*
 * Muestra datos generales sobre los procesos, su grupo,
 * en que nodo residen y la version de MPI utilizada.
 */
483
484
485
486
487
488
489
490
491
492
493
494
void print_general_info(int myId, int grp, int numP) {
  int len;
  char *name = malloc(MPI_MAX_PROCESSOR_NAME * sizeof(char));
  char *version = malloc(MPI_MAX_LIBRARY_VERSION_STRING * sizeof(char));
  MPI_Get_processor_name(name, &len);
  MPI_Get_library_version(version, &len);
  printf("P%d Nuevo GRUPO %d de %d procs en nodo %s con %s\n", myId, grp, numP, name, version);

  free(name);
  free(version);
}

495
496
497
498
499
500
/*
 * Pide al proceso raiz imprimir los datos sobre las iteraciones realizadas por el grupo de procesos.
 *
 * Si es el ultimo grupo de procesos, muestra los datos obtenidos de tiempo de ejecucion, creacion de procesos
 * y las comunicaciones.
 */
501
int print_final_results() {
iker_martin's avatar
iker_martin committed
502
503
504
  int ptr_local, ptr_global, err;
  char *file_name;

505
  if(group->myId == ROOT) {
iker_martin's avatar
iker_martin committed
506
507
    file_name = NULL;
    file_name = malloc(40 * sizeof(char));
508
    if(file_name == NULL) return -1; // No ha sido posible alojar la memoria
509
    err = snprintf(file_name, 40, "R%d_G%dNP%dID%d.out", run_id, group->grp, group->numP, group->myId);
510
    if(err < 0) return -2; // No ha sido posible obtener el nombre de fichero
iker_martin's avatar
iker_martin committed
511
512
    create_out_file(file_name, &ptr_local, 1);
  
513
514
    print_config_group(config_file, group->grp);
    print_iter_results(results, config_file->iters[group->grp] -1);
iker_martin's avatar
iker_martin committed
515
    free(file_name);
516
517

    if(group->grp == config_file->resizes -1) {
iker_martin's avatar
iker_martin committed
518
519
      file_name = NULL;
      file_name = malloc(20 * sizeof(char));
520
      if(file_name == NULL) return -1; // No ha sido posible alojar la memoria
521
      err = snprintf(file_name, 20, "R%d_Global.out", run_id);
522
      if(err < 0) return -2; // No ha sido posible obtener el nombre de fichero
iker_martin's avatar
iker_martin committed
523
524

      create_out_file(file_name, &ptr_global, 1);
525
526
      print_config(config_file, group->grp);
      print_global_results(results, config_file->resizes);
iker_martin's avatar
iker_martin committed
527
528
      free(file_name);
      
529
530
    }
  }
531
  return 0;
532
533
534
535
536
}

/*
 * Inicializa la estructura group
 */
537
void init_group_struct(char *argv[], int argc, int myId, int numP) {
538
539
540
541
542
  group = malloc(1 * sizeof(group_data));
  group->myId        = myId;
  group->numP        = numP;
  group->grp         = 0;
  group->iter_start  = 0;
543
  group->commAsync   = MAL_COMM_UNINITIALIZED;
544
  group->argc        = argc;
545
546
  group->argv        = argv;
}
547

548
549
550
551
552
553
554
555
556
557
/*
 * Inicializa los datos para este grupo de procesos.
 *
 * En caso de ser el primer grupo de procesos, lee el fichero de configuracion
 * e inicializa los vectores de comunicacion.
 *
 * En caso de ser otro grupo de procesos entra a la funcion "Sons_init()" donde
 * se comunican con los padres para inicializar sus datos.
 */
void init_application() {
558
559
560
561
562
563
564
  if(group->argc < 2) {
    printf("Falta el fichero de configuracion. Uso:\n./programa config.ini id\nEl argumento numerico id es opcional\n");
    exit(0);
  }
  if(group->argc > 2) {
    run_id = atoi(group->argv[2]);
  }
565

566
567
  config_file = read_ini_file(group->argv[1]);
  init_results_data(&results, config_file->resizes, config_file->iters[group->grp]);
568
569
570
571
  if(config_file->comm_tam) {
    group->compute_comm_array = malloc(config_file->comm_tam * sizeof(char));
  }
  if(config_file->sdr) {
572
573
    malloc_comm_array(&(group->sync_array), config_file->sdr , group->myId, group->numP);
  }
574
  if(config_file->adr) {
575
576
    malloc_comm_array(&(group->async_array), config_file->adr , group->myId, group->numP);
  }
577
578
579
   
  obtain_op_times();
}
580

581
582
583
584
/*
 * Obtiene cuanto tiempo es necesario para realizar una operacion de PI
 */
void obtain_op_times() {
585
  double result, start_time = MPI_Wtime();
586
  int i, qty = 20000;
587
  result = 0;
588
  for(i=0; i<qty; i++) {
589
    result += computePiSerial(config_file->matrix_tam);
590
  }
591
592
  //printf("Creado Top con valor %lf\n", result);
  //fflush(stdout);
593

594
  config_file->Top = (MPI_Wtime() - start_time) / qty; //Tiempo de una operacion
595
  MPI_Bcast(&(config_file->Top), 1, MPI_DOUBLE, ROOT, MPI_COMM_WORLD); 
596
597
598
599
600
601
}

/*
 * Libera toda la memoria asociada con la aplicacion
 */
void free_application_data() {
602
603
604
605
  if(config_file->comm_tam) {
    free(group->compute_comm_array);
  }
  if(config_file->sdr) {
606
607
    free(group->sync_array);
  }
608
  if(config_file->adr) {
609
610
    free(group->async_array);
  }
611
  
612
613
614
615
  free(group);
  free_config(config_file);
  free_results_data(&results);
}
iker_martin's avatar
iker_martin committed
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640


/* 
 * Función para crear un fichero con el nombre pasado como argumento.
 * Si el nombre ya existe, se escribe la informacion a continuacion.
 *
 * El proceso que llama a la función pasa a tener como salida estandar
 * dicho fichero si el valor "newstdout" es verdadero.
 *
 */
int create_out_file(char *nombre, int *ptr, int newstdout) {
  int err;

  *ptr = open(nombre, O_WRONLY | O_CREAT | O_APPEND, 0644);
  if(*ptr < 0) return -1; // No ha sido posible crear el fichero

  if(newstdout) {
    err = close(1);
    if(err < 0) return -2; // No es posible modificar la salida estandar
    err = dup(*ptr);
    if(err < 0) return -3; // No es posible modificar la salida estandar
  }

  return 0;
}