configuration.c 16.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>
#include "../IOcodes/read_ini.h"
#include "configuration.h"
#include "../malleability/distribution_methods/block_distribution.h"

void malloc_config_resizes(configuration *user_config);
10
void malloc_config_stages(configuration *user_config);
11

12
13
void free_config_stage(iter_stage_t *stage, int *freed_ids, size_t *found_ids);

14
15
void def_struct_config_file(configuration *config_file);
void def_struct_groups(configuration *config_file);
16
void def_struct_groups_strategies(configuration *config_file);
17
void def_struct_iter_stage(configuration *config_file);
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

/*
 * Inicializa una estructura de configuracion
 *
 * Si el parametro "file_name" no es nulo,
 * se obtiene la configuracion a partir de 
 * un fichero .ini
 *
 * En caso de que sea nulo, es el usuario
 * el que tiene que elegir los valores a
 * utilizar.
 */
void init_config(char *file_name, configuration **user_config) {
  if(file_name != NULL) {
    ext_functions_t mallocs;
    mallocs.resizes_f = malloc_config_resizes;
34
    mallocs.stages_f = malloc_config_stages;
35
36
37
38
39
    *user_config = read_ini_file(file_name, mallocs);
  } else {
    configuration *config = NULL;

    config = malloc(sizeof(configuration));
40
41
    config->n_resizes=0;
    config->n_groups=1;
42
43
44
    malloc_config_resizes(config);
    config->n_stages=1;
    malloc_config_stages(config);
45
46
47
48
49
50
51
    if(config == NULL) {
        perror("Error when reserving configuration structure\n");
	MPI_Abort(MPI_COMM_WORLD, -3);
	return;
    }
    *user_config=config;
  }
52
  def_struct_config_file(*user_config);
53
  def_struct_groups_strategies(*user_config);
54
55
56
57
58
59
60
61
62
63
}

/*
 * Reserva de memoria para los vectores de la estructura de configuracion
 *
 * Si se llama desde fuera de este fichero, la memoria de la estructura
 * tiene que reservarse con la siguiente linea:
 * "configuration *config = malloc(sizeof(configuration));"
 *
 * Sin embargo se puede obtener a traves de las funciones
64
 *  - init_config
65
66
67
 *  - recv_config_file
 */
void malloc_config_resizes(configuration *user_config) {
68
  size_t i;
69
  if(user_config != NULL) {
70
71
    user_config->groups = malloc(sizeof(group_config_t) * user_config->n_groups);
    for(i=0; i<user_config->n_groups; i++) {
72
73
74
      user_config->groups[i].iters = 0;
      user_config->groups[i].procs = 1;
      user_config->groups[i].sm = 0;
75
76
      user_config->groups[i].ss = NULL;
      user_config->groups[i].ss_len = 0;
77
      user_config->groups[i].phy_dist = 0;
78
      user_config->groups[i].rm = 0;
79
80
      user_config->groups[i].rs = NULL;
      user_config->groups[i].rs_len = 0;
81
82
      user_config->groups[i].factor = 1;
    }
83
    def_struct_groups(user_config);
84
85
86
87
88
89
90
91
92
  }
}

/*
 * Inicializa la memoria para las fases de iteraciones.
 * No se reserva memoria, pero si se pone a NULL
 * para poder liberar correctamente cada fase.
 *
 * Se puede obtener a traves de las funciones
93
 *  - init_config
94
95
 *  - recv_config_file
 */
96
void malloc_config_stages(configuration *user_config) {
97
  size_t i;
98
  if(user_config != NULL) {
99
    user_config->stages = malloc(sizeof(iter_stage_t) * user_config->n_stages);
100
101
102
103
    for(i=0; i<user_config->n_stages; i++) {
      user_config->stages[i].array = NULL;
      user_config->stages[i].full_array = NULL;
      user_config->stages[i].double_array = NULL;
104
      user_config->stages[i].reqs = NULL;
105
      user_config->stages[i].counts.counts = NULL;
106
107
      user_config->stages[i].bytes = 0;
      user_config->stages[i].my_bytes = 0;
108
      user_config->stages[i].real_bytes = 0;
109
110
      user_config->stages[i].operations = 0;
      user_config->stages[i].pt = 0;
111
      user_config->stages[i].id = -1;
112
113
      user_config->stages[i].t_op = 0;
      user_config->stages[i].t_stage = 0;
114
      user_config->stages[i].t_capped = 0;
115
    }
116
    def_struct_iter_stage(user_config);
117
  }
118
119
120
121
122
123
124
}


/*
 * Libera toda la memoria de una estructura de configuracion
 */
void free_config(configuration *user_config) {
125
126
127
    size_t i, found_ids;
    int *freed_ids;
    found_ids = 0;
128
    if(user_config != NULL) {
129
      freed_ids = (int *) malloc(user_config->n_stages * sizeof(int));
130
      for(i=0; i < user_config->n_stages; i++) {
131
        free_config_stage(&(user_config->stages[i]), freed_ids, &found_ids);
132
      }
133
134
135
136
137

      for(i=0; i < user_config->n_groups; i++) {
        free(user_config->groups[i].ss);
        free(user_config->groups[i].rs);
      }
138
      //Liberar tipos derivados
139
140
141
142
143
144
      MPI_Type_free(&(user_config->config_type));
      user_config->config_type = MPI_DATATYPE_NULL;

      MPI_Type_free(&(user_config->group_type));
      user_config->group_type = MPI_DATATYPE_NULL;

145
146
147
      MPI_Type_free(&(user_config->group_strats_type));
      user_config->group_strats_type = MPI_DATATYPE_NULL;

148
149
      MPI_Type_free(&(user_config->iter_stage_type));
      user_config->iter_stage_type = MPI_DATATYPE_NULL;
150
      
151
      free(user_config->groups);
152
      free(user_config->stages);
153
      free(user_config);
154
155
156
157
158
159
160
161
162
      free(freed_ids);
    }
}

/*
 * Libera toda la memoria de una stage
 */
void free_config_stage(iter_stage_t *stage, int *freed_ids, size_t *found_ids) {
  size_t i;
163
  int mpi_index, free_reqs;
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

  free_reqs = 1;
  if(stage->id > -1) {
    for(i=0; i<*found_ids; i++) {
      if(stage->id == freed_ids[i]) {
  	free_reqs = 0;
        break;
      }
    }
    if(free_reqs) {
      freed_ids[*found_ids] = stage->id;
      *found_ids=*found_ids + 1;
    }
  }
	
  if(stage->array != NULL) {
    free(stage->array);
    stage->array = NULL;
  }
  if(stage->full_array != NULL) {
    free(stage->full_array);
    stage->full_array = NULL;
  }
  if(stage->double_array != NULL) {
    free(stage->double_array);
    stage->double_array = NULL;
  }
  if(stage->reqs != NULL && free_reqs) {
192
193
194
195
    for(mpi_index=0; mpi_index<stage->req_count; mpi_index++) {
      if(stage->reqs[mpi_index] != MPI_REQUEST_NULL) {
        MPI_Request_free(&(stage->reqs[mpi_index]));
	stage->reqs[mpi_index] = MPI_REQUEST_NULL;
196
      }
197
    }
198
199
200
201
202
203
    free(stage->reqs);
    stage->reqs = NULL;
  }
  if(stage->counts.counts != NULL) {
    freeCounts(&(stage->counts));
  }
204
205
206
207
208
209
210
}


/*
 * Imprime por salida estandar toda la informacion que contiene
 * la configuracion pasada como argumento
 */
211
void print_config(configuration *user_config) {
212
  if(user_config != NULL) {
213
    size_t i, j;
214
215
    printf("Config loaded: R=%zu, S=%zu, granularity=%d, SDR=%zu, ADR=%zu, Rigid=%d, Capture_Method=%d\n",
        user_config->n_resizes, user_config->n_stages, user_config->granularity, user_config->sdr, user_config->adr, user_config->rigid_times, user_config->capture_method);
216
    for(i=0; i<user_config->n_stages; i++) {
217
218
      printf("Stage %zu: PT=%d, T_stage=%lf, bytes=%d, T_capped=%d\n",
        i, user_config->stages[i].pt, user_config->stages[i].t_stage, user_config->stages[i].real_bytes, user_config->stages[i].t_capped);
219
    }
220
    for(i=0; i<user_config->n_groups; i++) {
221
      printf("Group %zu: Iters=%d, Procs=%d, Factors=%f, Dist=%d, RM=%d, SM=%d",
222
        i, user_config->groups[i].iters, user_config->groups[i].procs, user_config->groups[i].factor, 
223
224
225
226
227
228
229
230
231
232
233
	user_config->groups[i].phy_dist, user_config->groups[i].rm, user_config->groups[i].sm);

      printf(", RS=%d", user_config->groups[i].rs[0]);
      for(j=1; j<user_config->groups[i].rs_len; j++) {
        printf("/%d", user_config->groups[i].rs[j]);
      }
      printf(", SS=%d", user_config->groups[i].ss[0]);
      for(j=1; j<user_config->groups[i].ss_len; j++) {
        printf("/%d", user_config->groups[i].ss[j]);
      }
      printf("\n");
234
235
236
237
238
239
240
241
242
    }
  }
}


/*
 * Imprime por salida estandar la informacion relacionada con un
 * solo grupo de procesos en su configuracion.
 */
243
244
void print_config_group(configuration *user_config, size_t grp) {
  size_t i;
245
246
247
248
  if(user_config != NULL) {
    int parents, sons;
    parents = sons = 0;
    if(grp > 0) {
249
      parents = user_config->groups[grp-1].procs;
250
    }
251
    if(grp < user_config->n_groups - 1) {
252
      sons = user_config->groups[grp+1].procs;
253
254
    }

255
256
    printf("Config: granularity=%d, SDR=%zu, ADR=%zu, Rigid=%d, Capture_Method=%d\n",
        user_config->granularity, user_config->sdr, user_config->adr, user_config->rigid_times, user_config->capture_method);
257
    for(i=0; i<user_config->n_stages; i++) {
258
259
      printf("Stage %zu: PT=%d, T_stage=%lf, bytes=%d, T_capped=%d\n",
        i, user_config->stages[i].pt, user_config->stages[i].t_stage, user_config->stages[i].real_bytes, user_config->stages[i].t_capped);
260
    }
261
262
263
264
265
266
267
268
269
270
271
272
    printf("Group %zu: Iters=%d, Procs=%d, Factors=%f, Dist=%d, RM=%d, SM=%d", grp, user_config->groups[grp].iters, user_config->groups[grp].procs, user_config->groups[grp].factor,
      user_config->groups[grp].phy_dist, user_config->groups[grp].rm, user_config->groups[grp].sm);

    printf(", RS=%d", user_config->groups[grp].rs[0]);
    for(i=1; i<user_config->groups[grp].rs_len; i++) {
      printf("/%d", user_config->groups[grp].rs[i]);
    }
    printf(", SS=%d", user_config->groups[grp].ss[0]);
    for(i=1; i<user_config->groups[grp].ss_len; i++) {
      printf("/%d", user_config->groups[grp].ss[i]);
    }
    printf(", parents=%d, children=%d\n", parents, sons);
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  }
}


//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ||
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ||
//| FUNCIONES DE INTERCOMUNICACION DE ESTRUCTURA DE CONFIGURACION ||
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ||
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| |/

/*
 * Envia una estructura de configuracion 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 la
 * configuracion al otro grupo.
 */
void send_config_file(configuration *config_file, int root, MPI_Comm intercomm) {
292
293
  MPI_Bcast(config_file, 1, config_file->config_type, root, intercomm);
  MPI_Bcast(config_file->stages, config_file->n_stages, config_file->iter_stage_type, root, intercomm);
294
295
  MPI_Bcast(config_file->groups, config_file->n_groups, config_file->group_type, root, intercomm);
  MPI_Bcast(config_file->groups, 1, config_file->group_strats_type, root, intercomm);
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
}



/*
 * Recibe una estructura de configuracion desde otro grupo de procesos
 * y la devuelve. La memoria de la estructura se reserva en esta funcion.
 *
 * 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
 * la configuracion a este grupo.
 *
 * La memoria de la configuracion devuelta tiene que ser liberada con
 * la funcion "free_config".
 */
void recv_config_file(int root, MPI_Comm intercomm, configuration **config_file_out) {
312
  size_t i;
313
314
  configuration *config_file = malloc(sizeof(configuration));
  def_struct_config_file(config_file);
315

316
  MPI_Bcast(config_file, 1, config_file->config_type, root, intercomm);
317
318

  //Inicializado de estructuras internas
319
  config_file->n_resizes = config_file->n_groups-1;
320
  malloc_config_stages(config_file); // Inicializar a NULL vectores stage
321
  malloc_config_resizes(config_file); // Inicializar valores de grupos
322
  MPI_Bcast(config_file->stages, config_file->n_stages, config_file->iter_stage_type, root, intercomm);
323
324
325
326
327
328
329
330
  MPI_Bcast(config_file->groups, config_file->n_groups, config_file->group_type, root, intercomm);

  for(i=0; i<config_file->n_groups; i++) {
    config_file->groups[i].ss = (int *) malloc(config_file->groups[i].ss_len * sizeof(int));
    config_file->groups[i].rs = (int *) malloc(config_file->groups[i].rs_len * sizeof(int));
  }
  def_struct_groups_strategies(config_file); // Inicializar vectores de grupos
  MPI_Bcast(config_file->groups, 1, config_file->group_strats_type, root, intercomm);
331
332
333
334
335
336

  *config_file_out = config_file;
}


/*
337
 * Tipo derivado para enviar 7 elementos especificos
338
339
 * de la estructura de configuracion con una sola comunicacion.
 */
340
void def_struct_config_file(configuration *config_file) {
341
342
  int i, counts = 7;
  int blocklengths[7] = {1, 1, 1, 1, 1, 1, 1};
343
344
345
346
  MPI_Aint displs[counts], dir;
  MPI_Datatype types[counts];

  // Rellenar vector types
347
  types[0] = types[1] = types[2] = types[3] = MPI_UNSIGNED_LONG;
348
  types[4] = types[5] = types[6] = MPI_INT;
349
350
351
352

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

353
  MPI_Get_address(&(config_file->n_groups), &displs[0]);
354
  MPI_Get_address(&(config_file->n_stages), &displs[1]);
355
356
357
  MPI_Get_address(&(config_file->sdr), &displs[2]);
  MPI_Get_address(&(config_file->adr), &displs[3]);
  MPI_Get_address(&(config_file->granularity), &displs[4]);
358
  MPI_Get_address(&(config_file->rigid_times), &displs[5]);
359
  MPI_Get_address(&(config_file->capture_method), &displs[6]);
360
361
362

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

363
364
  MPI_Type_create_struct(counts, blocklengths, displs, types, &(config_file->config_type));
  MPI_Type_commit(&(config_file->config_type));
365
366
367
}

/*
368
369
370
 * Tipo derivado para enviar elementos especificos
 * de la estructuras de la configuracion de cada grupo 
 * en una sola comunicacion.
371
 */
372
void def_struct_groups(configuration *config_file) {
373
374
  int i, counts = 8;
  int blocklengths[8] = {1, 1, 1, 1, 1, 1, 1, 1};
375
376
  MPI_Aint displs[counts], dir;
  MPI_Datatype aux, types[counts];
377
  group_config_t *groups = config_file->groups;
378
379

  // Rellenar vector types
380
381
  types[0] = types[1] = types[2] = types[4] = types[5] = MPI_INT;
  types[3] = types[6] = MPI_UNSIGNED_LONG;
382
  types[7] = MPI_FLOAT;
383

384
385
  // Rellenar vector displs
  MPI_Get_address(groups, &dir);
386

387
388
389
  MPI_Get_address(&(groups->iters), &displs[0]);
  MPI_Get_address(&(groups->procs), &displs[1]);
  MPI_Get_address(&(groups->sm), &displs[2]);
390
  MPI_Get_address(&(groups->ss_len), &displs[3]);
391
  MPI_Get_address(&(groups->phy_dist), &displs[4]);
392
  MPI_Get_address(&(groups->rm), &displs[5]);
393
  MPI_Get_address(&(groups->rs_len), &displs[6]);
394
  MPI_Get_address(&(groups->factor), &displs[7]);
395
396
397

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

398
399
400
  if (config_file->n_groups == 1) {
    MPI_Type_create_struct(counts, blocklengths, displs, types, &(config_file->group_type));
    MPI_Type_commit(&(config_file->group_type));
401
402
403
  } else { // Si hay mas de una fase(estructura), el "extent" se modifica.
    MPI_Type_create_struct(counts, blocklengths, displs, types, &aux);
    // Tipo derivado para enviar N elementos de la estructura
404
405
    MPI_Type_create_resized(aux, 0, sizeof(group_config_t), &(config_file->group_type));
    MPI_Type_commit(&(config_file->group_type));
406
    MPI_Type_free(&aux);
407
  }
408
409
}

410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
/*
 * Tipo derivado para enviar las estrategias
 * de cada grupo con una sola comunicacion.
 */
void def_struct_groups_strategies(configuration *config_file) {
  int i, counts = config_file->n_groups*2;
  int *blocklengths;
  MPI_Aint *displs, dir;
  MPI_Datatype *types;
  group_config_t *group;

  blocklengths = (int *) malloc(counts * sizeof(int));
  displs = (MPI_Aint *) malloc(counts * sizeof(MPI_Aint));
  types = (MPI_Datatype *) malloc(counts * sizeof(MPI_Datatype));

  MPI_Get_address(config_file->groups, &dir);
  for(i = 0; i < counts; i+=2) {
    group = &config_file->groups[i/2];

    MPI_Get_address(group->ss, &displs[i]);
    MPI_Get_address(group->rs, &displs[i+1]);
    displs[i] -= dir;
    displs[i+1] -= dir;
    types[i] = types[i+1] = MPI_INT;
    blocklengths[i] = group->ss_len;
    blocklengths[i+1] = group->rs_len;
  }

  MPI_Type_create_struct(counts, blocklengths, displs, types, &config_file->group_strats_type);
  MPI_Type_commit(&config_file->group_strats_type);

  free(blocklengths);
  free(displs);
  free(types);
}

446
447
448
449
/*
 * Tipo derivado para enviar elementos especificos
 * de la estructuras de fases de iteracion en una sola comunicacion.
 */
450
void def_struct_iter_stage(configuration *config_file) {
451
452
  int i, counts = 6;
  int blocklengths[6] = {1, 1, 1, 1, 1, 1};
453
454
  MPI_Aint displs[counts], dir;
  MPI_Datatype aux, types[counts];
455
  iter_stage_t *stages = config_file->stages;
456
457

  // Rellenar vector types
458
459
  types[0] = types[1] = types[2] = types[3] = MPI_INT;
  types[4] = types[5] = MPI_DOUBLE;
460
461
462
463
464

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

  MPI_Get_address(&(stages->pt), &displs[0]);
465
466
467
468
469
  MPI_Get_address(&(stages->id), &displs[1]);
  MPI_Get_address(&(stages->bytes), &displs[2]);
  MPI_Get_address(&(stages->t_capped), &displs[3]);
  MPI_Get_address(&(stages->t_stage), &displs[4]);
  MPI_Get_address(&(stages->t_op), &displs[5]);
470
471
472

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

473
474
475
  if (config_file->n_stages == 1) {
    MPI_Type_create_struct(counts, blocklengths, displs, types, &(config_file->iter_stage_type));
    MPI_Type_commit(&(config_file->iter_stage_type));
476
477
478
  } else { // Si hay mas de una fase(estructura), el "extent" se modifica.
    MPI_Type_create_struct(counts, blocklengths, displs, types, &aux);
    // Tipo derivado para enviar N elementos de la estructura
479
480
    MPI_Type_create_resized(aux, 0, sizeof(iter_stage_t), &(config_file->iter_stage_type)); 
    MPI_Type_commit(&(config_file->iter_stage_type));
481
    MPI_Type_free(&aux);
482
483
  }
}