results.c 9.98 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
//TODO Generalizar ambas funciones en una sola
17
18
19
20
21
22
23
24
/*
 * 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.
 */
25
void send_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
41
42
43
44
45
/*
 * 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.
 */
46
void recv_results(results_data *results, int root, size_t resizes, MPI_Comm intercomm) {
47
48
49
50
  MPI_Datatype results_type;

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

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

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

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

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

  MPI_Get_address(&(results->sync_start), &displs[0]);
  MPI_Get_address(&(results->async_start), &displs[1]);
79
  MPI_Get_address(&(results->exec_start), &displs[2]);
80
81
82
  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?
83
84
85
86
87
88

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

  MPI_Type_create_struct(counts, blocklengths, displs, types, results_type);
  MPI_Type_commit(results_type);
}
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//======================================================||
//======================================================||
//================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;
  }
}

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

126

127
128
129
130
131
132
133
134
135
/*
 * 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)
136
    MPI_Reduce(MPI_IN_PLACE, results->iters_time, (int) results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
137
  else
138
    MPI_Reduce(results->iters_time, NULL, (int) results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
139
140
}

141
142
143
144
145
146
147
148
149
150
151
152

/*
 * 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++) {
153
      MPI_Reduce(MPI_IN_PLACE, results->stage_times[i], (int) results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
154
155
156
157
    }
  }
  else {
    for(i=0; i<stages; i++) {
158
      MPI_Reduce(results->stage_times[i], NULL, (int) results->iter_index, MPI_DOUBLE, MPI_MAX, root, comm);
159
160
161
162
    }
  }
}

163
164
165
166
167
//======================================================||
//======================================================||
//===============PRINT RESULTS FUNCTIONS================||
//======================================================||
//======================================================||
168
169
170
171

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

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

182
  printf("\nAsync_Iters: %ld\n", results.iters_async);
183
184
185
186
187
}

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

191
192
193
  for(i=0; i < n_stages; i++) {
    printf("T_stage %ld: ", i);
    for(j=0; j < results.iter_index; j++) {
194
195
196
197
      printf("%lf ", results.stage_times[i][j]);
    }
    printf("\n");
  }
198
199
}

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

208
209
  printf("T_spawn: ");
  for(i=0; i < resizes - 1; i++) {
210
    printf("%lf ", results.spawn_time[i]);
211
212
  }

213
  printf("\nT_spawn_real: ");
214
  for(i=0; i< resizes - 1; i++) {
215
    printf("%lf ", results.spawn_real_time[i]);
216
217
  }

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

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

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

231
232
233
234
235
236
//======================================================||
//======================================================||
//=============INIT/FREE RESULTS FUNCTIONS==============||
//======================================================||
//======================================================||

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

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

252
253
254
  results->iters_size = iters_size + RESULTS_EXTRA_SIZE;
  results->iters_time = calloc(results->iters_size, sizeof(double));
  results->stage_times = malloc(stages * sizeof(double*));
255
  for(i=0; i<stages; i++) {
256
    results->stage_times[i] = calloc(results->iters_size, sizeof(double));
257
258
  }

259
  results->iters_async = 0;
260
  results->iter_index = 0;
261

262
263
}

264
265
void realloc_results_iters(results_data *results, size_t stages, size_t needed) {
  int error = 0;
266
  double *time_aux;
267
  size_t i;
268
269
  time_aux = (double *) realloc(results->iters_time, needed * sizeof(double));

270
  for(i=0; i<stages; i++) { //TODO Comprobar que no da error el realloc
271
272
    results->stage_times[i] = (double *) realloc(results->stage_times[i], needed * sizeof(double));
    if(results->stage_times[i] == NULL) error = 1;
273
274
  }

275
276
  if(time_aux == NULL) error = 1;
  if(error) {
277
    fprintf(stderr, "Fatal error - No se ha podido realojar la memoria de resultados\n");
278
279
280
281
282
283
    MPI_Abort(MPI_COMM_WORLD, 1);
  }

  results->iters_time = time_aux;
}

284
285
286
/*
 * Libera toda la memoria asociada con una estructura de resultados.
 */
287
288
289
290
291
292
293
294
295
296
297
void free_results_data(results_data *results, size_t stages) {
  size_t i;
  if(results != NULL) {
    free(results->spawn_time);
    free(results->spawn_real_time);
    free(results->sync_time);
    free(results->async_time);

    free(results->iters_time);
    for(i=0; i<stages; i++) {
      free(results->stage_times[i]);
298
    }
299
300
    free(results->stage_times);
  }
301
}