#include #include #include #include #include #include #include "ProcessDist.h" //--------------PRIVATE DECLARATIONS---------------// void node_dist( struct physical_dist dist, int **qty, int *used_nodes); void spread_dist(struct physical_dist dist, int *used_nodes, int *procs); void compact_dist(struct physical_dist dist, int *used_nodes, int *procs); void generate_info_string(char *nodelist, int *procs_array, int nodes, MPI_Info *info); void fill_str_hostfile(char *nodelist, int *qty, int used_nodes, char **hostfile_str); int write_str_node(char **hostfile_str, int len_og, int qty, char *node_name); //@deprecated functions void generate_info_hostfile(char *nodelist, int *procs_array, int nodes, MPI_Info *info); int create_hostfile(char **file_name); void fill_hostfile(char *nodelist, int ptr, int *qty, int used_nodes); int write_hostfile_node(int ptr, int qty, char *node_name); /* * Pone los datos para una estructura que guarda los parametros * para realizar un mappeado de los procesos. * * Si la memoria no esta reservada devuelve falso y no hace nada. * Si puede realizar los cambios devuelve verdadero. * * IN parameters --> * target_qty: Numero de procesos tras la reconfiguracion * alreadyCreated: Numero de procesos padre a considerar * La resta de numC-alreadyCreated es el numero de hijos a crear * num_cpus: Numero de cpus totales (En uso o no) * num_nodes: Numero de nodos disponibles por esta aplicacion * info_type: Indica como realizar el mappeado, si indicarlo * en una cadena (MALL_DIST_STRING) o en un hostfile * (MALL_DIST_HOSTFILE) * dist_type: Indica como sera el mappeado, si intentar rellenar * primero los nodos con cpus ya usados (CPUS/BEST/COMPACT) o * que todos los nodos tengan el mismo numero de cpus usados * (NODES/WORST/SPREAD) */ int physical_struct_create(int target_qty, int already_created, int num_cpus, int num_nodes, char *nodelist, int dist_type, int info_type, struct physical_dist *dist) { if(*dist == NULL) { return 0; } dist->target_qty = target_qty; dist->already_created = already_created; dist->num_cpus = num_cpus; dist->num_cpus = num_nodes; dist->nodelist = nodelist dist->dist_type = dist_type; dist->info_type = info_type; return 1; } /* * Configura la creacion de un nuevo grupo de procesos, reservando la memoria * para una llamada a MPI_Comm_spawn, obteniendo una distribucion fisica * para los procesos y creando un fichero hostfile. * * OUT parameters --> * info_spawn: Objeto MPI_Info en el que se indica el mappeado * a usar al crear los procesos. */ void processes_dist(struct physical_dist dist, MPI_Info *info_spawn) { int used_nodes=0; int *procs_array; // GET NEW DISTRIBUTION node_dist(dist, &procs_array, &used_nodes); switch(dist.info_type) { case MALL_DIST_STRING: generate_info_string(nodelist, procs_array, used_nodes, info_spawn); break; case MALL_DIST_HOSTFILE: generate_info_hostfile(nodelist, procs_array, used_nodes, info_spawn); break; } free(procs_array); } /* * Obtiene la distribucion fisica del grupo de procesos a crear, devolviendo * cuantos nodos se van a utilizar y la cantidad de procesos que alojara cada * nodo. * * Se permiten dos tipos de distribuciones fisicas segun el valor de "dist_type": * * COMM_PHY_NODES (1): Orientada a equilibrar el numero de procesos entre * todos los nodos disponibles. * COMM_PHY_CPU (2): Orientada a completar la capacidad de un nodo antes de * ocupar otro nodo. */ void node_dist(struct physical_dist dist, int **qty, int *used_nodes) { int i, *procs; procs = calloc(dist.num_nodes, sizeof(int)); // Numero de procesos por nodo /* GET NEW DISTRIBUTION */ switch(dist.dist_type) { case MALL_DIST_SPREAD: // DIST NODES @deprecated spread_dist(dist, used_nodes, procs); break; case MALL_DIST_COMPACT: // DIST CPUs compact_dist(dist, used_nodes, procs); break; } //Copy results to output vector qty *qty = calloc(*used_nodes, sizeof(int)); // Numero de procesos por nodo for(i=0; i< *used_nodes; i++) { (*qty)[i] = procs[i]; } free(procs); } /* * Distribucion basada en equilibrar el numero de procesos en cada nodo * para que todos los nodos tengan el mismo numero. Devuelve el total de * nodos utilizados y el numero de procesos a crear en cada nodo. * * TODO Tener en cuenta procesos ya creados (already_created) */ void spread_dist(struct physical_dist dist, int *used_nodes, int *procs) { int i, tamBl, remainder; *used_nodes = dist.num_nodes; tamBl = dist.numC / dist.num_nodes; remainder = dist.numC % dist.num_nodes; for(i=0; i dist.num_nodes) *used_nodes = dist.num_nodes; //FIXME Si ocurre esto no es un error? } /* * Crea y devuelve un objeto MPI_Info con un par hosts/mapping * en el que se indica el mappeado a utilizar en los nuevos * procesos. */ void generate_info_string(char *nodelist, int *procs_array, int nodes, MPI_Info *info){ // CREATE AND SET STRING HOSTS char *hoststring; fill_str_hostfile(nodelist, procs_array, nodes, &hoststring); MPI_Info_create(info); MPI_Info_set(*info, "hosts", hoststring); free(hoststring); } /* * Crea y devuelve una cadena para ser utilizada por la llave "hosts" * al crear procesos e indicar donde tienen que ser creados. */ void fill_str_hostfile(char *nodelist, int *qty, int used_nodes, char **hostfile_str) { int i=0, len=0; char *host; hostlist_t hostlist; hostlist = slurm_hostlist_create(nodelist); while ( (host = slurm_hostlist_shift(hostlist)) && i < used_nodes) { if(qty[i] != 0) { len = write_str_node(hostfile_str, len, qty[i], host); } i++; free(host); } slurm_hostlist_destroy(hostlist); } /* * AƱade en una cadena "qty" entradas de "node_name". * Realiza la reserva de memoria y la realoja si es necesario. */ int write_str_node(char **hostfile_str, int len_og, int qty, char *node_name) { int err, len_node, len, i; char *ocurrence; len_node = strlen(node_name); len = qty * (len_node + 1); if(len_og == 0) { // Memoria no reservada *hostfile_str = (char *) malloc(len * sizeof(char) - (1 * sizeof(char))); } else { // Cadena ya tiene datos *hostfile_str = (char *) realloc(*hostfile_str, (len_og + len) * sizeof(char) - (1 * sizeof(char))); } if(hostfile_str == NULL) return -1; // No ha sido posible alojar la memoria ocurrence = (char *) malloc((len_node+1) * sizeof(char)); if(ocurrence == NULL) return -1; // No ha sido posible alojar la memoria err = sprintf(ocurrence, ",%s", node_name); if(err < 0) return -2; // No ha sido posible escribir sobre la variable auxiliar i=0; if(len_og == 0) { // Si se inicializa, la primera es una copia i++; strcpy(*hostfile_str, node_name); } for(; ijob_array[j_info->record_count - 1]; // Free JOB INFO //slurm_free_job_info_msg(j_info);