read_ini.c 16.3 KB
Newer Older
1
2
3
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
iker_martin's avatar
iker_martin committed
4
#include <mpi.h>
5
#include "read_ini.h"
iker_martin's avatar
iker_martin committed
6
#include "../malleability/ProcessDist.h"
7
#include "../malleability/distribution_methods/block_distribution.h"
8
9
#include "ini.h"

iker_martin's avatar
iker_martin committed
10

11
void malloc_config_resizes(configuration *user_config, int resizes);
12
void init_config_stages(configuration *user_config);
iker_martin's avatar
iker_martin committed
13
14
void def_struct_config_file(configuration *config_file, MPI_Datatype *config_type);
void def_struct_config_file_array(configuration *config_file, MPI_Datatype *config_type);
15
void def_struct_iter_stage(iter_stage_t *stages, int n_stages, MPI_Datatype *config_type);
iker_martin's avatar
iker_martin committed
16

17
18
19
20
21
22
23
/*
 * Funcion utilizada para leer el fichero de configuracion
 * y guardarlo en una estructura para utilizarlo en el futuro.
 *
 * Primero lee la seccion "general" y a continuacion cada una
 * de las secciones "resize%d".
 */
24
25
26
27
28
static int handler(void* user, const char* section, const char* name,
                   const char* value) {
    configuration* pconfig = (configuration*)user;

    char *resize_name = malloc(10 * sizeof(char));
29
    snprintf(resize_name, 10, "resize%d", pconfig->actual_resize);
30

31
32
    char *stage_name = malloc(10 * sizeof(char));
    snprintf(stage_name, 10, "stage%d", pconfig->actual_stage);
33

34
    #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
35
36
37
38
39
40
    if (MATCH("general", "R")) {
        pconfig->n_resizes = atoi(value) + 1;
        malloc_config_resizes(pconfig, pconfig->n_resizes);
    } else if (MATCH("general", "S")) {
        pconfig->n_stages = atoi(value);
        pconfig->stages = malloc(sizeof(iter_stage_t) * pconfig->n_stages);
41
        init_config_stages(pconfig);
42
43
    } else if (MATCH("general", "Granularity")) {
        pconfig->granularity = atoi(value);
44
45
46
47
    } else if (MATCH("general", "SDR")) {
        pconfig->sdr = atoi(value);
    } else if (MATCH("general", "ADR")) {
        pconfig->adr = atoi(value);
48
49
50
51
52
53
    } else if (MATCH("general", "AT")) {
        pconfig->at = atoi(value);
    } else if (MATCH("general", "SM")) {
        pconfig->sm = atoi(value);
    } else if (MATCH("general", "SS")) {
        pconfig->ss = atoi(value);
54

55
    // Iter stage
56
57
58
59
60
61
62
63
64
65
    } else if (MATCH(stage_name, "PT")) {
	if(pconfig->actual_stage < pconfig->n_stages)
          pconfig->stages[pconfig->actual_stage].pt = atoi(value);
    } else if (MATCH(stage_name, "bytes")) {
	if(pconfig->actual_stage < pconfig->n_stages)
          pconfig->stages[pconfig->actual_stage].bytes = atoi(value);
    } else if (MATCH(stage_name, "t_stage")) {
	if(pconfig->actual_stage < pconfig->n_stages) {
          pconfig->stages[pconfig->actual_stage].t_stage = atof(value);
          pconfig->actual_stage = pconfig->actual_stage+1; // Ultimo elemento del grupo
66
	}
67
68

    // Resize stage
69
70
71
72
73
74
75
76
77
78
79
    } else if (MATCH(resize_name, "Iters")) {
	if(pconfig->actual_resize < pconfig->n_resizes)
          pconfig->iters[pconfig->actual_resize] = atoi(value);
    } else if (MATCH(resize_name, "Procs")) {
	if(pconfig->actual_resize < pconfig->n_resizes)
          pconfig->procs[pconfig->actual_resize] = atoi(value);
    } else if (MATCH(resize_name, "FactorS")) {
	if(pconfig->actual_resize < pconfig->n_resizes)
          pconfig->factors[pconfig->actual_resize] = atof(value);
    } else if (MATCH(resize_name, "Dist")) {
	if(pconfig->actual_resize < pconfig->n_resizes) {
80
  	  char *aux = strdup(value);
81
82
          if (strcmp(aux, "spread") == 0) {
            pconfig->phy_dist[pconfig->actual_resize] = COMM_PHY_SPREAD;
83
  	  } else {
84
            pconfig->phy_dist[pconfig->actual_resize] = COMM_PHY_COMPACT;
85
86
87
	  }
	  free(aux);
          pconfig->actual_resize = pconfig->actual_resize+1; // Ultimo elemento del grupo
88
	}
89

90
91
92
93
94
    } else {
        return 0;  /* unknown section or name, error */
    }
 
    free(resize_name);
95
    free(stage_name);
96
97
98
    return 1;
}

99
100
101
102
103
104
105
/*
 * Crea y devuelve una estructura de configuracion a traves
 * de un nombre de fichero dado.
 *
 * La memoria de la estructura se reserva en la funcion y es conveniente
 * liberarla con la funcion "free_config()"
 */
106
107
108
109
110
111
112
113
114
configuration *read_ini_file(char *file_name) {
    configuration *config = NULL;

    config = malloc(sizeof(configuration) * 1);
    if(config == NULL) {
        printf("Error when reserving configuration structure\n");
	return NULL;
    }
    config->actual_resize=0;
115
    config->actual_stage=0;
116
117
118
119
120
121
122
123
124
125
126

    if(ini_parse(file_name, handler, config) < 0) { // Obtener configuracion
        printf("Can't load '%s'\n", file_name);
        return NULL;
    }
    return config;
}

/*
 * Reserva de memoria para los vectores de la estructura de configuracion
 *
127
128
129
130
131
132
133
 * 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
 *  - read_ini_file
 *  - recv_config_file
134
 */
135
void malloc_config_resizes(configuration *user_config, int resizes) {
136
137
138
    if(user_config != NULL) {
      user_config->iters = malloc(sizeof(int) * resizes);
      user_config->procs = malloc(sizeof(int) * resizes);
iker_martin's avatar
iker_martin committed
139
      user_config->factors = malloc(sizeof(float) * resizes);
140
141
142
143
      user_config->phy_dist = malloc(sizeof(int) * resizes);
    }
}

144
145
146
147
148
149
150
151
152
/*
 * 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
 *  - read_ini_file
 *  - recv_config_file
 */
153
void init_config_stages(configuration *user_config) {
154
155
    int i;
    if(user_config != NULL) {
156
157
158
159
160
161
       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;
        user_config->stages[i].counts.counts = NULL;
        user_config->stages[i].real_bytes = 0;
162
163
        user_config->stages[i].intercept = 0;
        user_config->stages[i].slope = 0;
164
165
166
167
      }
    }
}

168
169
170
/*
 * Libera toda la memoria de una estructura de configuracion
 */
171
void free_config(configuration *user_config) {
172
    int i;
173
    if(user_config != NULL) {
174
175
176
177
      free(user_config->iters);
      free(user_config->procs);
      free(user_config->factors);
      free(user_config->phy_dist);
178
      
179
      for(i=0; i < user_config->n_stages; i++) {
180
	
181
182
183
        if(user_config->stages[i].array != NULL) {
          free(user_config->stages[i].array);
          user_config->stages[i].array = NULL;
184
	}
185
186
187
        if(user_config->stages[i].full_array != NULL) {
          free(user_config->stages[i].full_array);
          user_config->stages[i].full_array = NULL;
188
	}
189
190
191
        if(user_config->stages[i].double_array != NULL) {
          free(user_config->stages[i].double_array);
          user_config->stages[i].double_array = NULL;
192
	}
193
194
        if(user_config->stages[i].counts.counts != NULL) {
	  freeCounts(&(user_config->stages[i].counts));
195
196
	}
	
197
      }
198
      
199
      //free(user_config->stages); //FIXME ERROR de memoria relacionado con la carpeta malleability
200
      free(user_config);
201
202
203
    }
}

204
/*
205
206
207
 * Imprime por salida estandar toda la informacion que contiene
 * la configuracion pasada como argumento
 */
208
void print_config(configuration *user_config, int grp) {
209
210
  if(user_config != NULL) {
    int i;
211
    printf("Config loaded: R=%d, S=%d, granularity=%d, SDR=%d, ADR=%d, AT=%d, SM=%d, SS=%d, latency=%2.8f, bw=%lf || grp=%d\n",
212
213
214
215
216
        user_config->n_resizes, user_config->n_stages, user_config->granularity, user_config->sdr, user_config->adr, 
	user_config->at, user_config->sm, user_config->ss, user_config->latency_m, user_config->bw_m, grp);
    for(i=0; i<user_config->n_stages; i++) {
      printf("Stage %d: PT=%d, T_stage=%lf, bytes=%d, Intercept=%lf, Slope=%lf\n",
        i, user_config->stages[i].pt, user_config->stages[i].t_stage, user_config->stages[i].real_bytes, user_config->stages[i].intercept, user_config->stages[i].slope);
217
    }
218
219
    for(i=0; i<user_config->n_resizes; i++) {
      printf("Resize %d: Iters=%d, Procs=%d, Factors=%f, Dist=%d\n",
220
221
222
223
        i, user_config->iters[i], user_config->procs[i], user_config->factors[i], user_config->phy_dist[i]);
    }
  }
}
iker_martin's avatar
iker_martin committed
224
225


226
227
228
229
/*
 * Imprime por salida estandar la informacion relacionada con un
 * solo grupo de procesos en su configuracion.
 */
230
void print_config_group(configuration *user_config, int grp) {
231
  int i;
232
233
234
235
236
237
  if(user_config != NULL) {
    int parents, sons;
    parents = sons = 0;
    if(grp > 0) {
      parents = user_config->procs[grp-1];
    }
238
    if(grp < user_config->n_resizes - 1) {
239
240
241
      sons = user_config->procs[grp+1];
    }

242
    printf("Config: granularity=%d, SDR=%d, ADR=%d, AT=%d, SM=%d, SS=%d, latency=%2.8f, bw=%lf\n",
243
244
245
246
        user_config->granularity, user_config->sdr, user_config->adr, user_config->at, user_config->sm, user_config->ss, user_config->latency_m, user_config->bw_m);
    for(i=0; i<user_config->n_stages; i++) {
      printf("Stage %d: PT=%d, T_stage=%lf, bytes=%d, Intercept=%lf, Slope=%lf\n",
        i, user_config->stages[i].pt, user_config->stages[i].t_stage, user_config->stages[i].real_bytes, user_config->stages[i].intercept, user_config->stages[i].slope);
247
    }
248
249
250
251
252
    printf("Config Group: iters=%d, factor=%f, phy=%d, procs=%d, parents=%d, sons=%d\n",
        user_config->iters[grp], user_config->factors[grp], user_config->phy_dist[grp], user_config->procs[grp], parents, sons);
  }
}

253
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ||
254
255
256
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ||
//| FUNCIONES DE INTERCOMUNICACION DE ESTRUCTURA DE CONFIGURACION ||
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ||
257
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| |/
iker_martin's avatar
iker_martin committed
258

259
260
261
262
263
264
265
266
/*
 * 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.
 */
iker_martin's avatar
iker_martin committed
267
268
void send_config_file(configuration *config_file, int root, MPI_Comm intercomm) {

269
  MPI_Datatype config_type, config_type_array, iter_stage_type;
iker_martin's avatar
iker_martin committed
270

271
272
  // Obtener un tipo derivado para enviar todos los
  // datos escalares con una sola comunicacion
iker_martin's avatar
iker_martin committed
273
274
  def_struct_config_file(config_file, &config_type);

275
276
277

  // Obtener un tipo derivado para enviar los tres vectores
  // de enteros con una sola comunicacion
iker_martin's avatar
iker_martin committed
278
  def_struct_config_file_array(config_file, &config_type_array);
279

280
281
  // Obtener un tipo derivado para enviar las estructuras de fases de iteracion
  // con una sola comunicacion
282
  def_struct_iter_stage(&(config_file->stages[0]), config_file->n_stages, &iter_stage_type);
283

284
  MPI_Bcast(config_file, 1, config_type, root, intercomm);
iker_martin's avatar
iker_martin committed
285
  MPI_Bcast(config_file, 1, config_type_array, root, intercomm);
286
287
  MPI_Bcast(config_file->factors, config_file->n_resizes, MPI_FLOAT, root, intercomm);
  MPI_Bcast(config_file->stages, config_file->n_stages, iter_stage_type, root, intercomm);
iker_martin's avatar
iker_martin committed
288

289
  //Liberar tipos derivados
iker_martin's avatar
iker_martin committed
290
291
  MPI_Type_free(&config_type);
  MPI_Type_free(&config_type_array);
292
  MPI_Type_free(&iter_stage_type);
iker_martin's avatar
iker_martin committed
293
294
}

295
296
297
298
299
300
301
302
303
304
305
/*
 * 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".
 */
306
void recv_config_file(int root, MPI_Comm intercomm, configuration **config_file_out) {
iker_martin's avatar
iker_martin committed
307

308
  MPI_Datatype config_type, config_type_array, iter_stage_type;
iker_martin's avatar
iker_martin committed
309

310

iker_martin's avatar
iker_martin committed
311
312
  configuration *config_file = malloc(sizeof(configuration) * 1);

313
314
315
  // Obtener un tipo derivado para recibir todos los
  // datos escalares con una sola comunicacion
  def_struct_config_file(config_file, &config_type);
iker_martin's avatar
iker_martin committed
316
317
  MPI_Bcast(config_file, 1, config_type, root, intercomm);

318
  //Inicializado de estructuras internas
319
320
  malloc_config_resizes(config_file, config_file->n_resizes); // Reserva de memoria de los vectores
  config_file->stages = malloc(sizeof(iter_stage_t) * config_file->n_stages);
321

322
323
  // Obtener un tipo derivado para enviar los tres vectores
  // de enteros con una sola comunicacion
iker_martin's avatar
iker_martin committed
324
  def_struct_config_file_array(config_file, &config_type_array);
325
  def_struct_iter_stage(&(config_file->stages[0]), config_file->n_stages, &iter_stage_type);
iker_martin's avatar
iker_martin committed
326
327

  MPI_Bcast(config_file, 1, config_type_array, root, intercomm);
328
329
  MPI_Bcast(config_file->factors, config_file->n_resizes, MPI_FLOAT, root, intercomm);
  MPI_Bcast(config_file->stages, config_file->n_stages, iter_stage_type, root, intercomm);
iker_martin's avatar
iker_martin committed
330

331
  //Liberar tipos derivados
iker_martin's avatar
iker_martin committed
332
333
  MPI_Type_free(&config_type);
  MPI_Type_free(&config_type_array);
334
  MPI_Type_free(&iter_stage_type);
iker_martin's avatar
iker_martin committed
335

336
  init_config_stages(config_file); // Inicializar a NULL vectores
337
  *config_file_out = config_file;
iker_martin's avatar
iker_martin committed
338
339
}

340
/*
341
 * Tipo derivado para enviar 11 elementos especificos
342
343
 * de la estructura de configuracion con una sola comunicacion.
 */
iker_martin's avatar
iker_martin committed
344
void def_struct_config_file(configuration *config_file, MPI_Datatype *config_type) {
345
346
  int i, counts = 11;
  int blocklengths[11] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
iker_martin's avatar
iker_martin committed
347
348
349
350
  MPI_Aint displs[counts], dir;
  MPI_Datatype types[counts];

  // Rellenar vector types
351
352
  types[0] = types[1] = types[2] = types[3] = types[4] = types[5] = types[6] = types[7] = types[8] = MPI_INT;
  types[9] = types[10] = MPI_DOUBLE;
iker_martin's avatar
iker_martin committed
353

354
  // Rellenar vector displs
iker_martin's avatar
iker_martin committed
355
356
  MPI_Get_address(config_file, &dir);

357
358
359
360
  MPI_Get_address(&(config_file->n_resizes), &displs[0]);
  MPI_Get_address(&(config_file->n_stages), &displs[1]);
  MPI_Get_address(&(config_file->actual_resize), &displs[2]); // TODO Refactor Es necesario enviarlo?
  MPI_Get_address(&(config_file->granularity), &displs[3]);
361
362
  MPI_Get_address(&(config_file->sdr), &displs[4]);
  MPI_Get_address(&(config_file->adr), &displs[5]);
363
364
365
  MPI_Get_address(&(config_file->at), &displs[6]);
  MPI_Get_address(&(config_file->ss), &displs[7]);
  MPI_Get_address(&(config_file->sm), &displs[8]);
366
367
  MPI_Get_address(&(config_file->latency_m), &displs[9]);
  MPI_Get_address(&(config_file->bw_m), &displs[10]);
iker_martin's avatar
iker_martin committed
368
369
370
371
372
373
374

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

  MPI_Type_create_struct(counts, blocklengths, displs, types, config_type);
  MPI_Type_commit(config_type);
}

375
376
377
378
/*
 * Tipo derivado para enviar tres vectores de enteros
 * de la estructura de configuracion con una sola comunicacion.
 */
iker_martin's avatar
iker_martin committed
379
380
381
382
383
384
385
386
387
388
void def_struct_config_file_array(configuration *config_file, MPI_Datatype *config_type) {
  int i, counts = 3;
  int blocklengths[3] = {1, 1, 1};
  MPI_Aint displs[counts], dir;
  MPI_Datatype aux, types[counts];

  // Rellenar vector types
  types[0] = types[1] = types[2] = MPI_INT;

  // Modificar blocklengths al valor adecuado
389
  blocklengths[0] = blocklengths[1] = blocklengths[2] = config_file->n_resizes;
iker_martin's avatar
iker_martin committed
390
391
392
393
394
395
396
397
398
399

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

  MPI_Get_address(config_file->iters, &displs[0]);
  MPI_Get_address(config_file->procs, &displs[1]);
  MPI_Get_address(config_file->phy_dist, &displs[2]);

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

400
  // Tipo derivado para enviar un solo elemento de tres vectores
iker_martin's avatar
iker_martin committed
401
  MPI_Type_create_struct(counts, blocklengths, displs, types, &aux);
402
403
  // Tipo derivado para enviar N elementos de tres vectores(3N en total)
  MPI_Type_create_resized(aux, 0, 1*sizeof(int), config_type); 
iker_martin's avatar
iker_martin committed
404
405
  MPI_Type_commit(config_type);
}
406
407
408
409
410
411


/*
 * Tipo derivado para enviar elementos especificos
 * de la estructuras de fases de iteracion en una sola comunicacion.
 */
412
void def_struct_iter_stage(iter_stage_t *stages, int n_stages, MPI_Datatype *config_type) {
413
414
415
  int i, counts = 4;
  int blocklengths[4] = {1, 1, 1, 1};
  MPI_Aint displs[counts], dir;
416
  MPI_Datatype aux, types[counts];
417
418

  // Rellenar vector types
419
  types[0] = types[3] = MPI_INT;
420
  types[1] = MPI_FLOAT;
421
  types[2] = MPI_DOUBLE;
422
423

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

426
427
428
429
  MPI_Get_address(&(stages->pt), &displs[0]);
  MPI_Get_address(&(stages->t_stage), &displs[1]);
  MPI_Get_address(&(stages->t_op), &displs[2]);
  MPI_Get_address(&(stages->bytes), &displs[3]);
430
431
432

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

433
  if (n_stages == 1) {
434
435
436
437
    MPI_Type_create_struct(counts, blocklengths, displs, types, config_type);
  } 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
438
    MPI_Type_create_resized(aux, 0, sizeof(iter_stage_t), config_type); 
439
  }
440
441
  MPI_Type_commit(config_type);
}