results.c 11.9 KB
Newer Older
1
2
3
4
5
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include "results.h"

6
7
#define RESULTS_EXTRA_SIZE 100

8
void def_results_type(results_data *results, int resizes, MPI_Datatype *results_type);
9
10
11
12
13
14

//======================================================||
//======================================================||
//================MPI RESULTS FUNCTIONS=================||
//======================================================||
//======================================================||
15
16

/*
17
18
 * Comunica una estructura de resultados a todos los procesos del comunicador
 * a traves de un tipo derivado.
19
 *
20
21
22
23
 * Si se llama con un intercommunicador, el grupo de procesos que envia los datos
 * tiene que indicar en el proceso raiz el valor "MPI_ROOT" para "root" y el resto
 * de ese grupo el valor "MPI_PROC_NULL". Los procesos del otro grupo tienen que
 * indicar el Id del proceso raiz que ha puesto "MPI_ROOT".
24
 */
25
void comm_results(results_data *results, int root, size_t resizes, MPI_Comm intercomm) {
26
27
28
29
  MPI_Datatype results_type;

  // Obtener un tipo derivado para enviar todos los
  // datos escalares con una sola comunicacion
30
  def_results_type(results, resizes, &results_type);
31
32
33
34
35
36
  MPI_Bcast(results, 1, results_type, root, intercomm);

  //Liberar tipos derivados
  MPI_Type_free(&results_type);
}

37
38
39
40
/*
 * Define un tipo derivado de MPI para mandar los tiempos
 * con una sola comunicacion.
 *
41
 * En concreto son tres escalares y dos vectores de tamaño "resizes"
42
43
 */
void def_results_type(results_data *results, int resizes, MPI_Datatype *results_type) {
44
45
  int i, counts = 7;
  int blocklengths[] = {1, 1, 1, 1, 1, 1, 1};
46
47
48
49
  MPI_Aint displs[counts], dir;
  MPI_Datatype types[counts];

  // Rellenar vector types
50
51
  types[0] = types[1] = types[2] = types[3] = types[4] = types[5] = types[6] = MPI_DOUBLE;
  blocklengths[2] = blocklengths[3] = blocklengths[4] = blocklengths[5] = blocklengths[6] = resizes;
52
53
54
55

  // Rellenar vector displs
  MPI_Get_address(results, &dir);

56
57
58
59
60
61
  MPI_Get_address(&(results->exec_start), &displs[0]);
  MPI_Get_address(&(results->wasted_time), &displs[1]);
  MPI_Get_address(results->sync_time, &displs[2]);
  MPI_Get_address(results->async_time, &displs[3]);
  MPI_Get_address(results->spawn_real_time, &displs[4]);
  MPI_Get_address(results->spawn_time, &displs[5]);
62
  MPI_Get_address(results->malleability_time, &displs[6]);
63
64
65
66
67
68

  for(i=0;i<counts;i++) displs[i] -= dir;

  MPI_Type_create_struct(counts, blocklengths, displs, types, results_type);
  MPI_Type_commit(results_type);
}
69
70
71
72
73
74
75
76
77
78
79
80
81
//======================================================||
//======================================================||
//================SET RESULTS FUNCTIONS=================||
//======================================================||
//======================================================||

/*
 * Guarda los resultados respecto a la redistribución de datos
 * tras una reconfiguración. A llamar por los hijos tras
 * terminar la redistribución y obtener la configuración.
 */
void set_results_post_reconfig(results_data *results, int grp, int sdr, int adr) {
  if(sdr) { // Si no hay datos sincronos, el tiempo es 0
82
    results->sync_time[grp-1]  = results->sync_end - results->sync_time[grp-1];
83
  } else {
84
    results->sync_time[grp-1]  = 0;
85
86
  }
  if(adr) { // Si no hay datos asincronos, el tiempo es 0
87
    results->async_time[grp-1]  = results->async_end - results->async_time[grp-1];
88
  } else {
89
    results->async_time[grp-1]  = 0;
90
  }
91
  results->malleability_time[grp-1]  = results->malleability_end - results->malleability_time[grp-1];
92
93
}

94
95
96
97
98
99
100
101
102
103
104
/*
 * Pone el indice del siguiente elemento a escribir a 0 para los vectores
 * que tengan que ver con las iteraciones.
 * Por tanto, todos los anteriores valores de esos vectores pasan a ser invalidos
 * si se intentan acceder desde un código externo.
 *
 * Solo es necesario llamar a esta funcion cuando se ha realizado una
 * expansion con el metodo MERGE
 */
void reset_results_index(results_data *results) {
  results->iter_index = 0;
105
  results->iters_async = 0;
106
107
}

108
109
110
111
112
113
114
//=============================================================== FIXME BORRAR?
int compare(const void *_a, const void *_b) { 
        double *a, *b;
        a = (double *) _a;
        b = (double *) _b;
        return (*a - *b);
}
115
116
117
118
119
120
121
/*
 * Obtiene para cada iteracion, el tiempo maximo entre todos los procesos
 * que han participado.
 *
 * Es necesario obtener el maximo, pues es el que representa el tiempo real
 * que se ha utilizado.
 */
122
123
void compute_results_iter(results_data *results, int myId, int numP, int root, MPI_Comm comm) { //TODO Probar a quedarse la MEDIA en vez de MAX?
  if(myId == root) {
124
125
    MPI_Reduce(MPI_IN_PLACE, results->iters_time, results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
    /*
126
127
    for(size_t i=0; i<results->iter_index; i++) {
      results->iters_time[i] = results->iters_time[i] / numP;
128
    }*/
129
  } else {
130
    MPI_Reduce(results->iters_time, NULL, results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
131
  }
132
  /*
133
134
135
136
137
138
139
140
141
142
143
144
  double *aux_all_iters, *aux_id_iters, median;
  if(myId == root) {
    aux_all_iters = malloc(numP *results->iter_index * sizeof(double));
  }
  MPI_Gather(results->iters_time, results->iter_index, MPI_DOUBLE, aux_all_iters, results->iter_index, MPI_DOUBLE, root, comm);
  if(myId == root) {
    aux_id_iters = malloc(numP * sizeof(double));
    for(size_t i=0; i<results->iter_index; i++) {
      for(int j=0; j<numP; j++) {
        aux_id_iters[j] = aux_all_iters[i+(results->iter_index*j)];
      }
      // Get Median
145
      qsort(aux_id_iters, numP, sizeof(double), &compare);
146
147
148
149
150
151
      median = aux_id_iters[numP/2];
      if (numP % 2 == 0) median = (aux_id_iters[numP/2 - 1] + aux_id_iters[numP/2]) / 2;
      results->iters_time[i] = median;
    }
    free(aux_all_iters);
    free(aux_id_iters);
152
  }
153
  */
154
155
}

156
157
158
159
160
161
162
163

/*
 * Obtiene para cada stage de cada iteracion, el tiempo maximo entre todos los procesos
 * que han participado.
 *
 * Es necesario obtener el maximo, pues es el que representa el tiempo real
 * que se ha utilizado.
 */
164
void compute_results_stages(results_data *results, int myId, int numP, int root, int stages, MPI_Comm comm) { //TODO Probar a quedarse la MEDIA en vez de MAX?
165
166
167
  int i;
  if(myId == root) {
    for(i=0; i<stages; i++) {
168
169
      MPI_Reduce(MPI_IN_PLACE, results->stage_times[i], results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
     /* for(size_t j=0; j<results->iter_index; j++) {
170
        results->stage_times[i][j] = results->stage_times[i][j] / numP;
171
      }*/
172
173
174
175
    }
  }
  else {
    for(i=0; i<stages; i++) {
176
      MPI_Reduce(results->stage_times[i], NULL, results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
177
178
    }
  }
179
  MPI_Barrier(comm); //FIXME Esto debería de borrarse
180
181
}

182
183
184
185
186
//======================================================||
//======================================================||
//===============PRINT RESULTS FUNCTIONS================||
//======================================================||
//======================================================||
187
188
189
190

/*
 * Imprime por pantalla los resultados locales.
 * Estos son los relacionados con las iteraciones, que son el tiempo
191
 * por iteracion, el tipo (Normal o durante communicacion asincrona).
192
 */
193
void print_iter_results(results_data results) {
194
  size_t i;
195

196
  printf("Async_Iters: %ld\n", results.iters_async);
197
  printf("T_iter: ");
198
199
  for(i=0; i< results.iter_index; i++) {
    printf("%lf ", results.iters_time[i]);
200
  }
201
  printf("\n");
202
203
204
205
206
}

/*
 * Imprime por pantalla los resultados locales de un stage.
 */
207
208
void print_stage_results(results_data results, size_t n_stages) {
  size_t i, j;
209

210
211
212
  for(i=0; i < n_stages; i++) {
    printf("T_stage %ld: ", i);
    for(j=0; j < results.iter_index; j++) {
213
214
215
216
      printf("%lf ", results.stage_times[i][j]);
    }
    printf("\n");
  }
217
218
}

219
220
221
222
223
/*
 * Imprime por pantalla los resultados globales.
 * Estos son el tiempo de creacion de procesos, los de comunicacion
 * asincrona y sincrona y el tiempo total de ejecucion.
 */
224
225
void print_global_results(results_data results, size_t resizes) {
  size_t i;
226

227
  printf("T_spawn: ");
228
  for(i=0; i < resizes; i++) {
229
    printf("%lf ", results.spawn_time[i]);
230
231
  }

232
  printf("\nT_spawn_real: ");
233
  for(i=0; i< resizes; i++) {
234
    printf("%lf ", results.spawn_real_time[i]);
235
236
  }

237
  printf("\nT_SR: ");
238
  for(i=0; i < resizes; i++) {
239
    printf("%lf ", results.sync_time[i]);
240
241
  }

242
  printf("\nT_AR: ");
243
  for(i=0; i < resizes; i++) {
244
    printf("%lf ", results.async_time[i]);
245
246
  }

247
248
249
250
251
  printf("\nT_Malleability: ");
  for(i=0; i < resizes; i++) {
    printf("%lf ", results.malleability_time[i]);
  }

252
  printf("\nT_total: %lf\n", results.exec_time);
253
254
}

255
256
257
258
259
260
//======================================================||
//======================================================||
//=============INIT/FREE RESULTS FUNCTIONS==============||
//======================================================||
//======================================================||

261
262
263
264
265
266
/*
 * Inicializa los datos relacionados con una estructura de resultados.
 *
 * Los argumentos "resizes" y "iters_size" se necesitan para obtener el tamaño
 * de los vectores de resultados.
 */
267
268
void init_results_data(results_data *results, size_t resizes, size_t stages, size_t iters_size) {
  size_t i;
269
270

  results->spawn_time = calloc(resizes, sizeof(double));
271
  results->spawn_real_time = calloc(resizes, sizeof(double));
272
273
  results->sync_time = calloc(resizes, sizeof(double));
  results->async_time = calloc(resizes, sizeof(double));
274
  results->malleability_time = calloc(resizes, sizeof(double));
275
  results->wasted_time = 0;
276

277
278
279
  results->iters_size = iters_size + RESULTS_EXTRA_SIZE;
  results->iters_time = calloc(results->iters_size, sizeof(double));
  results->stage_times = malloc(stages * sizeof(double*));
280
  for(i=0; i<stages; i++) {
281
    results->stage_times[i] = calloc(results->iters_size, sizeof(double));
282
283
  }

284
  results->iters_async = 0;
285
  results->iter_index = 0;
286

287
288
}

289
290
void realloc_results_iters(results_data *results, size_t stages, size_t needed) {
  int error = 0;
291
  double *time_aux;
292
  size_t i;
293
294
295

  if(results->iters_size >= needed) return;

296
  time_aux = (double *) realloc(results->iters_time, needed * sizeof(double));
297
  if(time_aux == NULL) error = 1;
298

299
  for(i=0; i<stages; i++) { //TODO Comprobar que no da error el realloc
300
301
    results->stage_times[i] = (double *) realloc(results->stage_times[i], needed * sizeof(double));
    if(results->stage_times[i] == NULL) error = 1;
302
303
  }

304
  if(error) {
305
    fprintf(stderr, "Fatal error - No se ha podido realojar la memoria de resultados\n");
306
307
308
309
    MPI_Abort(MPI_COMM_WORLD, 1);
  }

  results->iters_time = time_aux;
310
  results->iters_size = needed;
311
312
}

313
314
315
/*
 * Libera toda la memoria asociada con una estructura de resultados.
 */
316
317
318
void free_results_data(results_data *results, size_t stages) {
  size_t i;
  if(results != NULL) {
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
    if(results->spawn_time != NULL) {
      free(results->spawn_time);
      results->spawn_time = NULL;
    }
    if(results->spawn_real_time != NULL) {
      free(results->spawn_real_time);
      results->spawn_real_time = NULL;
    }
    if(results->sync_time != NULL) {
      free(results->sync_time);
      results->sync_time = NULL;
    }
    if(results->async_time != NULL) {
      free(results->async_time);
      results->async_time = NULL;
    }
335
336
337
338
    if(results->malleability_time != NULL) {
      free(results->malleability_time);
      results->malleability_time = NULL;
    }
339

340
341
342
343
    if(results->iters_time != NULL) {
      free(results->iters_time);
      results->iters_time = NULL;
    }
344
    for(i=0; i<stages; i++) {
345
346
347
348
349
350
351
352
      if(results->stage_times[i] != NULL) {
        free(results->stage_times[i]);
        results->stage_times[i] = NULL;
      }
    }
    if(results->stage_times != NULL) {
      free(results->stage_times);
      results->stage_times = NULL;
353
    }
354
  }
355
}