configuration.c 16.8 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

323
  MPI_Bcast(config_file->stages, config_file->n_stages, config_file->iter_stage_type, root, intercomm);
324
325
326
327
328
329
330
331
  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);
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
  MPI_Aint displs[counts], dir;
344
345
  MPI_Datatype types[counts], type_size_t;
  MPI_Type_match_size(MPI_TYPECLASS_INTEGER, sizeof(size_t), &type_size_t);
346
347

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

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

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

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

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

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

  // Rellenar vector types
382
  types[0] = types[1] = types[2] = types[4] = types[5] = MPI_INT;
383
  types[3] = types[6] = type_size_t;
384
  types[7] = MPI_FLOAT;
385

386
387
  // Rellenar vector displs
  MPI_Get_address(groups, &dir);
388

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

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

400
401
402
  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));
403
404
405
  } 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
406
407
    MPI_Type_create_resized(aux, 0, sizeof(group_config_t), &(config_file->group_type));
    MPI_Type_commit(&(config_file->group_type));
408
    MPI_Type_free(&aux);
409
  }
410
411
}

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
/*
 * 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) {
429
    group = &(config_file->groups[i/2]);
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

    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);
}

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

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

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

  MPI_Get_address(&(stages->pt), &displs[0]);
467
468
469
470
471
  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]);
472
473
474

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

475
476
477
  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));
478
479
480
  } 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
481
482
    MPI_Type_create_resized(aux, 0, sizeof(iter_stage_t), &(config_file->iter_stage_type)); 
    MPI_Type_commit(&(config_file->iter_stage_type));
483
    MPI_Type_free(&aux);
484
485
  }
}