9e35f80ab6
This commit was SVN r32822.
241 строка
5.5 KiB
C
241 строка
5.5 KiB
C
/* -*- Mode: C; c-basic-offset:4 ; -*- */
|
|
/*
|
|
*
|
|
* Copyright (c) 2013 Mellanox Technologies, Inc.
|
|
* All rights reserved.
|
|
* Copyright (c) 2014 Intel, Inc. All rights reserved.
|
|
* $COPYRIGHT$
|
|
* Additional copyrights may follow
|
|
*
|
|
* $HEADER$
|
|
*
|
|
*/
|
|
|
|
#include "pmi2_pmap_parser.h"
|
|
|
|
/**
|
|
pmi2 process mapping is returned as a
|
|
comma separated list of tuples:
|
|
ex: (vector,(0,4,4),(0,4,1))
|
|
slurm cyclic distro of 4 ranks over 2 nodes:
|
|
(vector,(0,2,1),(0,2,1))
|
|
slurm block distro of 4 ranks over 2 nodes:
|
|
(vector,(0,2,2))
|
|
|
|
|
|
Format of each tuple is (base, H, L), where
|
|
H is number of nodes spawned by tuple,
|
|
L is number of ranks per node,
|
|
base is offset from node 0.
|
|
|
|
Tuple can be visualized as a rectangle on two
|
|
dimensional (Hosts, Local Ranks) plane:
|
|
|
|
------------------------------------ Hosts ->
|
|
| H
|
|
| +--------+
|
|
|<- base -->| |
|
|
| | | L
|
|
| +--------+
|
|
Local Ranks
|
|
V
|
|
|
|
Note that ranks increase by column. Tuple (0,2,3) looks like:
|
|
0 3
|
|
1 4
|
|
2 5
|
|
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
static int find_my_node(char *map, int me)
|
|
{
|
|
int abs_rank;
|
|
int base, H, L;
|
|
char *p;
|
|
|
|
p = map;
|
|
abs_rank = 0;
|
|
while (NULL != (p = strstr(p+1, ",("))) {
|
|
if (3 != sscanf(p, ",(%d,%d,%d)", &base, &H, &L)) {
|
|
return -1;
|
|
}
|
|
if (me >= abs_rank && me < abs_rank + H*L) {
|
|
/* found my rectangle, compute node */
|
|
return base + (me - abs_rank)/L;
|
|
}
|
|
abs_rank += H*L;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int *find_lrs(char *map, int my_node, int *nlrs)
|
|
{
|
|
int abs_rank;
|
|
int base, H, L;
|
|
char *p;
|
|
int *lrs;
|
|
int max_lr;
|
|
int i;
|
|
|
|
p = map;
|
|
abs_rank = 0;
|
|
*nlrs = 0;
|
|
max_lr = 16;
|
|
lrs = malloc(max_lr * sizeof(int));
|
|
while (NULL != (p = strstr(p+1, ",("))) {
|
|
if (3 != sscanf(p, ",(%d,%d,%d)", &base, &H, &L)) {
|
|
free(lrs);
|
|
return NULL;
|
|
}
|
|
if (base <= my_node && my_node < base + H) {
|
|
if (*nlrs + L >= max_lr) {
|
|
lrs = realloc(lrs, (max_lr + L) * sizeof(int));
|
|
if (NULL == lrs) {
|
|
*nlrs = 0;
|
|
free(lrs);
|
|
return NULL;
|
|
}
|
|
max_lr += L;
|
|
}
|
|
/* skip (my_node - base) columns of L elems,
|
|
* numbers in my column are local to me
|
|
*/
|
|
for (i = 0; i < L; i++) {
|
|
lrs[*nlrs] = (my_node - base) * L + i + abs_rank;
|
|
(*nlrs) ++;
|
|
}
|
|
}
|
|
abs_rank += H*L;
|
|
}
|
|
|
|
if (0 == *nlrs) {
|
|
free(lrs);
|
|
lrs = 0;
|
|
}
|
|
return lrs;
|
|
}
|
|
|
|
/**
|
|
* @param pmap process map as returned by PMI_process_mapping
|
|
* attribute
|
|
* @param my_rank
|
|
* @param node set to my node id
|
|
* @param nlrs set to the number of local ranks returned
|
|
*
|
|
* @return array that contains ranks local to my_rank or NULL
|
|
* on failure. Array must be freed by the caller.
|
|
*/
|
|
int *mca_common_pmi2_parse_pmap(char *pmap, int my_rank,
|
|
int *node, int *nlrs)
|
|
{
|
|
char *p;
|
|
|
|
p = strstr(pmap, "(vector");
|
|
if (NULL == p) {
|
|
return NULL;
|
|
}
|
|
|
|
*node = find_my_node(p, my_rank);
|
|
if (0 > *node) {
|
|
return NULL;
|
|
}
|
|
|
|
return find_lrs(p, *node, nlrs);
|
|
}
|
|
|
|
|
|
#ifdef STANDALONE_TEST
|
|
#include <assert.h>
|
|
static void dump_lrs(int *lrs, int me, int node, int n)
|
|
{
|
|
int i;
|
|
|
|
printf("Total %d ranks/node, node %d me %d\n", n, node, me);
|
|
for (i = 0; i < n; i++) {
|
|
printf("%d ", lrs[i]);
|
|
}
|
|
printf("\n");
|
|
free(lrs);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int me, n, node;
|
|
int *lrs;
|
|
char *pmap;
|
|
int a1[] = {0, 1};
|
|
int a2[] = {2, 3};
|
|
int a3[] = {0, 2};
|
|
int a4[] = {1, 3};
|
|
int a5[] = {0,1,3,2,16,17};
|
|
int a6[] = {8,9,10,11,19};
|
|
|
|
|
|
if (argc == 3) {
|
|
me = atoi(argv[1]);
|
|
lrs = orte_grpcomm_pmi2_parse_pmap(argv[2], me, &node, &n);
|
|
if (NULL == lrs) {
|
|
printf("can not parse pmap\n");
|
|
exit(1);
|
|
}
|
|
dump_lrs(lrs, me, node, n);
|
|
exit(0);
|
|
}
|
|
/* built in cases */
|
|
|
|
pmap = "(vector,(0,2,2))";
|
|
me = 1;
|
|
lrs = orte_grpcomm_pmi2_parse_pmap(pmap, me, &node, &n);
|
|
assert(lrs);
|
|
assert(n == 2);
|
|
assert(memcmp(lrs, a1, 2) == 0);
|
|
free(lrs);
|
|
|
|
|
|
pmap = "(vector,(0,2,2))";
|
|
me = 2;
|
|
lrs = orte_grpcomm_pmi2_parse_pmap(pmap, me, &node, &n);
|
|
assert(lrs);
|
|
assert(n == 2);
|
|
assert(memcmp(lrs, a2, 2) == 0);
|
|
free(lrs);
|
|
|
|
|
|
/* cyclic distro which skips node 0 */
|
|
pmap = "(vector,(1,2,1),(1,2,1))";
|
|
me = 0;
|
|
lrs = orte_grpcomm_pmi2_parse_pmap(pmap, me, &node, &n);
|
|
assert(lrs);
|
|
assert(n == 2);
|
|
assert(memcmp(lrs, a3, n) == 0);
|
|
free(lrs);
|
|
|
|
pmap = "(vector,(1,2,1),(1,2,1))";
|
|
me = 3;
|
|
lrs = orte_grpcomm_pmi2_parse_pmap(pmap, me, &node, &n);
|
|
assert(lrs);
|
|
assert(n == 2);
|
|
assert(memcmp(lrs, a4, n) == 0);
|
|
free(lrs);
|
|
|
|
pmap = "(vector,(0,4,4),(0,1,2),(1,3,1))";
|
|
me = 3;
|
|
lrs = orte_grpcomm_pmi2_parse_pmap(pmap, me, &node, &n);
|
|
assert(lrs);
|
|
assert(n == 6);
|
|
assert(memcmp(lrs, a5, n) == 0);
|
|
free(lrs);
|
|
|
|
pmap = "(vector,(0,4,4),(0,1,2),(1,3,1))";
|
|
me = 10;
|
|
lrs = orte_grpcomm_pmi2_parse_pmap(pmap, me, &node, &n);
|
|
assert(lrs);
|
|
assert(n == 5);
|
|
assert(memcmp(lrs, a6, n) == 0);
|
|
free(lrs);
|
|
return 0;
|
|
}
|
|
#endif
|