root/mpich2/trunk/src/pm/hydra/pm/pmiserv/pmi_handle.c @ 4887

Revision 4887, 14.3 KB (checked in by balaji, 5 months ago)

Warning stomp.

Line 
1/* -*- Mode: C; c-basic-offset:4 ; -*- */
2/*
3 *  (C) 2008 by Argonne National Laboratory.
4 *      See COPYRIGHT in top-level directory.
5 */
6
7#include "hydra.h"
8#include "pmi_handle.h"
9#include "pmi_handle_v1.h"
10#include "pmi_handle_v2.h"
11
12HYD_PMCD_pmi_pg_t *HYD_pg_list = NULL;
13struct HYD_PMCD_pmi_handle *HYD_PMCD_pmi_handle = { 0 };
14
15struct segment {
16    int start_pid;
17    int proc_count;
18    int node_id;
19    struct segment *next;
20};
21
22struct block {
23    int start_node_id;
24    int num_blocks;
25    int block_size;
26    struct block *next;
27};
28
29static HYD_Status allocate_kvs(HYD_PMCD_pmi_kvs_t ** kvs, int pgid)
30{
31    HYD_Status status = HYD_SUCCESS;
32
33    HYDU_FUNC_ENTER();
34
35    HYDU_MALLOC(*kvs, HYD_PMCD_pmi_kvs_t *, sizeof(HYD_PMCD_pmi_kvs_t), status);
36    HYDU_snprintf((*kvs)->kvs_name, MAXNAMELEN, "kvs_%d_%d", (int) getpid(), pgid);
37    (*kvs)->key_pair = NULL;
38
39  fn_exit:
40    HYDU_FUNC_EXIT();
41    return status;
42
43  fn_fail:
44    goto fn_exit;
45}
46
47
48static HYD_Status create_pg(HYD_PMCD_pmi_pg_t ** pg, int pgid)
49{
50    HYD_Status status = HYD_SUCCESS;
51
52    HYDU_FUNC_ENTER();
53
54    HYDU_MALLOC(*pg, HYD_PMCD_pmi_pg_t *, sizeof(HYD_PMCD_pmi_pg_t), status);
55    (*pg)->id = pgid;
56    (*pg)->num_procs = 0;
57    (*pg)->num_subgroups = 0;
58    (*pg)->conn_procs = NULL;
59    (*pg)->barrier_count = 0;
60    (*pg)->node_list = NULL;
61
62    status = allocate_kvs(&(*pg)->kvs, pgid);
63    HYDU_ERR_POP(status, "unable to allocate kvs space\n");
64
65    (*pg)->next = NULL;
66
67  fn_exit:
68    HYDU_FUNC_EXIT();
69    return status;
70
71  fn_fail:
72    goto fn_exit;
73}
74
75
76static HYD_Status free_pmi_process_list(HYD_PMCD_pmi_process_t * process_list)
77{
78    HYD_PMCD_pmi_process_t *process, *tmp;
79    HYD_Status status = HYD_SUCCESS;
80
81    HYDU_FUNC_ENTER();
82
83    process = process_list;
84    while (process) {
85        tmp = process->next;
86        HYDU_FREE(process);
87        process = tmp;
88    }
89
90    HYDU_FUNC_EXIT();
91    return status;
92}
93
94
95static HYD_Status free_pmi_kvs_list(HYD_PMCD_pmi_kvs_t * kvs_list)
96{
97    HYD_PMCD_pmi_kvs_pair_t *key_pair, *tmp;
98    HYD_Status status = HYD_SUCCESS;
99
100    HYDU_FUNC_ENTER();
101
102    key_pair = kvs_list->key_pair;
103    while (key_pair) {
104        tmp = key_pair->next;
105        HYDU_FREE(key_pair);
106        key_pair = tmp;
107    }
108    HYDU_FREE(kvs_list);
109
110    HYDU_FUNC_EXIT();
111    return status;
112}
113
114
115static HYD_Status free_pmi_node_list(HYD_PMCD_pmi_node_t * node_list)
116{
117    HYD_PMCD_pmi_node_t *node, *tmp;
118    HYD_Status status = HYD_SUCCESS;
119
120    HYDU_FUNC_ENTER();
121
122    node = node_list;
123    while (node) {
124        tmp = node->next;
125        free_pmi_process_list(node->process_list);
126        free_pmi_kvs_list(node->kvs);
127        HYDU_FREE(node);
128        node = tmp;
129    }
130
131    HYDU_FUNC_EXIT();
132    return status;
133}
134
135
136static struct HYD_PMCD_pmi_node *allocate_node(HYD_PMCD_pmi_pg_t * pg, int node_id)
137{
138    struct HYD_PMCD_pmi_node *node;
139    HYD_Status status = HYD_SUCCESS;
140
141    HYDU_FUNC_ENTER();
142
143    HYDU_MALLOC(node, HYD_PMCD_pmi_node_t *, sizeof(HYD_PMCD_pmi_node_t), status);
144    node->node_id = node_id;
145    node->pg = pg;
146    node->process_list = NULL;
147    node->kvs = NULL;
148    node->next = NULL;
149
150  fn_exit:
151    HYDU_FUNC_EXIT();
152    return node;
153
154  fn_fail:
155    node = NULL;
156    goto fn_exit;
157}
158
159
160HYD_Status HYD_PMCD_pmi_add_kvs(const char *key, char *val, HYD_PMCD_pmi_kvs_t * kvs,
161                                char **key_pair_str, int *ret)
162{
163    HYD_PMCD_pmi_kvs_pair_t *key_pair, *run;
164    HYD_Status status = HYD_SUCCESS;
165
166    HYDU_FUNC_ENTER();
167
168    HYDU_MALLOC(key_pair, HYD_PMCD_pmi_kvs_pair_t *, sizeof(HYD_PMCD_pmi_kvs_pair_t), status);
169    HYDU_snprintf(key_pair->key, MAXKEYLEN, "%s", key);
170    HYDU_snprintf(key_pair->val, MAXVALLEN, "%s", val);
171    key_pair->next = NULL;
172
173    key_pair_str = NULL;
174    *ret = 0;
175
176    if (kvs->key_pair == NULL) {
177        kvs->key_pair = key_pair;
178    }
179    else {
180        run = kvs->key_pair;
181        while (run->next) {
182            if (!strcmp(run->key, key_pair->key)) {
183                /* duplicate key found */
184                *key_pair_str = HYDU_strdup(key_pair->key);
185                *ret = -1;
186                break;
187            }
188            run = run->next;
189        }
190        run->next = key_pair;
191    }
192
193  fn_exit:
194    HYDU_FUNC_EXIT();
195    return status;
196
197  fn_fail:
198    goto fn_exit;
199}
200
201
202HYD_Status HYD_PMCD_pmi_id_to_rank(int id, int *rank)
203{
204    HYD_Status status = HYD_SUCCESS;
205
206    HYDU_FUNC_ENTER();
207
208    if (HYD_handle.ranks_per_proc == -1) {
209        /* If multiple procs per rank is not defined, use ID as the rank */
210        *rank = id;
211    }
212    else {
213        *rank = (id * HYD_handle.ranks_per_proc) + HYD_pg_list->conn_procs[id];
214        HYD_pg_list->conn_procs[id]++;
215    }
216
217    HYDU_FUNC_EXIT();
218    return status;
219}
220
221
222HYD_Status HYD_PMCD_pmi_process_mapping(HYD_PMCD_pmi_process_t * process,
223                                        enum HYD_PMCD_pmi_process_mapping_type type,
224                                        char **process_mapping_str)
225{
226    int i, j, k, node_id, *process_mapping;
227    char *tmp[HYD_NUM_TMP_STRINGS];
228    struct HYD_Partition *partition;
229    struct HYD_Partition_segment *segment;
230    struct segment *seglist_head, *seglist_tail = NULL, *seg;
231    struct block *blocklist_head, *blocklist_tail = NULL, *block;
232    int done;
233    HYD_Status status = HYD_SUCCESS;
234
235    HYDU_FUNC_ENTER();
236
237    seglist_head = NULL;
238    node_id = -1;
239    FORALL_PARTITIONS(partition, HYD_handle.partition_list) {
240        node_id++;
241        for (segment = partition->segment_list; segment; segment = segment->next) {
242            HYDU_MALLOC(seg, struct segment *, sizeof(struct segment), status);
243            seg->start_pid = segment->start_pid;
244            seg->proc_count = segment->proc_count;
245            seg->node_id = node_id;
246            seg->next = NULL;
247
248            if (seglist_head == NULL) {
249                seglist_head = seg;
250                seglist_tail = seg;
251            }
252            else {
253                seglist_tail->next = seg;
254                seglist_tail = seg;
255            }
256        }
257    }
258
259    /* Sort the segment list */
260    done = 1;
261    while (1) {
262        for (seg = seglist_head; seg; seg = seg->next) {
263            if (seg->next && (seg->start_pid > seg->next->start_pid)) {
264                seg->start_pid = seg->start_pid + seg->next->start_pid;
265                seg->next->start_pid = seg->start_pid - seg->next->start_pid;
266                seg->start_pid = seg->start_pid - seg->next->start_pid;
267
268                seg->proc_count = seg->proc_count + seg->next->proc_count;
269                seg->next->proc_count = seg->proc_count - seg->next->proc_count;
270                seg->proc_count = seg->proc_count - seg->next->proc_count;
271
272                seg->node_id = seg->node_id + seg->next->node_id;
273                seg->next->node_id = seg->node_id - seg->next->node_id;
274                seg->node_id = seg->node_id - seg->next->node_id;
275
276                done = 0;
277            }
278        }
279        if (done)
280            break;
281    }
282
283    /* Create a block list off the segment list */
284    blocklist_head = NULL;
285    for (seg = seglist_head; seg; seg = seg->next) {
286        if (blocklist_head == NULL) {
287            HYDU_MALLOC(blocklist_head, struct block *, sizeof(struct block), status);
288            blocklist_head->start_node_id = seg->node_id;
289            blocklist_head->block_size = seg->proc_count;
290            blocklist_head->num_blocks = 1;
291            blocklist_head->next = NULL;
292            blocklist_tail = blocklist_head;
293        }
294        else if ((blocklist_tail->start_node_id + blocklist_tail->num_blocks == seg->node_id)
295                 && (blocklist_tail->block_size == seg->proc_count)) {
296            blocklist_tail->num_blocks++;
297        }
298        else {
299            HYDU_MALLOC(blocklist_tail->next, struct block *, sizeof(struct block), status);
300            blocklist_tail = blocklist_tail->next;
301            blocklist_tail->start_node_id = seg->node_id;
302            blocklist_tail->block_size = seg->proc_count;
303            blocklist_tail->num_blocks = 1;
304            blocklist_tail->next = NULL;
305        }
306    }
307
308    if (type == HYD_PMCD_pmi_explicit) {
309        /* Explicit process mapping */
310        HYDU_MALLOC(process_mapping, int *, process->node->pg->num_procs * sizeof(int),
311                    status);
312
313        k = 0;
314        for (block = blocklist_head; block; block = block->next)
315            for (i = 0; i < block->num_blocks; i++)
316                for (j = 0; j < block->block_size; j++)
317                    process_mapping[k++] = block->start_node_id + i;
318
319        i = 0;
320        tmp[i++] = HYDU_strdup("explicit,");
321        for (j = 0; j < k; j++) {
322            tmp[i++] = HYDU_int_to_str(process_mapping[j]);
323            if (j < k - 1)
324                tmp[i++] = HYDU_strdup(",");
325            HYDU_STRLIST_CONSOLIDATE(tmp, i, status);
326        }
327        tmp[i++] = NULL;
328
329        status = HYDU_str_alloc_and_join(tmp, process_mapping_str);
330        HYDU_ERR_POP(status, "error while joining strings\n");
331
332        HYDU_free_strlist(tmp);
333    }
334    else if (type == HYD_PMCD_pmi_vector) {
335        i = 0;
336        tmp[i++] = HYDU_strdup("(");
337        tmp[i++] = HYDU_strdup("vector,");
338        for (block = blocklist_head; block; block = block->next) {
339            tmp[i++] = HYDU_strdup("(");
340            tmp[i++] = HYDU_int_to_str(block->start_node_id);
341            tmp[i++] = HYDU_strdup(",");
342            tmp[i++] = HYDU_int_to_str(block->num_blocks);
343            tmp[i++] = HYDU_strdup(",");
344            tmp[i++] = HYDU_int_to_str(block->block_size);
345            if (block->next)
346                tmp[i++] = HYDU_strdup(",");
347            tmp[i++] = HYDU_strdup(")");
348            HYDU_STRLIST_CONSOLIDATE(tmp, i, status);
349        }
350        tmp[i++] = HYDU_strdup(")");
351        tmp[i++] = NULL;
352
353        status = HYDU_str_alloc_and_join(tmp, process_mapping_str);
354        HYDU_ERR_POP(status, "error while joining strings\n");
355
356        HYDU_free_strlist(tmp);
357    }
358    else {
359        HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "unrecognized process mapping\n");
360    }
361
362  fn_exit:
363    HYDU_FUNC_EXIT();
364    return status;
365
366  fn_fail:
367    goto fn_exit;
368}
369
370
371static struct HYD_PMCD_pmi_node *find_node(HYD_PMCD_pmi_pg_t * pg, int rank)
372{
373    int found = 0, node_id, srank;
374    struct HYD_Partition *partition;
375    struct HYD_Partition_segment *segment;
376    struct HYD_PMCD_pmi_node *node, *tmp;
377    HYD_Status status = HYD_SUCCESS;
378
379    srank = rank % HYD_handle.global_core_count;
380
381    node_id = 0;
382    FORALL_PARTITIONS(partition, HYD_handle.partition_list) {
383        for (segment = partition->segment_list; segment; segment = segment->next) {
384            if ((srank >= segment->start_pid) &&
385                (srank < (segment->start_pid + segment->proc_count))) {
386                /* We found our rank */
387                found = 1;
388                break;
389            }
390        }
391        if (found)
392            break;
393        node_id++;
394    }
395
396    /* See if the node already exists */
397    for (node = pg->node_list; node; node = node->next)
398        if (node->node_id == node_id)
399            return node;
400
401    /* allocate node-level KVS space */
402    node = allocate_node(pg, node_id);
403    HYDU_ERR_CHKANDJUMP(status, !node, HYD_INTERNAL_ERROR, "unable to allocate PMI node\n");
404
405    status = allocate_kvs(&node->kvs, 0);
406    HYDU_ERR_POP(status, "unable to allocate kvs space\n");
407
408    if (pg->node_list == NULL)
409        pg->node_list = node;
410    else {
411        tmp = pg->node_list;
412        while (tmp->next)
413            tmp = tmp->next;
414        tmp->next = node;
415    }
416
417  fn_exit:
418    return node;
419
420  fn_fail:
421    goto fn_exit;
422}
423
424HYD_Status HYD_PMCD_pmi_add_process_to_pg(HYD_PMCD_pmi_pg_t * pg, int fd, int rank)
425{
426    HYD_PMCD_pmi_process_t *process, *tmp;
427    struct HYD_PMCD_pmi_node *node;
428    HYD_Status status = HYD_SUCCESS;
429
430    HYDU_FUNC_ENTER();
431
432    /* Find the node corresponding to the rank */
433    node = find_node(pg, rank);
434
435    /* Add process to the node */
436    HYDU_MALLOC(process, HYD_PMCD_pmi_process_t *, sizeof(HYD_PMCD_pmi_process_t), status);
437    process->fd = fd;
438    process->rank = rank;
439    process->epoch = 0;
440    process->node = node;
441    process->next = NULL;
442    if (node->process_list == NULL)
443        node->process_list = process;
444    else {
445        tmp = node->process_list;
446        while (tmp->next)
447            tmp = tmp->next;
448        tmp->next = process;
449    }
450
451  fn_exit:
452    HYDU_FUNC_EXIT();
453    return status;
454
455  fn_fail:
456    goto fn_exit;
457}
458
459
460HYD_PMCD_pmi_process_t *HYD_PMCD_pmi_find_process(int fd)
461{
462    HYD_PMCD_pmi_pg_t *pg;
463    HYD_PMCD_pmi_node_t *node;
464    HYD_PMCD_pmi_process_t *process = NULL;
465
466    for (pg = HYD_pg_list; pg; pg = pg->next) {
467        for (node = pg->node_list; node; node = node->next) {
468            for (process = node->process_list; process; process = process->next) {
469                if (process->fd == fd)
470                    return process;
471            }
472        }
473    }
474
475    return NULL;
476}
477
478
479HYD_Status HYD_PMCD_pmi_init(void)
480{
481    struct HYD_Partition *partition;
482    struct HYD_Partition_exec *exec;
483    int i;
484    HYD_Status status = HYD_SUCCESS;
485
486    HYDU_FUNC_ENTER();
487
488    status = create_pg(&HYD_pg_list, 0);
489    HYDU_ERR_POP(status, "unable to create pg\n");
490
491    /* Find the number of processes in the PG */
492    HYD_pg_list->num_subgroups = 0;
493    FORALL_ACTIVE_PARTITIONS(partition, HYD_handle.partition_list) {
494        for (exec = partition->exec_list; exec; exec = exec->next)
495            HYD_pg_list->num_subgroups += exec->proc_count;
496    }
497
498    if (HYD_handle.ranks_per_proc != -1)
499        HYD_pg_list->num_procs = HYD_pg_list->num_subgroups * HYD_handle.ranks_per_proc;
500    else
501        HYD_pg_list->num_procs = HYD_pg_list->num_subgroups;
502
503    /* Allocate and initialize the connected ranks */
504    HYDU_MALLOC(HYD_pg_list->conn_procs, int *, HYD_pg_list->num_subgroups * sizeof(int), status);
505    for (i = 0; i < HYD_pg_list->num_subgroups; i++)
506        HYD_pg_list->conn_procs[i] = 0;
507
508  fn_exit:
509    HYDU_FUNC_EXIT();
510    return status;
511
512  fn_fail:
513    goto fn_exit;
514}
515
516
517HYD_Status HYD_PMCD_pmi_finalize(void)
518{
519    HYD_PMCD_pmi_pg_t *pg, *tmp;
520    HYD_Status status = HYD_SUCCESS;
521
522    HYDU_FUNC_ENTER();
523
524    pg = HYD_pg_list;
525    while (pg) {
526        tmp = pg->next;
527
528        if (pg->conn_procs)
529            HYDU_FREE(pg->conn_procs);
530
531        status = free_pmi_node_list(pg->node_list);
532        HYDU_ERR_POP(status, "unable to free process list\n");
533
534        status = free_pmi_kvs_list(pg->kvs);
535        HYDU_ERR_POP(status, "unable to free kvs list\n");
536
537        HYDU_FREE(pg);
538        pg = tmp;
539    }
540
541  fn_exit:
542    HYDU_FUNC_EXIT();
543    return status;
544
545  fn_fail:
546    goto fn_exit;
547}
Note: See TracBrowser for help on using the browser.