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

void malloc_config_resizes(configuration *user_config);
11
void malloc_config_stages(configuration *user_config);
12
13

void def_struct_config_file(configuration *config_file, MPI_Datatype *config_type);
14
void def_struct_groups(group_config_t *groups, size_t n_resizes, MPI_Datatype *config_type);
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void def_struct_iter_stage(iter_stage_t *stages, size_t n_stages, MPI_Datatype *config_type);

/*
 * 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;
32
    mallocs.stages_f = malloc_config_stages;
33
34
35
36
37
    *user_config = read_ini_file(file_name, mallocs);
  } else {
    configuration *config = NULL;

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

/*
 * 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
59
 *  - init_config
60
61
62
 *  - recv_config_file
 */
void malloc_config_resizes(configuration *user_config) {
63
  size_t i;
64
  if(user_config != NULL) {
65
    user_config->groups = malloc(sizeof(group_config_t) * user_config->n_resizes);
66
67
68
69
70
71
72
73
74
    for(i=0; i<user_config->n_resizes; i++) {
      user_config->groups[i].iters = 0;
      user_config->groups[i].procs = 1;
      user_config->groups[i].sm = 0;
      user_config->groups[i].ss = 1;
      user_config->groups[i].phy_dist = 0;
      user_config->groups[i].at = 0;
      user_config->groups[i].factor = 1;
    }
75
76
77
78
79
80
81
82
83
  }
}

/*
 * 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
84
 *  - init_config
85
86
 *  - recv_config_file
 */
87
void malloc_config_stages(configuration *user_config) {
88
  size_t i;
89
  if(user_config != NULL) {
90
    user_config->stages = malloc(sizeof(iter_stage_t) * user_config->n_stages);
91
    user_config->t_op_comms = 0;
92
93
94
95
96
97
    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;
98
    }
99
  }
100
101
102
103
104
105
106
}


/*
 * Libera toda la memoria de una estructura de configuracion
 */
void free_config(configuration *user_config) {
107
    size_t i;
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    if(user_config != NULL) {
      
      for(i=0; i < user_config->n_stages; i++) {
	
        if(user_config->stages[i].array != NULL) {
          free(user_config->stages[i].array);
          user_config->stages[i].array = NULL;
	}
        if(user_config->stages[i].full_array != NULL) {
          free(user_config->stages[i].full_array);
          user_config->stages[i].full_array = NULL;
	}
        if(user_config->stages[i].double_array != NULL) {
          free(user_config->stages[i].double_array);
          user_config->stages[i].double_array = NULL;
	}
        if(user_config->stages[i].counts.counts != NULL) {
	  freeCounts(&(user_config->stages[i].counts));
	}
	
      }
      
130
      free(user_config->groups);
131
      free(user_config->stages);
132
133
134
135
136
137
138
139
140
      free(user_config);
    }
}


/*
 * Imprime por salida estandar toda la informacion que contiene
 * la configuracion pasada como argumento
 */
141
void print_config(configuration *user_config) {
142
  if(user_config != NULL) {
143
144
    size_t i;
    printf("Config loaded: R=%zu, S=%zu, granularity=%d, SDR=%d, ADR=%d, latency=%2.8f, bw=%lf\n",
145
        user_config->n_resizes, user_config->n_stages, user_config->granularity, user_config->sdr, user_config->adr, 
146
	user_config->latency_m, user_config->bw_m);
147
    for(i=0; i<user_config->n_stages; i++) {
148
      printf("Stage %zu: PT=%d, T_stage=%lf, bytes=%d\n",
149
        i, user_config->stages[i].pt, user_config->stages[i].t_stage, user_config->stages[i].real_bytes);
150
151
    }
    for(i=0; i<user_config->n_resizes; i++) {
152
      printf("Group %zu: Iters=%d, Procs=%d, Factors=%f, Dist=%d, AT=%d, SM=%d, SS=%d\n",
153
154
155
        i, user_config->groups[i].iters, user_config->groups[i].procs, user_config->groups[i].factor, 
	user_config->groups[i].phy_dist, user_config->groups[i].at, user_config->groups[i].sm,
	user_config->groups[i].ss);
156
157
158
159
160
161
162
163
164
    }
  }
}


/*
 * Imprime por salida estandar la informacion relacionada con un
 * solo grupo de procesos en su configuracion.
 */
165
166
void print_config_group(configuration *user_config, size_t grp) {
  size_t i;
167
168
169
170
  if(user_config != NULL) {
    int parents, sons;
    parents = sons = 0;
    if(grp > 0) {
171
      parents = user_config->groups[grp-1].procs;
172
173
    }
    if(grp < user_config->n_resizes - 1) {
174
      sons = user_config->groups[grp+1].procs;
175
176
    }

177
178
    printf("Config: granularity=%d, SDR=%d, ADR=%d, latency=%2.8f, bw=%lf\n",
        user_config->granularity, user_config->sdr, user_config->adr, user_config->latency_m, user_config->bw_m);
179
    for(i=0; i<user_config->n_stages; i++) {
180
      printf("Stage %zu: PT=%d, T_stage=%lf, bytes=%d\n",
181
        i, user_config->stages[i].pt, user_config->stages[i].t_stage, user_config->stages[i].real_bytes);
182
    }
183
    printf("Group %zu: Iters=%d, Procs=%d, Factors=%f, Dist=%d, AT=%d, SM=%d, SS=%d, parents=%d, children=%d\n",
184
185
186
      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].at, user_config->groups[grp].sm,
      user_config->groups[grp].ss, parents, sons);
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  }
}


//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ||
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ||
//| 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) {
206
  MPI_Datatype config_type, group_type, iter_stage_type;
207
208
209
210
211
212
213

  // Obtener un tipo derivado para enviar todos los
  // datos escalares con una sola comunicacion
  def_struct_config_file(config_file, &config_type);

  // Obtener un tipo derivado para enviar las estructuras de fases de iteracion
  // con una sola comunicacion
214
215
  def_struct_groups(&(config_file->groups[0]), config_file->n_resizes, &group_type);
  def_struct_iter_stage(&(config_file->stages[0]), config_file->n_stages, &iter_stage_type);
216
217

  MPI_Bcast(config_file, 1, config_type, root, intercomm);
218
  MPI_Bcast(config_file->groups, config_file->n_resizes, group_type, root, intercomm);
219
220
221
222
  MPI_Bcast(config_file->stages, config_file->n_stages, iter_stage_type, root, intercomm);

  //Liberar tipos derivados
  MPI_Type_free(&config_type);
223
  MPI_Type_free(&group_type);
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  MPI_Type_free(&iter_stage_type);
}



/*
 * 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) {
241
  MPI_Datatype config_type, group_type, iter_stage_type;
242
243
244
245
246
247
248
249
  configuration *config_file = malloc(sizeof(configuration) * 1);

  // Obtener un tipo derivado para recibir todos los
  // datos escalares con una sola comunicacion
  def_struct_config_file(config_file, &config_type);
  MPI_Bcast(config_file, 1, config_type, root, intercomm);

  //Inicializado de estructuras internas
250
251
  config_file->groups = malloc(sizeof(group_config_t) * config_file->n_resizes);
  config_file->stages = malloc(sizeof(iter_stage_t) * config_file->n_stages);
252
253
  malloc_config_resizes(config_file); // Inicializar valores de grupos
  malloc_config_stages(config_file); // Inicializar a NULL vectores stage
254
255
256

  // Obtener un tipo derivado para enviar los tres vectores
  // de enteros con una sola comunicacion
257
258
  def_struct_groups(&(config_file->groups[0]), config_file->n_resizes, &group_type);
  def_struct_iter_stage(&(config_file->stages[0]), config_file->n_stages, &iter_stage_type);
259
  MPI_Bcast(config_file->groups, config_file->n_resizes, group_type, root, intercomm);
260
261
262
263
  MPI_Bcast(config_file->stages, config_file->n_stages, iter_stage_type, root, intercomm);

  //Liberar tipos derivados
  MPI_Type_free(&config_type);
264
  MPI_Type_free(&group_type);
265
266
267
268
269
270
271
272
273
274
275
  MPI_Type_free(&iter_stage_type);

  *config_file_out = config_file;
}


/*
 * Tipo derivado para enviar 11 elementos especificos
 * de la estructura de configuracion con una sola comunicacion.
 */
void def_struct_config_file(configuration *config_file, MPI_Datatype *config_type) {
276
277
  int i, counts = 8;
  int blocklengths[8] = {1, 1, 1, 1, 1, 1, 1, 1};
278
279
280
281
  MPI_Aint displs[counts], dir;
  MPI_Datatype types[counts];

  // Rellenar vector types
282
283
  types[0] = types[1] = types[2] = types[3] = types[4] = types[5] = MPI_INT;
  types[6] = types[7] = MPI_DOUBLE;
284
285
286
287
288
289

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

  MPI_Get_address(&(config_file->n_resizes), &displs[0]);
  MPI_Get_address(&(config_file->n_stages), &displs[1]);
290
291
292
  MPI_Get_address(&(config_file->granularity), &displs[2]);
  MPI_Get_address(&(config_file->sdr), &displs[3]);
  MPI_Get_address(&(config_file->adr), &displs[4]);
293
294
295
  MPI_Get_address(&(config_file->rigid_times), &displs[5]);
  MPI_Get_address(&(config_file->latency_m), &displs[6]);
  MPI_Get_address(&(config_file->bw_m), &displs[7]);
296
297
298
299
300
301
302
303

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

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

/*
304
305
306
 * Tipo derivado para enviar elementos especificos
 * de la estructuras de la configuracion de cada grupo 
 * en una sola comunicacion.
307
 */
308
309
310
void def_struct_groups(group_config_t *groups, size_t n_resizes, MPI_Datatype *config_type) {
  int i, counts = 7;
  int blocklengths[7] = {1, 1, 1, 1, 1, 1, 1};
311
312
313
314
  MPI_Aint displs[counts], dir;
  MPI_Datatype aux, types[counts];

  // Rellenar vector types
315
316
  types[0] = types[1] = types[2] = types[3] = types[4] = types[5] = MPI_INT;
  types[6] = MPI_DOUBLE;
317

318
319
  // Rellenar vector displs
  MPI_Get_address(groups, &dir);
320

321
322
323
324
325
326
327
  MPI_Get_address(&(groups->iters), &displs[0]);
  MPI_Get_address(&(groups->procs), &displs[1]);
  MPI_Get_address(&(groups->sm), &displs[2]);
  MPI_Get_address(&(groups->ss), &displs[3]);
  MPI_Get_address(&(groups->phy_dist), &displs[4]);
  MPI_Get_address(&(groups->at), &displs[5]);
  MPI_Get_address(&(groups->factor), &displs[6]);
328
329
330

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

331
332
333
334
335
336
337
  if (n_resizes == 1) {
    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
    MPI_Type_create_resized(aux, 0, sizeof(iter_stage_t), config_type); 
  }
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  MPI_Type_commit(config_type);
}

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

  // Rellenar vector types
  types[0] = types[3] = MPI_INT;
353
  types[1] = types[2] = MPI_DOUBLE;
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373

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

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

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

  if (n_stages == 1) {
    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
    MPI_Type_create_resized(aux, 0, sizeof(iter_stage_t), config_type); 
  }
  MPI_Type_commit(config_type);
}