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

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

//======================================================||
//======================================================||
//================MPI RESULTS FUNCTIONS=================||
//======================================================||
//======================================================||
13

14
//TODO Generalizar ambas funciones en una sola
15
16
17
18
19
20
21
22
23
/*
 * Envia una estructura de resultados al grupo de procesos al que se 
 * enlaza este grupo a traves del intercomunicador pasado como argumento.
 *
 * Esta funcion tiene que ser llamada por todos los procesos del mismo grupo
 * e indicar cual es el proceso raiz que se encargara de enviar los
 * resultados al otro grupo.
 */
void send_results(results_data *results, int root, int resizes, MPI_Comm intercomm) {
24
25
26
27
  MPI_Datatype results_type;

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

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

35
36
37
38
39
40
41
42
43
44
/*
 * Recibe una estructura de resultados desde otro grupo de procesos
 * y la devuelve. La memoria de la estructura se tiene que reservar con antelacion
 * con la función "init_results_data".
 *
 * Esta funcion tiene que ser llamada por todos los procesos del mismo grupo
 * e indicar cual es el proceso raiz del otro grupo que se encarga de enviar
 * los resultados a este grupo.
 */
void recv_results(results_data *results, int root, int resizes, MPI_Comm intercomm) {
45
46
47
48
  MPI_Datatype results_type;

  // Obtener un tipo derivado para enviar todos los
  // datos escalares con una sola comunicacion
49
  def_results_type(results, resizes, &results_type);
50
51
52
53
54
55
  MPI_Bcast(results, 1, results_type, root, intercomm);

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

56
57
58
59
/*
 * Define un tipo derivado de MPI para mandar los tiempos
 * con una sola comunicacion.
 *
60
 * En concreto son tres escalares y dos vectores de tamaño "resizes"
61
62
 */
void def_results_type(results_data *results, int resizes, MPI_Datatype *results_type) {
63
64
  int i, counts = 6;
  int blocklengths[] = {1, 1, 1, 1, 1, 1};
65
66
67
68
  MPI_Aint displs[counts], dir;
  MPI_Datatype types[counts];

  // Rellenar vector types
69
  types[0] = types[1] = types[2] = types[3] = types[4] = types[5] = MPI_DOUBLE;
70
  blocklengths[3] = blocklengths[4] = resizes;
71
72
73
74
75
76

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

  MPI_Get_address(&(results->sync_start), &displs[0]);
  MPI_Get_address(&(results->async_start), &displs[1]);
77
  MPI_Get_address(&(results->exec_start), &displs[2]);
78
79
80
  MPI_Get_address(&(results->wasted_time), &displs[3]);
  MPI_Get_address(&(results->spawn_real_time[0]), &displs[4]);
  MPI_Get_address(&(results->spawn_time[0]), &displs[5]); //TODO Revisar si se puede simplificar //FIXME Si hay mas de un spawn error?
81
82
83
84
85
86

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

  MPI_Type_create_struct(counts, blocklengths, displs, types, results_type);
  MPI_Type_commit(results_type);
}
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//======================================================||
//======================================================||
//================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
    results->sync_time[grp]  = results->sync_end - results->sync_start;
  } else {
    results->sync_time[grp]  = 0;
  }
  if(adr) { // Si no hay datos asincronos, el tiempo es 0
    results->async_time[grp]  = results->async_end - results->async_start;
  } else {
    results->async_time[grp]  = 0;
  }
}

111
112
113
114
115
116
117
118
119
120
121
122
123
/*
 * 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;
}

124

125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * 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.
 */
void compute_results_iter(results_data *results, int myId, int root, MPI_Comm comm) {
  if(myId == root)
    MPI_Reduce(MPI_IN_PLACE, results->iters_time, results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
  else
    MPI_Reduce(results->iters_time, NULL, results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
}

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

/*
 * 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.
 */
void compute_results_stages(results_data *results, int myId, int root, int stages, MPI_Comm comm) {
  int i;
  if(myId == root) {
    for(i=0; i<stages; i++) {
      MPI_Reduce(MPI_IN_PLACE, results->stage_times[i], results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
    }
  }
  else {
    for(i=0; i<stages; i++) {
      MPI_Reduce(results->stage_times[i], NULL, results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
    }
  }
}

161
162
163
164
165
//======================================================||
//======================================================||
//===============PRINT RESULTS FUNCTIONS================||
//======================================================||
//======================================================||
166
167
168
169

/*
 * Imprime por pantalla los resultados locales.
 * Estos son los relacionados con las iteraciones, que son el tiempo
170
 * por iteracion, el tipo (Normal o durante communicacion asincrona).
171
 */
172
void print_iter_results(results_data results) {
173
  int i;
174

175
  printf("T_iter: ");
176
177
  for(i=0; i< results.iter_index; i++) {
    printf("%lf ", results.iters_time[i]);
178
179
  }

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  printf("\nAsync_Iters: %d\n", results.iters_async);
}

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

  for(i=0; i<n_stages; i++) {
    printf("T_stage %d: ", i);
    for(j=0; j< results.iter_index; j++) {
      printf("%lf ", results.stage_times[i][j]);
    }
    printf("\n");
  }
196
197
}

198
199
200
201
202
/*
 * 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.
 */
203
void print_global_results(results_data results, int resizes) {
204
205
  int i;

206
  printf("T_spawn: ");  // FIXME REFACTOR Cambiar nombre a T_resize_real
207
  for(i=0; i< resizes - 1; i++) {
208
    printf("%lf ", results.spawn_time[i]);
209
210
  }

211
  printf("\nT_spawn_real: "); // FIXME REFACTOR Cambiar nombre a T_resize
212
  for(i=0; i< resizes - 1; i++) {
213
    printf("%lf ", results.spawn_real_time[i]);
214
215
  }

216
  printf("\nT_SR: ");
217
  for(i=1; i < resizes; i++) {
218
    printf("%lf ", results.sync_time[i]);
219
220
  }

221
  printf("\nT_AR: ");
222
  for(i=1; i < resizes; i++) {
223
    printf("%lf ", results.async_time[i]);
224
225
  }

226
  printf("\nT_total: %lf\n", results.exec_time);
227
228
}

229
230
231
232
233
234
//======================================================||
//======================================================||
//=============INIT/FREE RESULTS FUNCTIONS==============||
//======================================================||
//======================================================||

235
236
237
238
239
240
/*
 * 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.
 */
241
242
void init_results_data(results_data *results, int resizes, int stages, int iters_size) {
  int i;
243
244

  results->spawn_time = calloc(resizes, sizeof(double));
245
  results->spawn_real_time = calloc(resizes, sizeof(double));
246
247
  results->sync_time = calloc(resizes, sizeof(double));
  results->async_time = calloc(resizes, sizeof(double));
248
  results->wasted_time = 0;
249
250
251

  results->iters_size = iters_size + 100;
  results->iters_time = calloc(iters_size + 100, sizeof(double)); //FIXME Numero magico
252
253
254
255
256
  results->stage_times = malloc(stages * sizeof(double*)); //FIXME Numero magico
  for(i=0; i<stages; i++) {
    results->stage_times[i] = calloc(iters_size + 100, sizeof(double)); //FIXME Numero magico
  }

257
  results->iters_async = 0;
258
  results->iter_index = 0;
259

260
261
}

262
263
void realloc_results_iters(results_data *results, int stages, int needed) {
  int i;
264
265
266
  double *time_aux;
  time_aux = (double *) realloc(results->iters_time, needed * sizeof(double));

267
268
269
270
  for(i=0; i<stages; i++) { //TODO Comprobar que no da error el realloc
    results->stage_times[i] = (double *) realloc(results->stage_times[i], needed * sizeof(double)); 
  }

271
  if(time_aux == NULL) {
272
    fprintf(stderr, "Fatal error - No se ha podido realojar la memoria de resultados\n");
273
274
275
276
277
278
    MPI_Abort(MPI_COMM_WORLD, 1);
  }

  results->iters_time = time_aux;
}

279
280
281
/*
 * Libera toda la memoria asociada con una estructura de resultados.
 */
282
283
void free_results_data(results_data *results, int stages) {
    int i;
284
    if(results != NULL) {
285
      free(results->spawn_time);
286
      free(results->spawn_real_time);
287
288
289
290
      free(results->sync_time);
      free(results->async_time);

      free(results->iters_time);
291
292
      for(i=0; i<stages; i++) {
        free(results->stage_times[i]);
293
      }
294
295
      free(results->stage_times);
    }
296
}