Blame src/mpi/init/netloc_util.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2018 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpiimpl.h"
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef HAVE_NETLOC
Packit Service c5cf8c
#include "netloc_util.h"
Packit Service c5cf8c
#include "mpl.h"
Packit Service c5cf8c
#define MAX_DISTANCE 65535
Packit Service c5cf8c
Packit Service c5cf8c
typedef struct semicube_edge {
Packit Service c5cf8c
    netloc_node_t **src;
Packit Service c5cf8c
    netloc_node_t **dest;
Packit Service c5cf8c
} semicube_edge;
Packit Service c5cf8c
Packit Service c5cf8c
typedef struct tree {
Packit Service c5cf8c
    netloc_node_t ***vertices;
Packit Service c5cf8c
    int num_nodes;
Packit Service c5cf8c
    semicube_edge **edges;
Packit Service c5cf8c
    int num_edges;
Packit Service c5cf8c
} tree;
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME get_tree_attributes
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
static int get_tree_attributes(netloc_topology_t topology,
Packit Service c5cf8c
                               MPIR_Netloc_network_attributes * network_attr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, j, k, l;
Packit Service c5cf8c
    netloc_node_t **traversal_order = NULL;
Packit Service c5cf8c
    int traversal_start, traversal_end;
Packit Service c5cf8c
    int visited_count;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int max_depth = 0;
Packit Service c5cf8c
    netloc_dt_lookup_table_t *host_nodes = NULL, *nodes = NULL;
Packit Service c5cf8c
    struct netloc_dt_lookup_table_iterator *hti = NULL, *ti = NULL;
Packit Service c5cf8c
    int start_index = 0, end_index = 0;
Packit Service c5cf8c
    int count_at_level_mismatch = 0;
Packit Service c5cf8c
    int bandwidth_mismatch = 0;
Packit Service c5cf8c
    int out_degree_mismatch = 0;
Packit Service c5cf8c
    int prev_width = 0;
Packit Service c5cf8c
    int edges_go_across_levels = 0;
Packit Service c5cf8c
    int out_degree_mismatch_at_level = 0;
Packit Service c5cf8c
    MPIR_CHKPMEM_DECL(3);
Packit Service c5cf8c
Packit Service c5cf8c
    network_attr->type = MPIR_NETLOC_NETWORK_TYPE__INVALID;
Packit Service c5cf8c
Packit Service c5cf8c
    host_nodes =
Packit Service c5cf8c
        (netloc_dt_lookup_table_t *) MPL_malloc(sizeof(netloc_dt_lookup_table_t), MPL_MEM_OTHER);
Packit Service c5cf8c
    mpi_errno = netloc_get_all_host_nodes(topology, host_nodes);
Packit Service c5cf8c
Packit Service c5cf8c
    if (!mpi_errno) {
Packit Service c5cf8c
        int host_node_at_leaf_level;
Packit Service c5cf8c
Packit Service c5cf8c
        /* Traversal order never exceeds the total number of nodes */
Packit Service c5cf8c
        MPIR_CHKPMEM_MALLOC(traversal_order, netloc_node_t **,
Packit Service c5cf8c
                            sizeof(netloc_node_t *) * topology->num_nodes, mpi_errno,
Packit Service c5cf8c
                            "traversal_order", MPL_MEM_OTHER);
Packit Service c5cf8c
Packit Service c5cf8c
        hti = netloc_dt_lookup_table_iterator_t_construct(*host_nodes);
Packit Service c5cf8c
Packit Service c5cf8c
        host_node_at_leaf_level = 1;
Packit Service c5cf8c
        while (!netloc_lookup_table_iterator_at_end(hti)) {
Packit Service c5cf8c
            netloc_node_t *node = (netloc_node_t *) netloc_lookup_table_iterator_next_entry(hti);
Packit Service c5cf8c
            int num_edges;
Packit Service c5cf8c
            netloc_edge_t **edges;
Packit Service c5cf8c
Packit Service c5cf8c
            if (node == NULL) {
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            netloc_get_all_edges(topology, node, &num_edges, &edges);
Packit Service c5cf8c
            for (i = 0; i < num_edges; i++) {
Packit Service c5cf8c
                /* Check that outgoing edge connects to switches only */
Packit Service c5cf8c
                if (edges[i]->dest_node->node_type != NETLOC_NODE_TYPE_SWITCH) {
Packit Service c5cf8c
                    host_node_at_leaf_level = 0;
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            if (!host_node_at_leaf_level)
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            MPIR_Assert(end_index < topology->num_nodes);
Packit Service c5cf8c
            traversal_order[end_index++] = node;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        if (!host_node_at_leaf_level) {
Packit Service c5cf8c
            network_attr->type = MPIR_NETLOC_NETWORK_TYPE__INVALID;
Packit Service c5cf8c
            goto fn_exit;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        nodes =
Packit Service c5cf8c
            (netloc_dt_lookup_table_t *) MPL_malloc(sizeof(netloc_dt_lookup_table_t),
Packit Service c5cf8c
                                                    MPL_MEM_OTHER);
Packit Service c5cf8c
        mpi_errno = netloc_get_all_nodes(topology, nodes);
Packit Service c5cf8c
Packit Service c5cf8c
        if (!mpi_errno) {
Packit Service c5cf8c
            /* Traverse the graph in topological order */
Packit Service c5cf8c
            while (start_index < end_index) {
Packit Service c5cf8c
                netloc_node_t *node = traversal_order[start_index++];
Packit Service c5cf8c
                /* Add all neighbors to traversal list */
Packit Service c5cf8c
                netloc_edge_t **edges;
Packit Service c5cf8c
                int num_edges;
Packit Service c5cf8c
                netloc_get_all_edges(topology, node, &num_edges, &edges);
Packit Service c5cf8c
                for (j = 0; j < num_edges; j++) {
Packit Service c5cf8c
                    netloc_node_t *neighbor = edges[j]->dest_node;
Packit Service c5cf8c
                    int parents_visited = 1;
Packit Service c5cf8c
Packit Service c5cf8c
                    ti = netloc_dt_lookup_table_iterator_t_construct(*nodes);
Packit Service c5cf8c
                    while (!netloc_lookup_table_iterator_at_end(ti)) {
Packit Service c5cf8c
                        int num_parents_covered = 0, num_parents = 0;
Packit Service c5cf8c
                        netloc_node_t *parent_node =
Packit Service c5cf8c
                            (netloc_node_t *) netloc_lookup_table_iterator_next_entry(ti);
Packit Service c5cf8c
                        netloc_edge_t **neighbor_edges;
Packit Service c5cf8c
                        int neighbor_num_edges;
Packit Service c5cf8c
Packit Service c5cf8c
                        if (parent_node == NULL) {
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        netloc_get_all_edges(topology, parent_node, &neighbor_num_edges,
Packit Service c5cf8c
                                             &neighbor_edges);
Packit Service c5cf8c
                        for (k = 0; k < neighbor_num_edges; k++) {
Packit Service c5cf8c
                            if (neighbor_edges[k]->dest_node != neighbor) {
Packit Service c5cf8c
                                continue;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            num_parents++;
Packit Service c5cf8c
                            for (l = 0; l < start_index; l++) {
Packit Service c5cf8c
                                if (traversal_order[l] == parent_node) {
Packit Service c5cf8c
                                    num_parents_covered++;
Packit Service c5cf8c
                                    break;
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        if (num_parents != num_parents_covered) {
Packit Service c5cf8c
                            parents_visited = 0;
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    if (parents_visited) {
Packit Service c5cf8c
                        int added_previously = 0;
Packit Service c5cf8c
                        for (k = 0; k < end_index; k++) {
Packit Service c5cf8c
                            if (traversal_order[k] == neighbor) {
Packit Service c5cf8c
                                added_previously = 1;
Packit Service c5cf8c
                                break;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        if (!added_previously) {
Packit Service c5cf8c
                            MPIR_Assert(end_index < topology->num_nodes);
Packit Service c5cf8c
                            traversal_order[end_index++] = neighbor;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (end_index < topology->num_nodes) {
Packit Service c5cf8c
                /* Cycle in the graph, not a tree or close network */
Packit Service c5cf8c
                network_attr->type = MPIR_NETLOC_NETWORK_TYPE__INVALID;
Packit Service c5cf8c
                goto fn_exit;
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            /* Assign depths to nodes of the graph bottom up, in breadth first order */
Packit Service c5cf8c
            /* Indexed by node id, visited_node_list[i] > -1 indicates that the
Packit Service c5cf8c
             * node i has been visited */
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_CHKPMEM_MALLOC(network_attr->u.tree.node_levels, int *,
Packit Service c5cf8c
                                sizeof(int) * topology->num_nodes, mpi_errno,
Packit Service c5cf8c
                                "network_attr->u.tree.node_levels", MPL_MEM_OTHER);
Packit Service c5cf8c
Packit Service c5cf8c
            for (i = 0; i < topology->num_nodes; i++) {
Packit Service c5cf8c
                network_attr->u.tree.node_levels[i] = -1;
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            traversal_end = 0;
Packit Service c5cf8c
            traversal_start = 0;
Packit Service c5cf8c
            visited_count = 0;
Packit Service c5cf8c
            /* Initialize host depths to zero */
Packit Service c5cf8c
            for (i = 0; i < topology->num_nodes; i++) {
Packit Service c5cf8c
                if (topology->nodes[i]->node_type == NETLOC_NODE_TYPE_HOST) {
Packit Service c5cf8c
                    int num_edges;
Packit Service c5cf8c
                    netloc_edge_t **edges;
Packit Service c5cf8c
Packit Service c5cf8c
                    /* Mark the host node as visited */
Packit Service c5cf8c
                    network_attr->u.tree.node_levels[topology->nodes[i]->__uid__] = 0;
Packit Service c5cf8c
                    visited_count++;
Packit Service c5cf8c
Packit Service c5cf8c
                    /* Copy all parents without duplicates to the traversal list */
Packit Service c5cf8c
                    netloc_get_all_edges(topology, topology->nodes[i], &num_edges, &edges);
Packit Service c5cf8c
                    for (j = 0; j < num_edges; j++) {
Packit Service c5cf8c
                        if (network_attr->u.tree.node_levels[edges[j]->dest_node->__uid__] < 0) {
Packit Service c5cf8c
                            traversal_order[traversal_end++] = edges[j]->dest_node;
Packit Service c5cf8c
                            /* Switch levels start from 1 */
Packit Service c5cf8c
                            network_attr->u.tree.node_levels[edges[j]->dest_node->__uid__] = 1;
Packit Service c5cf8c
                            max_depth = 1;
Packit Service c5cf8c
                            visited_count++;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            while (visited_count < topology->num_nodes) {
Packit Service c5cf8c
                netloc_node_t *traversed_node = traversal_order[traversal_start++];
Packit Service c5cf8c
                int num_edges;
Packit Service c5cf8c
                netloc_edge_t **edges;
Packit Service c5cf8c
                int depth = network_attr->u.tree.node_levels[traversed_node->__uid__];
Packit Service c5cf8c
Packit Service c5cf8c
                /* Find all nodes not visited with an edge from the current node */
Packit Service c5cf8c
                netloc_get_all_edges(topology, traversed_node, &num_edges, &edges);
Packit Service c5cf8c
                for (j = 0; j < num_edges; j++) {
Packit Service c5cf8c
                    if (edges[j]->dest_node == traversed_node) {
Packit Service c5cf8c
                        continue;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    if (network_attr->u.tree.node_levels[edges[j]->dest_node->__uid__] < 0 ||
Packit Service c5cf8c
                        (depth + 1) <
Packit Service c5cf8c
                        network_attr->u.tree.node_levels[edges[j]->dest_node->__uid__]) {
Packit Service c5cf8c
                        traversal_order[traversal_end++] = edges[j]->dest_node;
Packit Service c5cf8c
                        network_attr->u.tree.node_levels[edges[j]->dest_node->__uid__] = depth + 1;
Packit Service c5cf8c
                        if (max_depth < depth + 1) {
Packit Service c5cf8c
                            max_depth = depth + 1;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        visited_count++;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            /* End of depth assignment */
Packit Service c5cf8c
Packit Service c5cf8c
            /* Count the number of nodes and bandwidth at each level */
Packit Service c5cf8c
            for (i = 0; i < max_depth; i++) {
Packit Service c5cf8c
                int width_at_level = 0;
Packit Service c5cf8c
                int num_nodes_at_level = 0;
Packit Service c5cf8c
                int out_degree_at_level = -1;
Packit Service c5cf8c
                for (j = 0; j < topology->num_nodes; j++) {
Packit Service c5cf8c
                    if (network_attr->u.tree.node_levels[topology->nodes[j]->__uid__] == i) {
Packit Service c5cf8c
                        int num_edges;
Packit Service c5cf8c
                        netloc_edge_t **edges;
Packit Service c5cf8c
                        num_nodes_at_level++;
Packit Service c5cf8c
                        int edge_width = 0;
Packit Service c5cf8c
                        int node_out_degree = 0;
Packit Service c5cf8c
                        netloc_get_all_edges(topology, topology->nodes[j], &num_edges, &edges);
Packit Service c5cf8c
                        for (k = 0; k < num_edges; k++) {
Packit Service c5cf8c
                            if (edges[k]->src_node == topology->nodes[j]) {
Packit Service c5cf8c
                                edge_width += edges[k]->bandwidth;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            if (edges[k]->src_node == topology->nodes[j] &&
Packit Service c5cf8c
                                network_attr->u.tree.node_levels[edges[k]->dest_node->__uid__] ==
Packit Service c5cf8c
                                i - 1) {
Packit Service c5cf8c
                                node_out_degree++;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            if (edges[k]->src_node == topology->nodes[j] &&
Packit Service c5cf8c
                                (network_attr->u.tree.node_levels[edges[k]->dest_node->__uid__] !=
Packit Service c5cf8c
                                 i + 1) &&
Packit Service c5cf8c
                                (network_attr->u.tree.node_levels[edges[k]->dest_node->__uid__] !=
Packit Service c5cf8c
                                 i - 1)) {
Packit Service c5cf8c
                                edges_go_across_levels = 1;
Packit Service c5cf8c
                                break;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        if (i > 0) {
Packit Service c5cf8c
                            if (out_degree_at_level == -1) {
Packit Service c5cf8c
                                out_degree_at_level = node_out_degree;
Packit Service c5cf8c
                            } else if (out_degree_at_level != node_out_degree) {
Packit Service c5cf8c
                                out_degree_mismatch_at_level = i;
Packit Service c5cf8c
                                break;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        if (edges_go_across_levels) {
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        if ((i == max_depth && node_out_degree != 0) ||
Packit Service c5cf8c
                            (i > 0 && node_out_degree != 2)) {
Packit Service c5cf8c
                            out_degree_mismatch = 1;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        if (width_at_level == 0) {
Packit Service c5cf8c
                            width_at_level = edge_width;
Packit Service c5cf8c
                        } else if (width_at_level != edge_width) {
Packit Service c5cf8c
                            bandwidth_mismatch = 1;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
                if (out_degree_mismatch_at_level || edges_go_across_levels) {
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                if (num_nodes_at_level != ((unsigned) 1 << (max_depth - i))) {
Packit Service c5cf8c
                    count_at_level_mismatch = 1;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                if (i > 0 && width_at_level != 2 * prev_width) {
Packit Service c5cf8c
                    bandwidth_mismatch = 1;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (!out_degree_mismatch_at_level && !edges_go_across_levels) {
Packit Service c5cf8c
                network_attr->type = MPIR_NETLOC_NETWORK_TYPE__CLOS_NETWORK;
Packit Service c5cf8c
                if (!count_at_level_mismatch && !bandwidth_mismatch && !out_degree_mismatch) {
Packit Service c5cf8c
                    network_attr->type = MPIR_NETLOC_NETWORK_TYPE__FAT_TREE;
Packit Service c5cf8c
                }
Packit Service c5cf8c
Packit Service c5cf8c
                errno = MPIR_Netloc_get_network_end_point(MPIR_Process.network_attr,
Packit Service c5cf8c
                                                          MPIR_Process.netloc_topology,
Packit Service c5cf8c
                                                          MPIR_Process.hwloc_topology,
Packit Service c5cf8c
                                                          &MPIR_Process.
Packit Service c5cf8c
                                                          network_attr.network_endpoint);
Packit Service c5cf8c
                if (errno != MPI_SUCCESS) {
Packit Service c5cf8c
                    network_attr->type = MPIR_NETLOC_NETWORK_TYPE__INVALID;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            } else {
Packit Service c5cf8c
                network_attr->type = MPIR_NETLOC_NETWORK_TYPE__INVALID;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_CHKPMEM_COMMIT();
Packit Service c5cf8c
    MPIR_CHKPMEM_REAP();
Packit Service c5cf8c
    if (host_nodes != NULL) {
Packit Service c5cf8c
        MPL_free(host_nodes);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (nodes != NULL) {
Packit Service c5cf8c
        MPL_free(nodes);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static unsigned int get_hamming_distance(const unsigned long long src_label,
Packit Service c5cf8c
                                         const unsigned long long dest_label)
Packit Service c5cf8c
{
Packit Service c5cf8c
    unsigned int distance = 0;
Packit Service c5cf8c
    unsigned long long hamming_distance;
Packit Service c5cf8c
Packit Service c5cf8c
    hamming_distance = (unsigned long long) src_label ^ dest_label;
Packit Service c5cf8c
    while (hamming_distance) {
Packit Service c5cf8c
        if (hamming_distance & 1) {
Packit Service c5cf8c
            distance++;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        hamming_distance = hamming_distance >> 1;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return distance;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static int get_distance(netloc_node_t ** exposed_vertex, netloc_node_t ** root, tree * subtree)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int distance = 0;
Packit Service c5cf8c
    int i;
Packit Service c5cf8c
    if (exposed_vertex == root) {
Packit Service c5cf8c
        return distance;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    for (i = 0; i < subtree->num_edges; i++) {
Packit Service c5cf8c
        int temp_distance = 0;
Packit Service c5cf8c
        if (subtree->edges[0]->dest == exposed_vertex) {
Packit Service c5cf8c
            temp_distance = get_distance(subtree->edges[0]->src, root, subtree);
Packit Service c5cf8c
            if (temp_distance + 1 > distance) {
Packit Service c5cf8c
                distance = temp_distance + 1;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return distance;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static void get_path(netloc_node_t ** src, netloc_node_t ** dest, tree ** forest, int tree_count,
Packit Service c5cf8c
                     semicube_edge *** path, int *path_length)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, j;
Packit Service c5cf8c
    for (i = 0; i < tree_count; i++) {
Packit Service c5cf8c
        tree *subtree = forest[i];
Packit Service c5cf8c
        int subtree_edge_count = subtree->num_edges;
Packit Service c5cf8c
        for (j = 0; j < subtree_edge_count; j++) {
Packit Service c5cf8c
            int path_size = -1;
Packit Service c5cf8c
            if (subtree->edges[j]->dest == dest) {
Packit Service c5cf8c
                semicube_edge edge;
Packit Service c5cf8c
                edge.src = src;
Packit Service c5cf8c
                edge.dest = dest;
Packit Service c5cf8c
                *path[*path_length] = &edg;;
Packit Service c5cf8c
                *path_length = *path_length + 1;
Packit Service c5cf8c
            } else if (subtree->edges[j]->src == src) {
Packit Service c5cf8c
                int destination_reached = 0;
Packit Service c5cf8c
                int current_path_length = *path_length;
Packit Service c5cf8c
                get_path(subtree->edges[j]->dest, dest, forest, tree_count, path, path_length);
Packit Service c5cf8c
                if (path_length >= 0) {
Packit Service c5cf8c
                    semicube_edge *edge = (*path)[path_size - 1];
Packit Service c5cf8c
                    if (edge->dest == dest) {
Packit Service c5cf8c
                        destination_reached = 1;
Packit Service c5cf8c
                        break;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
                if (!destination_reached) {
Packit Service c5cf8c
                    *path_length = current_path_length;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static void get_root_of_tree(tree * subtree, netloc_node_t *** root)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, j;
Packit Service c5cf8c
    for (i = 0; i < subtree->num_nodes; i++) {
Packit Service c5cf8c
        netloc_node_t **vertex = subtree->vertices[i];
Packit Service c5cf8c
        int rootnode = 1;
Packit Service c5cf8c
        for (j = 0; j < subtree->num_edges; j++) {
Packit Service c5cf8c
            if (subtree->edges[j]->dest == vertex) {
Packit Service c5cf8c
                rootnode = 0;
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (rootnode) {
Packit Service c5cf8c
            *root = vertex;
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static void get_blossom(netloc_node_t *** nodes, int num_nodes,
Packit Service c5cf8c
                        semicube_edge ** edges, int num_edges, netloc_node_t *** unmarked_vertices,
Packit Service c5cf8c
                        int num_unmarked, netloc_node_t **** blossom_nodes, int *num_blossom_nodes,
Packit Service c5cf8c
                        int *stem_index)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, j;
Packit Service c5cf8c
    netloc_node_t **exposed_vertex;
Packit Service c5cf8c
    for (j = 0; j < num_unmarked; j++) {
Packit Service c5cf8c
        if (nodes[i] == unmarked_vertices[j]) {
Packit Service c5cf8c
            netloc_node_t ***traversed_nodes =
Packit Service c5cf8c
                (netloc_node_t ***) MPL_calloc(num_nodes, sizeof(netloc_node_t **), MPL_MEM_OTHER);
Packit Service c5cf8c
            int cycle_index = 0;
Packit Service c5cf8c
            int odd_cycle_found = 0;
Packit Service c5cf8c
            exposed_vertex = nodes[i];
Packit Service c5cf8c
            traversed_nodes[cycle_index++] = exposed_vertex;
Packit Service c5cf8c
            /* Find an odd cycle starting from the exposed vertex */
Packit Service c5cf8c
            while (1) {
Packit Service c5cf8c
                /* Find an edge adjacent to the current node */
Packit Service c5cf8c
                for (i = 0; i < num_edges; i++) {
Packit Service c5cf8c
                    if (edges[i]->src == exposed_vertex) {
Packit Service c5cf8c
                        traversed_nodes[cycle_index++] = edges[i]->dest;
Packit Service c5cf8c
                        exposed_vertex = edges[i]->dest;
Packit Service c5cf8c
                        break;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
                for (i = 0; i < cycle_index - 1; i++) {
Packit Service c5cf8c
                    if (traversed_nodes[i] == exposed_vertex && (cycle_index - 1 - i) & 1) {
Packit Service c5cf8c
                        odd_cycle_found = 1;
Packit Service c5cf8c
                        *num_blossom_nodes = cycle_index;
Packit Service c5cf8c
                        *blossom_nodes = traversed_nodes;
Packit Service c5cf8c
                        *stem_index = i;
Packit Service c5cf8c
                        break;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
                if (odd_cycle_found) {
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (odd_cycle_found) {
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static void find_augmenting_path(netloc_topology_t topology, netloc_node_t *** nodes, int num_nodes,
Packit Service c5cf8c
                                 semicube_edge ** edges, int num_edges,
Packit Service c5cf8c
                                 semicube_edge *** augmenting_path, int *augmenting_path_length,
Packit Service c5cf8c
                                 semicube_edge ** maximum_matching, int num_matching_edges)
Packit Service c5cf8c
{
Packit Service c5cf8c
    semicube_edge **current_augmenting_path = NULL;
Packit Service c5cf8c
    int path_length;
Packit Service c5cf8c
    int i, j, k, l;
Packit Service c5cf8c
    int unmarked_vertex_insert, unmarked_edge_insert = 0;
Packit Service c5cf8c
    netloc_node_t ***unmarked_vertices = NULL;
Packit Service c5cf8c
    semicube_edge **unmarked_edges = NULL;
Packit Service c5cf8c
    tree **forest;
Packit Service c5cf8c
    int forest_insert_index;
Packit Service c5cf8c
    /* Unmark all vertices and edges in the semicube graph, mark all edges of the matching */
Packit Service c5cf8c
    unmarked_vertex_insert = 0;
Packit Service c5cf8c
    unmarked_vertices =
Packit Service c5cf8c
        (netloc_node_t ***) MPL_calloc(num_nodes, sizeof(netloc_node_t **), MPL_MEM_OTHER);
Packit Service c5cf8c
    for (i = 0; i < num_nodes; i++) {
Packit Service c5cf8c
        netloc_node_t **semicube_vertex = nodes[i];
Packit Service c5cf8c
        int exposed_vertex = 1;
Packit Service c5cf8c
        for (j = 0; j < num_matching_edges; j++) {
Packit Service c5cf8c
            semicube_edge *edge = maximum_matching[j];
Packit Service c5cf8c
            if (edge->src == semicube_vertex || edge->dest == semicube_vertex) {
Packit Service c5cf8c
                exposed_vertex = 0;
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (exposed_vertex) {
Packit Service c5cf8c
            unmarked_vertices[unmarked_vertex_insert++] = semicube_vertex;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    unmarked_edge_insert = 0;
Packit Service c5cf8c
    unmarked_edges =
Packit Service c5cf8c
        (semicube_edge **) MPL_calloc(num_edges, sizeof(semicube_edge *), MPL_MEM_OTHER);
Packit Service c5cf8c
    /* Unmark all vertices and edges in the semicube graph, mark all edges of the matching */
Packit Service c5cf8c
    for (i = 0; i < num_edges; i++) {
Packit Service c5cf8c
        int marked_edge = 0;
Packit Service c5cf8c
        semicube_edge *edge = edges[i];
Packit Service c5cf8c
        for (j = 0; j < num_matching_edges; j++) {
Packit Service c5cf8c
            semicube_edge *local_edge = maximum_matching[j];
Packit Service c5cf8c
            if (local_edge->src == edge->src && local_edge->dest == edge->dest) {
Packit Service c5cf8c
                marked_edge = 1;
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (!marked_edge) {
Packit Service c5cf8c
            unmarked_edges[unmarked_edge_insert++] = edge;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    forest = (tree **) MPL_calloc(unmarked_vertex_insert, sizeof(tree *), MPL_MEM_OTHER);
Packit Service c5cf8c
    forest_insert_index = 0;
Packit Service c5cf8c
    /* Create a forest with each exposed vertex as a singleton set */
Packit Service c5cf8c
    for (i = 0; i < unmarked_vertex_insert; i++) {
Packit Service c5cf8c
        tree *singleton_tree = (tree *) MPL_malloc(sizeof(tree), MPL_MEM_OTHER);
Packit Service c5cf8c
        singleton_tree->vertices =
Packit Service c5cf8c
            (netloc_node_t ***) MPL_malloc(sizeof(netloc_node_t **), MPL_MEM_OTHER);
Packit Service c5cf8c
        singleton_tree->edges =
Packit Service c5cf8c
            (semicube_edge **) MPL_malloc(sizeof(semicube_edge *), MPL_MEM_OTHER);
Packit Service c5cf8c
        singleton_tree->vertices[0] = unmarked_vertices[i];
Packit Service c5cf8c
        singleton_tree->num_nodes = 1;
Packit Service c5cf8c
        singleton_tree->num_edges = 0;
Packit Service c5cf8c
        forest[forest_insert_index++] = singleton_tree;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    while (1) {
Packit Service c5cf8c
        int exposed_vertex = 0;
Packit Service c5cf8c
        netloc_node_t **vertex;
Packit Service c5cf8c
        netloc_node_t **root;
Packit Service c5cf8c
        int distance_from_root;
Packit Service c5cf8c
        int unmarked_vertex_index = -1;
Packit Service c5cf8c
        int unmarked_edge_index = -1;
Packit Service c5cf8c
        tree *subtree;
Packit Service c5cf8c
Packit Service c5cf8c
        exposed_vertex = 0;
Packit Service c5cf8c
        for (i = 0; i < forest_insert_index; i++) {
Packit Service c5cf8c
            subtree = forest[i];
Packit Service c5cf8c
            /* Check if the marked vertex is at an even distance from the
Packit Service c5cf8c
             * root node in its tree */
Packit Service c5cf8c
            for (j = 0; j < subtree->num_nodes; j++) {
Packit Service c5cf8c
                vertex = subtree->vertices[j];
Packit Service c5cf8c
                for (l = 0; l < unmarked_vertex_insert; l++) {
Packit Service c5cf8c
                    if (unmarked_vertices[l] == vertex) {
Packit Service c5cf8c
                        exposed_vertex = 1;
Packit Service c5cf8c
                        unmarked_vertex_index = l;
Packit Service c5cf8c
                        break;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
                if (exposed_vertex) {
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (exposed_vertex) {
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        if (!exposed_vertex) {
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        get_root_of_tree(subtree, &root);
Packit Service c5cf8c
        distance_from_root = get_distance(vertex, root, subtree);
Packit Service c5cf8c
        if (!(distance_from_root & 1)) {
Packit Service c5cf8c
            /* Find an unmarked edge from exposed_vertex */
Packit Service c5cf8c
            int unmarked_edge = 0;
Packit Service c5cf8c
            semicube_edge *edge;
Packit Service c5cf8c
            netloc_node_t **dest;
Packit Service c5cf8c
            for (j = 0; j < unmarked_edge_insert; j++) {
Packit Service c5cf8c
                if (unmarked_edges[j]->src == vertex || unmarked_edges[j]->dest == vertex) {
Packit Service c5cf8c
                    unmarked_edge = 1;
Packit Service c5cf8c
                    unmarked_edge_index = j;
Packit Service c5cf8c
                    edge = unmarked_edges[j];
Packit Service c5cf8c
                    dest = unmarked_edges[j]->dest;
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (unmarked_edge) {
Packit Service c5cf8c
                /* Check if the destination is not in the forest */
Packit Service c5cf8c
                int dest_in_forest = 0;
Packit Service c5cf8c
                tree *dest_subtree;
Packit Service c5cf8c
                netloc_node_t **dest_root;
Packit Service c5cf8c
                for (j = 0; j < forest_insert_index; j++) {
Packit Service c5cf8c
                    tree *tempsubtree = forest[j];
Packit Service c5cf8c
                    for (k = 0; k < tempsubtree->num_nodes; k++) {
Packit Service c5cf8c
                        if (tempsubtree->vertices[k] == dest) {
Packit Service c5cf8c
                            dest_in_forest = 1;
Packit Service c5cf8c
                            dest_subtree = tempsubtree;
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    if (dest_in_forest) {
Packit Service c5cf8c
                        break;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
                get_root_of_tree(dest_subtree, &dest_root);
Packit Service c5cf8c
Packit Service c5cf8c
                if (!dest_in_forest) {
Packit Service c5cf8c
                    int vertex_insert_position;
Packit Service c5cf8c
                    int edge_insert_position = 0;
Packit Service c5cf8c
                    /* The destination node is in matching graph */
Packit Service c5cf8c
                    semicube_edge *matching_edge = NULL;
Packit Service c5cf8c
                    for (j = 0; j < num_matching_edges; j++) {
Packit Service c5cf8c
                        semicube_edge *temp_matching_edge = maximum_matching[j];
Packit Service c5cf8c
                        if (temp_matching_edge->src == dest || temp_matching_edge->dest == dest) {
Packit Service c5cf8c
                            matching_edge = temp_matching_edge;
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    MPIR_Assert(matching_edge != NULL);
Packit Service c5cf8c
                    /* Add edge to subtree */
Packit Service c5cf8c
                    vertex_insert_position = subtree->num_nodes + 1;
Packit Service c5cf8c
                    subtree->vertices =
Packit Service c5cf8c
                        (netloc_node_t ***) MPL_realloc(subtree->vertices,
Packit Service c5cf8c
                                                        (vertex_insert_position + 1) *
Packit Service c5cf8c
                                                        sizeof(netloc_node_t **), MPL_MEM_OTHER);
Packit Service c5cf8c
                    subtree->vertices[vertex_insert_position] = dest;
Packit Service c5cf8c
                    subtree->num_nodes++;
Packit Service c5cf8c
Packit Service c5cf8c
                    subtree->edges =
Packit Service c5cf8c
                        (semicube_edge **) MPL_realloc(subtree->edges,
Packit Service c5cf8c
                                                       (edge_insert_position + 3) *
Packit Service c5cf8c
                                                       sizeof(subtree->edges[0]), MPL_MEM_OTHER);
Packit Service c5cf8c
Packit Service c5cf8c
                    for (j = 0; j < unmarked_edge_index; j++) {
Packit Service c5cf8c
                        semicube_edge *temp_matching_edge = unmarked_edges[j];
Packit Service c5cf8c
                        if (temp_matching_edge->src == vertex && temp_matching_edge->dest == dest) {
Packit Service c5cf8c
                            subtree->edges[edge_insert_position++] = temp_matching_edge;
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    subtree->edges[edge_insert_position++] = matching_edge;
Packit Service c5cf8c
                    subtree->num_edges += 2;
Packit Service c5cf8c
                } else if (get_distance(dest, dest_root, dest_subtree) & 1) {
Packit Service c5cf8c
                    /* Do nothing */
Packit Service c5cf8c
                } else {
Packit Service c5cf8c
                    if (root != dest_root) {
Packit Service c5cf8c
                        /* Found an augmenting path */
Packit Service c5cf8c
                        semicube_edge **first_path, **second_path;
Packit Service c5cf8c
                        int insert_index = 0;
Packit Service c5cf8c
                        int first_length = 0, second_length = 0;
Packit Service c5cf8c
                        get_path(root, vertex, forest, forest_insert_index, &first_path,
Packit Service c5cf8c
                                 &first_length);
Packit Service c5cf8c
                        get_path(dest_root, dest, forest, forest_insert_index, &second_path,
Packit Service c5cf8c
                                 &second_length);
Packit Service c5cf8c
                        current_augmenting_path =
Packit Service c5cf8c
                            MPL_calloc(current_augmenting_path, (first_length + second_length + 1) *
Packit Service c5cf8c
                                       sizeof(semicube_edge *), MPL_MEM_OTHER);
Packit Service c5cf8c
                        for (j = 0; j < first_length; j++) {
Packit Service c5cf8c
                            current_augmenting_path[insert_index++] = first_path[j];
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        current_augmenting_path[insert_index++] = edge;
Packit Service c5cf8c
                        for (j = 0; j < second_length; j++) {
Packit Service c5cf8c
                            current_augmenting_path[insert_index++] = second_path[j];
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        path_length = first_length + second_length + 1;
Packit Service c5cf8c
                        goto fn_exit;
Packit Service c5cf8c
                    } else {
Packit Service c5cf8c
                        netloc_node_t ***blossom_edges;
Packit Service c5cf8c
                        int num_blossom_nodes, stem_index, m, n;
Packit Service c5cf8c
                        get_blossom(nodes, num_nodes, edges, num_edges, unmarked_vertices,
Packit Service c5cf8c
                                    unmarked_vertex_insert, &blossom_edges,
Packit Service c5cf8c
                                    &num_blossom_nodes, &stem_index);
Packit Service c5cf8c
                        /* Contract a blossom in G and look for the path in the contracted graph */
Packit Service c5cf8c
                        for (j = stem_index + 1; j < num_blossom_nodes; j++) {
Packit Service c5cf8c
                            netloc_node_t **blossom_node = blossom_edges[j];
Packit Service c5cf8c
                            for (k = 0; k < num_nodes; k++) {
Packit Service c5cf8c
                                if (nodes[k] == blossom_node) {
Packit Service c5cf8c
                                    for (l = k; l < num_nodes - 1; l++) {
Packit Service c5cf8c
                                        nodes[l] = nodes[l + 1];
Packit Service c5cf8c
                                    }
Packit Service c5cf8c
                                    num_nodes--;
Packit Service c5cf8c
                                    k--;
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            if (j < num_blossom_nodes - 1) {
Packit Service c5cf8c
                                netloc_node_t **adj_blossom_node = blossom_edges[j];
Packit Service c5cf8c
                                for (k = 0; k < num_edges; k++) {
Packit Service c5cf8c
                                    if (edges[k]->src == blossom_node &&
Packit Service c5cf8c
                                        edges[k]->dest == adj_blossom_node) {
Packit Service c5cf8c
                                        for (l = k; l < num_edges - 1; l++) {
Packit Service c5cf8c
                                            edges[l] = edges[l + 1];
Packit Service c5cf8c
                                        }
Packit Service c5cf8c
                                        num_edges--;
Packit Service c5cf8c
                                        k--;
Packit Service c5cf8c
                                    }
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        find_augmenting_path(topology, nodes, num_nodes, edges, num_edges,
Packit Service c5cf8c
                                             &current_augmenting_path, &path_length,
Packit Service c5cf8c
                                             maximum_matching, num_matching_edges);
Packit Service c5cf8c
                        /* Find the node that connects to the stem */
Packit Service c5cf8c
                        for (j = 0; j < path_length; j++) {
Packit Service c5cf8c
                            if (current_augmenting_path[j]->src == blossom_edges[stem_index]) {
Packit Service c5cf8c
                                break;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        for (k = stem_index + 1; k < num_blossom_nodes; k++) {
Packit Service c5cf8c
                            if (current_augmenting_path[j]->dest == blossom_edges[k]) {
Packit Service c5cf8c
                                break;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        current_augmenting_path =
Packit Service c5cf8c
                            (semicube_edge **) MPL_realloc(current_augmenting_path,
Packit Service c5cf8c
                                                           sizeof(semicube_edge *) * (k -
Packit Service c5cf8c
                                                                                      stem_index
Packit Service c5cf8c
                                                                                      - 1),
Packit Service c5cf8c
                                                           MPL_MEM_OTHER);
Packit Service c5cf8c
Packit Service c5cf8c
                        current_augmenting_path[j]->dest =
Packit Service c5cf8c
                            current_augmenting_path[j + 1]->src = blossom_edges[stem_index + 1];
Packit Service c5cf8c
                        /* Shift edges to make room to lift blossom edges */
Packit Service c5cf8c
                        for (l = j + 1; l < path_length; l++) {
Packit Service c5cf8c
                            current_augmenting_path[l] =
Packit Service c5cf8c
                                current_augmenting_path[l + k - stem_index - 1];
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        for (l = j; l < (j + k - stem_index - 2); l++) {
Packit Service c5cf8c
                            semicube_edge edge;
Packit Service c5cf8c
                            edge.src = blossom_edges[l];
Packit Service c5cf8c
                            edge.dest = blossom_edges[l + 1];
Packit Service c5cf8c
                            current_augmenting_path[l] = &edg;;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        MPL_free(blossom_edges);
Packit Service c5cf8c
                        goto fn_exit;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            /* Mark edge */
Packit Service c5cf8c
            if (unmarked_edge) {
Packit Service c5cf8c
                for (j = unmarked_edge_index; j < unmarked_edge_insert - 1; j++) {
Packit Service c5cf8c
                    unmarked_edges[j] = unmarked_edges[j + 1];
Packit Service c5cf8c
                }
Packit Service c5cf8c
                unmarked_edge_insert--;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (exposed_vertex) {
Packit Service c5cf8c
            /* Mark vertex */
Packit Service c5cf8c
            for (j = unmarked_vertex_index; j < unmarked_vertex_insert - 1; j++) {
Packit Service c5cf8c
                unmarked_vertices[j] = unmarked_vertices[j + 1];
Packit Service c5cf8c
            }
Packit Service c5cf8c
            unmarked_vertex_insert--;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    if (forest != NULL) {
Packit Service c5cf8c
        MPL_free(forest);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (unmarked_vertices != NULL) {
Packit Service c5cf8c
        MPL_free(unmarked_vertices);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (unmarked_edges != NULL) {
Packit Service c5cf8c
        MPL_free(unmarked_edges);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    *augmenting_path = current_augmenting_path;
Packit Service c5cf8c
    *augmenting_path_length = path_length;
Packit Service c5cf8c
    return;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static void find_maximum_matching(netloc_topology_t topology, netloc_node_t *** nodes,
Packit Service c5cf8c
                                  int num_nodes, semicube_edge ** edges, int num_edges,
Packit Service c5cf8c
                                  semicube_edge *** maximum_matching, int *num_matching_edges)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, j;
Packit Service c5cf8c
    semicube_edge **augmenting_path =
Packit Service c5cf8c
        (semicube_edge **) MPL_malloc(sizeof(semicube_edge *), MPL_MEM_OTHER);
Packit Service c5cf8c
    int path_length;
Packit Service c5cf8c
    int insert_location = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    find_augmenting_path(topology, nodes, num_nodes, edges, num_edges, &augmenting_path,
Packit Service c5cf8c
                         &path_length, *maximum_matching, *num_matching_edges);
Packit Service c5cf8c
    if (augmenting_path != NULL && path_length > 0) {
Packit Service c5cf8c
        semicube_edge **matching =
Packit Service c5cf8c
            (semicube_edge **) MPL_malloc(sizeof(semicube_edge *), MPL_MEM_OTHER);
Packit Service c5cf8c
        /* Update the maximum matching */
Packit Service c5cf8c
        for (i = 0; i < *num_matching_edges; i++) {
Packit Service c5cf8c
            semicube_edge *edge = (*maximum_matching)[i];
Packit Service c5cf8c
            int edge_in_both_sets = 0;
Packit Service c5cf8c
            for (j = 0; j < path_length; j++) {
Packit Service c5cf8c
                semicube_edge *augmenting_path_edge = augmenting_path[j];
Packit Service c5cf8c
                if (edge->src == augmenting_path_edge->src &&
Packit Service c5cf8c
                    edge->dest == augmenting_path_edge->dest) {
Packit Service c5cf8c
                    edge_in_both_sets = 1;
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (!edge_in_both_sets) {
Packit Service c5cf8c
                matching =
Packit Service c5cf8c
                    (semicube_edge **) MPL_realloc(matching,
Packit Service c5cf8c
                                                   sizeof(semicube_edge *) * (insert_location + 1),
Packit Service c5cf8c
                                                   MPL_MEM_OTHER);
Packit Service c5cf8c
                matching[insert_location++] = edge;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        for (i = 0; i < path_length; i++) {
Packit Service c5cf8c
            semicube_edge *edge = augmenting_path[i];
Packit Service c5cf8c
            int edge_in_both_sets = 0;
Packit Service c5cf8c
            for (j = 0; j < *num_matching_edges; j++) {
Packit Service c5cf8c
                semicube_edge *augmenting_path_edge = (*maximum_matching)[i];
Packit Service c5cf8c
                if (edge->src == augmenting_path_edge->src &&
Packit Service c5cf8c
                    edge->dest == augmenting_path_edge->dest) {
Packit Service c5cf8c
                    edge_in_both_sets = 1;
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (!edge_in_both_sets) {
Packit Service c5cf8c
                matching =
Packit Service c5cf8c
                    (semicube_edge **) MPL_realloc(matching,
Packit Service c5cf8c
                                                   sizeof(semicube_edge *) * (insert_location + 1),
Packit Service c5cf8c
                                                   MPL_MEM_OTHER);
Packit Service c5cf8c
                matching[insert_location++] = edge;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        find_maximum_matching(topology, nodes, num_nodes, edges, num_edges, &matching,
Packit Service c5cf8c
                              &insert_location);
Packit Service c5cf8c
        *maximum_matching = matching;
Packit Service c5cf8c
        *num_matching_edges = insert_location;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    if (augmenting_path != NULL) {
Packit Service c5cf8c
        MPL_free(augmenting_path);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static int get_torus_attributes(netloc_topology_t topology,
Packit Service c5cf8c
                                MPIR_Netloc_network_attributes * network_attr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    netloc_dt_lookup_table_t *nodes;
Packit Service c5cf8c
    struct netloc_dt_lookup_table_iterator *hti = NULL;
Packit Service c5cf8c
    netloc_node_t *start_node = NULL;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int num_edges = -1;
Packit Service c5cf8c
Packit Service c5cf8c
    if (network_attr->type == MPIR_NETLOC_NETWORK_TYPE__INVALID) {
Packit Service c5cf8c
        network_attr->type = MPIR_NETLOC_NETWORK_TYPE__TORUS;
Packit Service c5cf8c
        /* Check necessary condition for a torus i.e., outdegree of each node is the same */
Packit Service c5cf8c
        int node_count = 0;
Packit Service c5cf8c
        nodes =
Packit Service c5cf8c
            (netloc_dt_lookup_table_t *) MPL_malloc(sizeof(netloc_dt_lookup_table_t),
Packit Service c5cf8c
                                                    MPL_MEM_OTHER);
Packit Service c5cf8c
        mpi_errno = netloc_get_all_nodes(topology, nodes);
Packit Service c5cf8c
        hti = netloc_dt_lookup_table_iterator_t_construct(*nodes);
Packit Service c5cf8c
Packit Service c5cf8c
        while (!netloc_lookup_table_iterator_at_end(hti)) {
Packit Service c5cf8c
            netloc_node_t *node = (netloc_node_t *) netloc_lookup_table_iterator_next_entry(hti);
Packit Service c5cf8c
            netloc_edge_t **edges;
Packit Service c5cf8c
            int num_edges_per_node;
Packit Service c5cf8c
            if (node == NULL) {
Packit Service c5cf8c
                break;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            netloc_get_all_edges(topology, node, &num_edges_per_node, &edges);
Packit Service c5cf8c
            if (!node_count || num_edges_per_node < num_edges) {
Packit Service c5cf8c
                num_edges = num_edges_per_node;
Packit Service c5cf8c
                start_node = node;
Packit Service c5cf8c
                node_count++;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (start_node != NULL && network_attr->type != MPIR_NETLOC_NETWORK_TYPE__INVALID) {
Packit Service c5cf8c
        /* Assuming that hypercube dimension size is less than the bit width of long long */
Packit Service c5cf8c
        unsigned long long *hypercube_labels = NULL;
Packit Service c5cf8c
        int i, j, k, l;
Packit Service c5cf8c
        int start_index, end_index;
Packit Service c5cf8c
        /* Bitmap of non-zero entries in the labels */
Packit Service c5cf8c
        unsigned long long covered_bits;
Packit Service c5cf8c
        int covered_bits_count;
Packit Service c5cf8c
        int index;
Packit Service c5cf8c
        /* Get rid of the extra bidirectional and cycle edges */
Packit Service c5cf8c
        netloc_edge_t **ignore_edges = NULL;
Packit Service c5cf8c
        netloc_node_t **traversal_order = NULL, ***semicube_vertices = NULL;
Packit Service c5cf8c
        semicube_edge **semicube_edges = NULL;
Packit Service c5cf8c
        semicube_edge **complementary_edges = NULL;
Packit Service c5cf8c
        semicube_edge **maximum_matching = NULL;
Packit Service c5cf8c
        int hypercube_dimension = 0;
Packit Service c5cf8c
        unsigned int **distance_matrix;
Packit Service c5cf8c
Packit Service c5cf8c
        end_index = 0;
Packit Service c5cf8c
        start_index = 0;
Packit Service c5cf8c
        traversal_order =
Packit Service c5cf8c
            (netloc_node_t **) MPL_malloc(sizeof(netloc_node_t *) * topology->num_nodes,
Packit Service c5cf8c
                                          MPL_MEM_OTHER);
Packit Service c5cf8c
        MPIR_Assert(end_index < topology->num_nodes);
Packit Service c5cf8c
        traversal_order[end_index++] = start_node;
Packit Service c5cf8c
        /* Compute the depth first order of nodes to associate hamming code */
Packit Service c5cf8c
        start_index = end_index = 0;
Packit Service c5cf8c
        traversal_order[end_index++] = start_node;
Packit Service c5cf8c
        while (start_index < end_index) {
Packit Service c5cf8c
            netloc_node_t *vertex = traversal_order[start_index++];
Packit Service c5cf8c
            int num_edges;
Packit Service c5cf8c
            netloc_edge_t **edges;
Packit Service c5cf8c
            netloc_get_all_edges(topology, vertex, &num_edges, &edges);
Packit Service c5cf8c
            for (i = 0; i < num_edges; i++) {
Packit Service c5cf8c
                int dest_added = 0;
Packit Service c5cf8c
                int node_added_previously = 0;
Packit Service c5cf8c
                for (j = 0; j < end_index; j++) {
Packit Service c5cf8c
                    for (k = 0; k < end_index; k++) {
Packit Service c5cf8c
                        if (edges[i]->dest_node == traversal_order[k]) {
Packit Service c5cf8c
                            node_added_previously = 1;
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    if (!node_added_previously) {
Packit Service c5cf8c
                        traversal_order[end_index++] = edges[i]->dest_node;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        MPIR_Assert(end_index == topology->num_nodes);
Packit Service c5cf8c
        distance_matrix =
Packit Service c5cf8c
            (unsigned int **) MPL_calloc(topology->num_nodes * topology->num_nodes,
Packit Service c5cf8c
                                         sizeof(unsigned int *), MPL_MEM_OTHER);
Packit Service c5cf8c
        for (i = 0; i < topology->num_nodes; i++) {
Packit Service c5cf8c
            netloc_node_t *node = topology->nodes[i];
Packit Service c5cf8c
            int num_edges;
Packit Service c5cf8c
            netloc_edge_t **edges;
Packit Service c5cf8c
            netloc_get_all_edges(topology, node, &num_edges, &edges);
Packit Service c5cf8c
            distance_matrix[node->__uid__] =
Packit Service c5cf8c
                (unsigned int *) MPL_calloc(topology->num_nodes, sizeof(unsigned int),
Packit Service c5cf8c
                                            MPL_MEM_OTHER);
Packit Service c5cf8c
            for (j = 0; j < topology->num_nodes; j++) {
Packit Service c5cf8c
                distance_matrix[node->__uid__][topology->nodes[j]->__uid__] = MAX_DISTANCE;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            for (j = 0; j < num_edges; j++) {
Packit Service c5cf8c
                netloc_node_t *neighbor = edges[j]->dest_node;
Packit Service c5cf8c
                distance_matrix[node->__uid__][neighbor->__uid__] = 1;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        /* Compute the transitive closure */
Packit Service c5cf8c
        for (k = 0; k < topology->num_nodes; k++) {
Packit Service c5cf8c
            for (i = 0; i < topology->num_nodes; i++) {
Packit Service c5cf8c
                int first_index = topology->nodes[i]->__uid__;
Packit Service c5cf8c
                for (j = 0; j < topology->num_nodes; j++) {
Packit Service c5cf8c
                    int second_index = topology->nodes[j]->__uid__;
Packit Service c5cf8c
                    int third_index = topology->nodes[k]->__uid__;
Packit Service c5cf8c
                    if (distance_matrix[first_index][second_index] >
Packit Service c5cf8c
                        distance_matrix[first_index][third_index] +
Packit Service c5cf8c
                        distance_matrix[third_index][second_index]) {
Packit Service c5cf8c
                        distance_matrix[first_index][second_index] =
Packit Service c5cf8c
                            distance_matrix[first_index][third_index] +
Packit Service c5cf8c
                            distance_matrix[third_index][second_index];
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        if (start_index == topology->num_nodes) {
Packit Service c5cf8c
            int complementary_edge_index;
Packit Service c5cf8c
            int semicube_vertex_count;
Packit Service c5cf8c
            int *semicube_vertices_index;
Packit Service c5cf8c
            int semicube_edge_count;
Packit Service c5cf8c
            int num_matching_edges;
Packit Service c5cf8c
            netloc_node_t ****path_graphs;
Packit Service c5cf8c
            int *path_graph_count;
Packit Service c5cf8c
            int path_graph_insert;
Packit Service c5cf8c
            int num_nodes_covered;
Packit Service c5cf8c
            int **temp_coordinate_map = NULL;
Packit Service c5cf8c
            long node_index;
Packit Service c5cf8c
            int *coordinates;
Packit Service c5cf8c
Packit Service c5cf8c
            /* Initialize labels with 0 */
Packit Service c5cf8c
            hypercube_labels =
Packit Service c5cf8c
                (unsigned long long *) MPL_calloc(start_index, sizeof(unsigned long long),
Packit Service c5cf8c
                                                  MPL_MEM_OTHER);
Packit Service c5cf8c
            covered_bits = 0;
Packit Service c5cf8c
            covered_bits_count = 0;
Packit Service c5cf8c
            /* Get the isometric hypercube embedding of the input graph */
Packit Service c5cf8c
            for (i = 1; i < start_index; i++) {
Packit Service c5cf8c
                /* Find a neighbor node 1 hop away to the current and try new labels till a feasible label is found */
Packit Service c5cf8c
                netloc_node_t *neighbor = traversal_order[i];
Packit Service c5cf8c
                unsigned long long neighbor_label, bit_flip, new_label;
Packit Service c5cf8c
                netloc_node_t *node;
Packit Service c5cf8c
                int valid_label;
Packit Service c5cf8c
                int num_shifts, total_shifts;
Packit Service c5cf8c
                node = NULL;
Packit Service c5cf8c
                for (j = 0; j < i; j++) {
Packit Service c5cf8c
                    int num_edges;
Packit Service c5cf8c
                    netloc_edge_t **edges;
Packit Service c5cf8c
                    netloc_get_all_edges(topology, traversal_order[j], &num_edges, &edges);
Packit Service c5cf8c
                    node = NULL;
Packit Service c5cf8c
                    for (l = 0; l < num_edges; l++) {
Packit Service c5cf8c
                        if (edges[l]->dest_node == neighbor) {
Packit Service c5cf8c
                            node = traversal_order[j];
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    if (node != NULL) {
Packit Service c5cf8c
                        break;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
                MPIR_Assert(node != NULL);
Packit Service c5cf8c
                /* Generate a new label at hamming distance 1 from neighbor */
Packit Service c5cf8c
                neighbor_label = hypercube_labels[node->__uid__];
Packit Service c5cf8c
                bit_flip = 1;
Packit Service c5cf8c
                num_shifts = 0;
Packit Service c5cf8c
                valid_label = 0;
Packit Service c5cf8c
                while (num_shifts++ < (sizeof(unsigned long long) * 8)) {
Packit Service c5cf8c
                    int current_valid_label = 1;
Packit Service c5cf8c
                    unsigned long long temp_label = neighbor_label ^ bit_flip;
Packit Service c5cf8c
                    bit_flip = bit_flip << 1;
Packit Service c5cf8c
Packit Service c5cf8c
                    for (j = 0; j < i; j++) {
Packit Service c5cf8c
                        netloc_node_t *prev_node = traversal_order[j];
Packit Service c5cf8c
                        unsigned int distance;
Packit Service c5cf8c
                        unsigned int hamming_distance;
Packit Service c5cf8c
                        /* Check if the new label is consistent with previous labels
Packit Service c5cf8c
                         * with hamming distance */
Packit Service c5cf8c
                        if (temp_label == hypercube_labels[prev_node->__uid__]) {
Packit Service c5cf8c
                            current_valid_label = 0;
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        /* Find the distance of `neighbor` to `prev_node` */
Packit Service c5cf8c
                        distance = distance_matrix[prev_node->__uid__][neighbor->__uid__];
Packit Service c5cf8c
                        hamming_distance =
Packit Service c5cf8c
                            get_hamming_distance(hypercube_labels[prev_node->__uid__], temp_label);
Packit Service c5cf8c
                        if (distance != MAX_DISTANCE && hamming_distance != distance) {
Packit Service c5cf8c
                            current_valid_label = 0;
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    if (current_valid_label) {
Packit Service c5cf8c
                        valid_label = 1;
Packit Service c5cf8c
                        /* Check if this covers more bits than before */
Packit Service c5cf8c
                        int temp_bit_count;
Packit Service c5cf8c
                        long temp_covered_bits = covered_bits | temp_label;
Packit Service c5cf8c
                        temp_bit_count = 0;
Packit Service c5cf8c
                        while (temp_covered_bits) {
Packit Service c5cf8c
                            if (temp_covered_bits & 1) {
Packit Service c5cf8c
                                temp_bit_count++;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            temp_covered_bits = temp_covered_bits / 2;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        if (covered_bits_count <= temp_bit_count) {
Packit Service c5cf8c
                            new_label = temp_label;
Packit Service c5cf8c
                            if (covered_bits_count < temp_bit_count) {
Packit Service c5cf8c
                                break;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            covered_bits_count = temp_bit_count;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
                if (!valid_label) {
Packit Service c5cf8c
                    network_attr->type = MPIR_NETLOC_NETWORK_TYPE__INVALID;
Packit Service c5cf8c
                    goto cleanup;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                hypercube_labels[neighbor->__uid__] = new_label;
Packit Service c5cf8c
                covered_bits = covered_bits | new_label;
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            MPL_free(distance_matrix);
Packit Service c5cf8c
            network_attr->type = MPIR_NETLOC_NETWORK_TYPE__TORUS;
Packit Service c5cf8c
Packit Service c5cf8c
            hypercube_dimension = 0;
Packit Service c5cf8c
            index = 0;
Packit Service c5cf8c
            while (covered_bits) {
Packit Service c5cf8c
                int value = covered_bits & 1;
Packit Service c5cf8c
                if (!value) {
Packit Service c5cf8c
                    for (i = 0; i < topology->num_nodes; i++) {
Packit Service c5cf8c
                        unsigned long long label = hypercube_labels[i];
Packit Service c5cf8c
                        if (!index) {
Packit Service c5cf8c
                            label =
Packit Service c5cf8c
                                ((label >> (index + 1)) << index) | (label & ((2 << index) - 1));
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        hypercube_labels[i] = label;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                } else {
Packit Service c5cf8c
                    hypercube_dimension++;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                covered_bits = covered_bits >> 1;
Packit Service c5cf8c
                index++;
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            semicube_vertices =
Packit Service c5cf8c
                (netloc_node_t ***) MPL_calloc(2 * hypercube_dimension, sizeof(netloc_node_t **),
Packit Service c5cf8c
                                               MPL_MEM_OTHER);
Packit Service c5cf8c
Packit Service c5cf8c
            semicube_vertices_index = (int *) MPL_calloc(2 * hypercube_dimension, sizeof(int),
Packit Service c5cf8c
                                                         MPL_MEM_OTHER);
Packit Service c5cf8c
            semicube_vertex_count = 0;
Packit Service c5cf8c
            /* Compute the semicubes of the hypercube embedding */
Packit Service c5cf8c
            for (j = 0; j < topology->num_nodes; j++) {
Packit Service c5cf8c
                unsigned long long label = hypercube_labels[topology->nodes[j]->__uid__];
Packit Service c5cf8c
                for (i = 0; i < hypercube_dimension; i++) {
Packit Service c5cf8c
                    int semicube_index;
Packit Service c5cf8c
                    int insert_position;
Packit Service c5cf8c
                    if (label & (1u << i)) {
Packit Service c5cf8c
                        semicube_index = 2 * i + 1;
Packit Service c5cf8c
                    } else {
Packit Service c5cf8c
                        semicube_index = 2 * i;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    if (semicube_vertices[semicube_index] == NULL) {
Packit Service c5cf8c
                        semicube_vertex_count++;
Packit Service c5cf8c
                        insert_position = 0;
Packit Service c5cf8c
                        semicube_vertices[semicube_index] =
Packit Service c5cf8c
                            (netloc_node_t **) MPL_malloc(sizeof(netloc_node_t *), MPL_MEM_OTHER);
Packit Service c5cf8c
                    } else {
Packit Service c5cf8c
                        insert_position = semicube_vertices_index[semicube_index] + 1;
Packit Service c5cf8c
                        semicube_vertices[semicube_index] =
Packit Service c5cf8c
                            (netloc_node_t **) MPL_realloc(semicube_vertices[semicube_index],
Packit Service c5cf8c
                                                           (insert_position +
Packit Service c5cf8c
                                                            1) * sizeof(netloc_node_t *),
Packit Service c5cf8c
                                                           MPL_MEM_OTHER);
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    semicube_vertices[semicube_index][insert_position] = topology->nodes[j];
Packit Service c5cf8c
                    semicube_vertices_index[semicube_index] = insert_position;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            /* Compute the semicube graph edges from the semicubes of the hypercube embedding */
Packit Service c5cf8c
            semicube_edges =
Packit Service c5cf8c
                (semicube_edge **) MPL_malloc(hypercube_dimension * 2 * sizeof(semicube_edge *),
Packit Service c5cf8c
                                              MPL_MEM_OTHER);
Packit Service c5cf8c
            MPIR_Assert(semicube_edges != NULL);
Packit Service c5cf8c
            semicube_edge_count = 0;
Packit Service c5cf8c
            for (i = 0; i < hypercube_dimension * 2 - 1; i++) {
Packit Service c5cf8c
                netloc_node_t **first_set = semicube_vertices[i];
Packit Service c5cf8c
                if (first_set != NULL) {
Packit Service c5cf8c
                    for (j = i + 1; j < hypercube_dimension * 2; j++) {
Packit Service c5cf8c
                        netloc_node_t **second_set = semicube_vertices[j];
Packit Service c5cf8c
                        if (semicube_vertices[j] != NULL) {
Packit Service c5cf8c
                            int insert_count = 0;
Packit Service c5cf8c
                            int valid_edge = 0;
Packit Service c5cf8c
                            netloc_node_t **union_set = (netloc_node_t **)
Packit Service c5cf8c
                                MPL_malloc((semicube_vertices_index[i] +
Packit Service c5cf8c
                                            semicube_vertices_index[j] +
Packit Service c5cf8c
                                            2) * sizeof(netloc_node_t *),
Packit Service c5cf8c
                                           MPL_MEM_OTHER);
Packit Service c5cf8c
                            for (k = 0; k <= semicube_vertices_index[i]; k++) {
Packit Service c5cf8c
                                union_set[insert_count++] = first_set[k];
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            for (k = 0; k <= semicube_vertices_index[j]; k++) {
Packit Service c5cf8c
                                int added_before = 0;
Packit Service c5cf8c
                                for (l = 0; l < insert_count; l++) {
Packit Service c5cf8c
                                    if (union_set[l] == second_set[k]) {
Packit Service c5cf8c
                                        added_before = 1;
Packit Service c5cf8c
                                        valid_edge = 1;
Packit Service c5cf8c
                                        break;
Packit Service c5cf8c
                                    }
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                                if (!added_before) {
Packit Service c5cf8c
                                    union_set[insert_count++] = second_set[k];
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            if (valid_edge && insert_count == topology->num_nodes) {
Packit Service c5cf8c
                                semicube_edge *edge =
Packit Service c5cf8c
                                    (semicube_edge *) MPL_malloc(sizeof(semicube_edge *),
Packit Service c5cf8c
                                                                 MPL_MEM_OTHER);
Packit Service c5cf8c
                                edge->src = first_set;
Packit Service c5cf8c
                                edge->dest = second_set;
Packit Service c5cf8c
                                semicube_edges[semicube_edge_count++] = edge;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            MPL_free(union_set);
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            num_matching_edges = 0;
Packit Service c5cf8c
            /* Compute the maximum matching for semicube graph */
Packit Service c5cf8c
            find_maximum_matching(topology, semicube_vertices, semicube_vertex_count,
Packit Service c5cf8c
                                  semicube_edges, semicube_edge_count, &maximum_matching,
Packit Service c5cf8c
                                  &num_matching_edges);
Packit Service c5cf8c
            complementary_edges =
Packit Service c5cf8c
                (semicube_edge **) MPL_malloc(hypercube_dimension * 2 * sizeof(semicube_edge *),
Packit Service c5cf8c
                                              MPL_MEM_OTHER);
Packit Service c5cf8c
            complementary_edge_index = 0;
Packit Service c5cf8c
            /* Compute complementary paths in the graph */
Packit Service c5cf8c
            for (i = 0; i < hypercube_dimension * 2 - 1; i++) {
Packit Service c5cf8c
                netloc_node_t **first_set = semicube_vertices[i];
Packit Service c5cf8c
                if (first_set != NULL) {
Packit Service c5cf8c
                    for (j = i + 1; j < hypercube_dimension * 2; j++) {
Packit Service c5cf8c
                        netloc_node_t **second_set = semicube_vertices[j];
Packit Service c5cf8c
                        if (semicube_vertices[j] != NULL) {
Packit Service c5cf8c
                            int insert_count = 0;
Packit Service c5cf8c
                            int valid_edge = 1;
Packit Service c5cf8c
                            netloc_node_t **union_set = (netloc_node_t **)
Packit Service c5cf8c
                                MPL_malloc(topology->num_nodes * sizeof(netloc_node_t *),
Packit Service c5cf8c
                                           MPL_MEM_OTHER);
Packit Service c5cf8c
                            for (k = 0; k <= semicube_vertices_index[i]; k++) {
Packit Service c5cf8c
                                union_set[insert_count++] = first_set[k];
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            for (k = 0; k <= semicube_vertices_index[j]; k++) {
Packit Service c5cf8c
                                int added_before = 0;
Packit Service c5cf8c
                                for (l = 0; l < insert_count; l++) {
Packit Service c5cf8c
                                    if (union_set[l] == second_set[k]) {
Packit Service c5cf8c
                                        added_before = 1;
Packit Service c5cf8c
                                        valid_edge = 0;
Packit Service c5cf8c
                                        break;
Packit Service c5cf8c
                                    }
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                                if (!added_before) {
Packit Service c5cf8c
                                    union_set[insert_count++] = second_set[k];
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            if (valid_edge && insert_count == topology->num_nodes) {
Packit Service c5cf8c
                                semicube_edge *edge =
Packit Service c5cf8c
                                    (semicube_edge *) MPL_malloc(sizeof(semicube_edge *),
Packit Service c5cf8c
                                                                 MPL_MEM_OTHER);
Packit Service c5cf8c
                                edge->src = first_set;
Packit Service c5cf8c
                                edge->dest = second_set;
Packit Service c5cf8c
                                complementary_edges[complementary_edge_index++] = edge;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            MPL_free(union_set);
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            /* Compute path graphs */
Packit Service c5cf8c
            path_graphs =
Packit Service c5cf8c
                (netloc_node_t ****) MPL_malloc((hypercube_dimension - num_matching_edges) *
Packit Service c5cf8c
                                                sizeof(netloc_node_t ***), MPL_MEM_OTHER);
Packit Service c5cf8c
            path_graph_count =
Packit Service c5cf8c
                MPL_calloc((hypercube_dimension - num_matching_edges), sizeof(int), MPL_MEM_OTHER);
Packit Service c5cf8c
            path_graph_insert = 0;
Packit Service c5cf8c
            num_nodes_covered = 0;
Packit Service c5cf8c
            for (i = 0; i < semicube_vertex_count; i++) {
Packit Service c5cf8c
                netloc_node_t **semicube_vertex = semicube_vertices[i];
Packit Service c5cf8c
                int vertex_covered = 0;
Packit Service c5cf8c
                for (j = 0; j < path_graph_insert; j++) {
Packit Service c5cf8c
                    for (k = 0; k < path_graph_count[j]; k++) {
Packit Service c5cf8c
                        if (path_graphs[j][k] == semicube_vertex) {
Packit Service c5cf8c
                            vertex_covered = 1;
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    if (vertex_covered) {
Packit Service c5cf8c
                        break;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
Packit Service c5cf8c
                if (!vertex_covered) {
Packit Service c5cf8c
                    int num_edges = 0;
Packit Service c5cf8c
                    for (j = 0; j < num_matching_edges; j++) {
Packit Service c5cf8c
                        if (maximum_matching[j]->src == semicube_vertex ||
Packit Service c5cf8c
                            maximum_matching[j]->dest == semicube_vertex) {
Packit Service c5cf8c
                            num_edges++;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    for (j = 0; j < complementary_edge_index; j++) {
Packit Service c5cf8c
                        if (complementary_edges[j]->src == semicube_vertex ||
Packit Service c5cf8c
                            complementary_edges[j]->dest == semicube_vertex) {
Packit Service c5cf8c
                            num_edges++;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    /* Start from a vertex with 1 incoming/outgoing edge */
Packit Service c5cf8c
                    if (num_edges == 1) {
Packit Service c5cf8c
                        int num_nodes;
Packit Service c5cf8c
                        path_graphs[path_graph_insert] =
Packit Service c5cf8c
                            (netloc_node_t ***) MPL_calloc(semicube_vertex_count,
Packit Service c5cf8c
                                                           sizeof(netloc_node_t **), MPL_MEM_OTHER);
Packit Service c5cf8c
                        num_nodes = 0;
Packit Service c5cf8c
                        path_graphs[path_graph_insert][num_nodes++] = semicube_vertex;
Packit Service c5cf8c
                        MPIR_Assert(path_graph_insert <=
Packit Service c5cf8c
                                    (hypercube_dimension - num_matching_edges));
Packit Service c5cf8c
Packit Service c5cf8c
                        while (semicube_vertex) {
Packit Service c5cf8c
                            netloc_node_t **neighbor = NULL;
Packit Service c5cf8c
                            for (j = 0; j < num_matching_edges; j++) {
Packit Service c5cf8c
                                if (maximum_matching[j]->src == semicube_vertex ||
Packit Service c5cf8c
                                    maximum_matching[j]->dest == semicube_vertex) {
Packit Service c5cf8c
                                    fflush(stdout);
Packit Service c5cf8c
                                    netloc_node_t **temp_neighbor = NULL;
Packit Service c5cf8c
                                    if (maximum_matching[j]->src == semicube_vertex) {
Packit Service c5cf8c
                                        temp_neighbor = maximum_matching[j]->dest;
Packit Service c5cf8c
                                    } else {
Packit Service c5cf8c
                                        temp_neighbor = maximum_matching[j]->src;
Packit Service c5cf8c
                                    }
Packit Service c5cf8c
                                    for (k = 0; k < num_nodes; k++) {
Packit Service c5cf8c
                                        vertex_covered = 0;
Packit Service c5cf8c
                                        if (path_graphs[path_graph_insert][k] == temp_neighbor) {
Packit Service c5cf8c
                                            vertex_covered = 1;
Packit Service c5cf8c
                                            break;
Packit Service c5cf8c
                                        }
Packit Service c5cf8c
                                    }
Packit Service c5cf8c
                                    if (!vertex_covered) {
Packit Service c5cf8c
                                        neighbor = temp_neighbor;
Packit Service c5cf8c
                                        break;
Packit Service c5cf8c
                                    }
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            if (!neighbor) {
Packit Service c5cf8c
                                for (j = 0; j < complementary_edge_index; j++) {
Packit Service c5cf8c
                                    if (complementary_edges[j]->src == semicube_vertex ||
Packit Service c5cf8c
                                        complementary_edges[j]->dest == semicube_vertex) {
Packit Service c5cf8c
                                        netloc_node_t **temp_neighbor = NULL;
Packit Service c5cf8c
                                        if (complementary_edges[j]->src == semicube_vertex) {
Packit Service c5cf8c
                                            temp_neighbor = complementary_edges[j]->dest;
Packit Service c5cf8c
                                        } else {
Packit Service c5cf8c
                                            temp_neighbor = complementary_edges[j]->src;
Packit Service c5cf8c
                                        }
Packit Service c5cf8c
                                        for (k = 0; k < num_nodes; k++) {
Packit Service c5cf8c
                                            vertex_covered = 0;
Packit Service c5cf8c
                                            if (path_graphs[path_graph_insert][k] == temp_neighbor) {
Packit Service c5cf8c
                                                vertex_covered = 1;
Packit Service c5cf8c
                                                break;
Packit Service c5cf8c
                                            }
Packit Service c5cf8c
                                        }
Packit Service c5cf8c
                                        if (!vertex_covered) {
Packit Service c5cf8c
                                            neighbor = temp_neighbor;
Packit Service c5cf8c
                                            break;
Packit Service c5cf8c
                                        }
Packit Service c5cf8c
                                    }
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
Packit Service c5cf8c
                            if (neighbor) {
Packit Service c5cf8c
                                path_graphs[path_graph_insert][num_nodes++] = neighbor;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            semicube_vertex = neighbor;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        path_graph_count[path_graph_insert] = num_nodes;
Packit Service c5cf8c
                        num_nodes_covered += num_nodes;
Packit Service c5cf8c
                        path_graph_insert++;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_Assert(num_nodes_covered == semicube_vertex_count);
Packit Service c5cf8c
            network_attr->u.torus.dimension = path_graph_insert;
Packit Service c5cf8c
            network_attr->u.torus.geometry =
Packit Service c5cf8c
                (int *) MPL_calloc(path_graph_insert, sizeof(int), MPL_MEM_OTHER);
Packit Service c5cf8c
            temp_coordinate_map =
Packit Service c5cf8c
                (int **) MPL_calloc(topology->num_nodes, sizeof(int *), MPL_MEM_OTHER);
Packit Service c5cf8c
            /* Traverse path graphs to assign coordinates of each node and size of torus along each dimension */
Packit Service c5cf8c
            for (i = 0; i < topology->num_nodes; i++) {
Packit Service c5cf8c
                netloc_node_t *vertex = topology->nodes[i];
Packit Service c5cf8c
                temp_coordinate_map[vertex->__uid__] =
Packit Service c5cf8c
                    MPL_calloc(path_graph_insert, sizeof(int), MPL_MEM_OTHER);
Packit Service c5cf8c
                for (j = 0; j < path_graph_insert; j++) {
Packit Service c5cf8c
                    int current_edge = 0;
Packit Service c5cf8c
                    /* Required to keep track of the number of complementary edges */
Packit Service c5cf8c
                    temp_coordinate_map[vertex->__uid__][j] = -1;
Packit Service c5cf8c
                    while (current_edge < (path_graph_count[j] + 1)) {
Packit Service c5cf8c
                        int vertex_in_first_set, vertex_in_second_set;
Packit Service c5cf8c
                        vertex_in_first_set = 0;
Packit Service c5cf8c
                        if (current_edge == 0) {
Packit Service c5cf8c
                            vertex_in_first_set = 1;
Packit Service c5cf8c
                        } else {
Packit Service c5cf8c
                            netloc_node_t **semicube_node = path_graphs[j][current_edge - 1];
Packit Service c5cf8c
                            int semicube_node_index = -1;
Packit Service c5cf8c
                            for (k = 0; k < semicube_vertex_count; k++) {
Packit Service c5cf8c
                                if (semicube_vertices[k] == semicube_node) {
Packit Service c5cf8c
                                    semicube_node_index = k;
Packit Service c5cf8c
                                    break;
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            for (k = 0; k <= semicube_vertices_index[semicube_node_index]; k++) {
Packit Service c5cf8c
                                if (vertex == semicube_node[k]) {
Packit Service c5cf8c
                                    vertex_in_first_set = 1;
Packit Service c5cf8c
                                    break;
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        if (!vertex_in_first_set) {
Packit Service c5cf8c
                            current_edge++;
Packit Service c5cf8c
                            continue;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
Packit Service c5cf8c
                        vertex_in_second_set = 0;
Packit Service c5cf8c
                        if (current_edge == path_graph_count[j]) {
Packit Service c5cf8c
                            vertex_in_second_set = 1;
Packit Service c5cf8c
                        } else {
Packit Service c5cf8c
                            netloc_node_t **semicube_node = path_graphs[j][current_edge];
Packit Service c5cf8c
                            int semicube_node_index = -1;
Packit Service c5cf8c
                            for (k = 0; k < semicube_vertex_count; k++) {
Packit Service c5cf8c
                                if (semicube_vertices[k] == semicube_node) {
Packit Service c5cf8c
                                    semicube_node_index = k;
Packit Service c5cf8c
                                    break;
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            for (k = 0; k <= semicube_vertices_index[semicube_node_index]; k++) {
Packit Service c5cf8c
                                if (vertex == semicube_node[k]) {
Packit Service c5cf8c
                                    vertex_in_second_set = 1;
Packit Service c5cf8c
                                    break;
Packit Service c5cf8c
                                }
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        if (vertex_in_second_set) {
Packit Service c5cf8c
                            /* Current edge counter has to be odd */
Packit Service c5cf8c
                            MPIR_Assert(current_edge & 1);
Packit Service c5cf8c
                            temp_coordinate_map[vertex->__uid__][j] = (current_edge + 1) / 2;
Packit Service c5cf8c
                            if (network_attr->u.torus.geometry[j] <
Packit Service c5cf8c
                                (temp_coordinate_map[vertex->__uid__][j] + 1)) {
Packit Service c5cf8c
                                network_attr->u.torus.geometry[j] =
Packit Service c5cf8c
                                    temp_coordinate_map[vertex->__uid__][j] + 1;
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            break;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        current_edge++;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    MPIR_Assert(temp_coordinate_map[vertex->__uid__][j] > -1);
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            /* Identify the network node corresponding to the current rank's node */
Packit Service c5cf8c
            errno = MPIR_Netloc_get_network_end_point(MPIR_Process.network_attr,
Packit Service c5cf8c
                                                      MPIR_Process.netloc_topology,
Packit Service c5cf8c
                                                      MPIR_Process.hwloc_topology,
Packit Service c5cf8c
                                                      &MPIR_Process.network_attr.network_endpoint);
Packit Service c5cf8c
            if (errno != MPI_SUCCESS) {
Packit Service c5cf8c
                network_attr->type = MPIR_NETLOC_NETWORK_TYPE__INVALID;
Packit Service c5cf8c
            } else {
Packit Service c5cf8c
                /* Flatten computed coordinates into a long value for the current node */
Packit Service c5cf8c
                coordinates =
Packit Service c5cf8c
                    temp_coordinate_map[MPIR_Process.network_attr.network_endpoint->__uid__];
Packit Service c5cf8c
                node_index = coordinates[0];
Packit Service c5cf8c
                for (j = 1; j < path_graph_insert; j++) {
Packit Service c5cf8c
                    node_index = (node_index * network_attr->u.torus.geometry[j]) + coordinates[j];
Packit Service c5cf8c
                }
Packit Service c5cf8c
                network_attr->u.torus.node_idx = index;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            MPL_free(temp_coordinate_map);
Packit Service c5cf8c
            MPL_free(path_graph_count);
Packit Service c5cf8c
            MPL_free(path_graphs);
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            network_attr->type = MPIR_NETLOC_NETWORK_TYPE__INVALID;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
      cleanup:
Packit Service c5cf8c
        if (traversal_order != NULL) {
Packit Service c5cf8c
            MPL_free(traversal_order);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (hypercube_labels != NULL) {
Packit Service c5cf8c
            MPL_free(hypercube_labels);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (semicube_edges != NULL) {
Packit Service c5cf8c
            MPL_free(semicube_edges);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (semicube_vertices != NULL) {
Packit Service c5cf8c
            MPL_free(semicube_vertices);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (maximum_matching != NULL) {
Packit Service c5cf8c
            MPL_free(maximum_matching);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        network_attr->type = MPIR_NETLOC_NETWORK_TYPE__INVALID;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Netloc_parse_topology
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Netloc_parse_topology(netloc_topology_t netloc_topology,
Packit Service c5cf8c
                               MPIR_Netloc_network_attributes * network_attr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    mpi_errno = get_tree_attributes(MPIR_Process.netloc_topology, network_attr);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
    if (network_attr->type == MPIR_NETLOC_NETWORK_TYPE__INVALID) {
Packit Service c5cf8c
        mpi_errno = get_torus_attributes(MPIR_Process.netloc_topology, network_attr);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static int get_physical_address(hwloc_obj_t hwloc_obj, char **device_physical_address)
Packit Service c5cf8c
{
Packit Service c5cf8c
    char *physical_address = NULL;
Packit Service c5cf8c
    int i;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    for (i = 0; i < hwloc_obj->infos_count; i++) {
Packit Service c5cf8c
        /* Check if node guid matches for infiniband networks */
Packit Service c5cf8c
        if (!strcmp(hwloc_obj->infos[i].name, "NodeGUID")) {
Packit Service c5cf8c
            physical_address =
Packit Service c5cf8c
                (char *) MPL_malloc(sizeof(hwloc_obj->infos[i].value), MPL_MEM_OTHER);
Packit Service c5cf8c
            strcpy(physical_address, hwloc_obj->infos[i].value);
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    *device_physical_address = physical_address;
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Netloc_get_network_end_point
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Netloc_get_network_end_point(MPIR_Netloc_network_attributes network_attributes,
Packit Service c5cf8c
                                      netloc_topology_t netloc_topology,
Packit Service c5cf8c
                                      hwloc_topology_t hwloc_topology, netloc_node_t ** end_point)
Packit Service c5cf8c
{
Packit Service c5cf8c
    hwloc_obj_t io_device = NULL;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int node_query_ret;
Packit Service c5cf8c
    netloc_dt_lookup_table_t *host_nodes;
Packit Service c5cf8c
    struct netloc_dt_lookup_table_iterator *hti = NULL;
Packit Service c5cf8c
    netloc_node_t *node_end_point = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
    host_nodes =
Packit Service c5cf8c
        (netloc_dt_lookup_table_t *) MPL_malloc(sizeof(netloc_dt_lookup_table_t), MPL_MEM_OTHER);
Packit Service c5cf8c
    node_query_ret = netloc_get_all_host_nodes(netloc_topology, host_nodes);
Packit Service c5cf8c
    if (node_query_ret) {
Packit Service c5cf8c
        /* No nodes found, which means that topology load failed */
Packit Service c5cf8c
        MPIR_ERR_CHKANDJUMP(node_query_ret, mpi_errno, MPI_ERR_OTHER, "**netloc_topo_load");
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    while ((io_device = hwloc_get_next_osdev(hwloc_topology, io_device))
Packit Service c5cf8c
           != NULL) {
Packit Service c5cf8c
        char *physical_address = NULL;
Packit Service c5cf8c
        /* Check if the physical id of the io device matches a node in netloc topology tree */
Packit Service c5cf8c
        mpi_errno = get_physical_address(io_device, &physical_address);
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
        if (physical_address != NULL) {
Packit Service c5cf8c
            /* Find the node in netloc tree with the same physical id */
Packit Service c5cf8c
            hti = netloc_dt_lookup_table_iterator_t_construct(*host_nodes);
Packit Service c5cf8c
            while (!netloc_lookup_table_iterator_at_end(hti)) {
Packit Service c5cf8c
                netloc_node_t *node =
Packit Service c5cf8c
                    (netloc_node_t *) netloc_lookup_table_iterator_next_entry(hti);
Packit Service c5cf8c
                if (node == NULL) {
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                if (!strcmp(physical_address, node->physical_id)) {
Packit Service c5cf8c
                    node_end_point = node;
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            MPL_free(physical_address);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (node_end_point == NULL) {
Packit Service c5cf8c
        MPIR_ERR_SETANDJUMP(mpi_errno, MPI_ERR_OTHER, "**netloc_endpoint_mismatch");
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    if (host_nodes != NULL) {
Packit Service c5cf8c
        MPL_free(host_nodes);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    *end_point = node_end_point;
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Netloc_get_hostnode_index_in_tree
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Netloc_get_hostnode_index_in_tree(MPIR_Netloc_network_attributes attributes,
Packit Service c5cf8c
                                           netloc_topology_t topology,
Packit Service c5cf8c
                                           netloc_node_t * network_endpoint,
Packit Service c5cf8c
                                           int *index, int *num_leaf_nodes)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int max_level = 0;
Packit Service c5cf8c
    netloc_node_t **traversal_order;
Packit Service c5cf8c
    int start_index, end_index, i, j, node_index, num_nodes;
Packit Service c5cf8c
    MPIR_CHKPMEM_DECL(3);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_CHKPMEM_MALLOC(traversal_order, netloc_node_t **,
Packit Service c5cf8c
                        sizeof(netloc_node_t *) * topology->num_nodes, mpi_errno,
Packit Service c5cf8c
                        "traversal_order", MPL_MEM_OTHER);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Assign index to nodes via breadth first traversal starting from nodes with maximum level,
Packit Service c5cf8c
     * corresponding to the top level switches */
Packit Service c5cf8c
    for (i = 0; i < topology->num_nodes; i++) {
Packit Service c5cf8c
        if (attributes.u.tree.node_levels[topology->nodes[i]->__uid__] > max_level) {
Packit Service c5cf8c
            max_level = attributes.u.tree.node_levels[topology->nodes[i]->__uid__];
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    end_index = 0;
Packit Service c5cf8c
    for (i = 0; i < topology->num_nodes; i++) {
Packit Service c5cf8c
        if (attributes.u.tree.node_levels[topology->nodes[i]->__uid__] == max_level) {
Packit Service c5cf8c
            MPIR_Assert(end_index < topology->num_nodes);
Packit Service c5cf8c
            traversal_order[end_index++] = topology->nodes[i];
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    start_index = 0;
Packit Service c5cf8c
    node_index = 0;
Packit Service c5cf8c
    num_nodes = 0;
Packit Service c5cf8c
    while (start_index < end_index) {
Packit Service c5cf8c
        int num_edges;
Packit Service c5cf8c
        netloc_edge_t **edges;
Packit Service c5cf8c
        netloc_node_t *traversal_node = traversal_order[start_index++];
Packit Service c5cf8c
        if (traversal_node == network_endpoint) {
Packit Service c5cf8c
            node_index = num_nodes;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (traversal_node->node_type == NETLOC_NODE_TYPE_HOST) {
Packit Service c5cf8c
            num_nodes++;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        netloc_get_all_edges(topology, traversal_node, &num_edges, &edges);
Packit Service c5cf8c
        for (i = 0; i < num_edges; i++) {
Packit Service c5cf8c
            int node_added_before = 0;
Packit Service c5cf8c
            for (j = 0; j < end_index; j++) {
Packit Service c5cf8c
                if (traversal_order[j] == edges[i]->dest_node) {
Packit Service c5cf8c
                    node_added_before = 1;
Packit Service c5cf8c
                    break;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (!node_added_before) {
Packit Service c5cf8c
                MPIR_Assert(end_index < topology->num_nodes);
Packit Service c5cf8c
                traversal_order[end_index++] = edges[i]->dest_node;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_CHKPMEM_COMMIT();
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_CHKPMEM_REAP();
Packit Service c5cf8c
    *index = node_index;
Packit Service c5cf8c
    *num_leaf_nodes = num_nodes;
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Netloc_get_switches_at_level
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Netloc_get_switches_at_level(netloc_topology_t topology,
Packit Service c5cf8c
                                      MPIR_Netloc_network_attributes attributes, int level,
Packit Service c5cf8c
                                      netloc_node_t *** switches_at_level, int *switch_count)
Packit Service c5cf8c
{
Packit Service c5cf8c
    netloc_node_t **switches = NULL;
Packit Service c5cf8c
    netloc_dt_lookup_table_t *switch_nodes = NULL;
Packit Service c5cf8c
    struct netloc_dt_lookup_table_iterator *hti = NULL;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int i = 0;
Packit Service c5cf8c
    int node_query_ret;
Packit Service c5cf8c
Packit Service c5cf8c
    switches = (netloc_node_t **) MPL_malloc(sizeof(netloc_node_t *), MPL_MEM_OTHER);
Packit Service c5cf8c
    switch_nodes =
Packit Service c5cf8c
        (netloc_dt_lookup_table_t *) MPL_malloc(sizeof(netloc_dt_lookup_table_t), MPL_MEM_OTHER);
Packit Service c5cf8c
    node_query_ret = netloc_get_all_switch_nodes(topology, switch_nodes);
Packit Service c5cf8c
Packit Service c5cf8c
    if (node_query_ret) {
Packit Service c5cf8c
        /* No switch nodes found, which means that topology load failed */
Packit Service c5cf8c
        MPIR_ERR_CHKANDJUMP(node_query_ret, mpi_errno, MPI_ERR_OTHER, "**netloc_topo_load");
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    hti = netloc_dt_lookup_table_iterator_t_construct(*switch_nodes);
Packit Service c5cf8c
    while (!netloc_lookup_table_iterator_at_end(hti)) {
Packit Service c5cf8c
        netloc_node_t *switch_node = (netloc_node_t *) netloc_lookup_table_iterator_next_entry(hti);
Packit Service c5cf8c
        if (switch_node == NULL) {
Packit Service c5cf8c
            break;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (attributes.u.tree.node_levels[switch_node->__uid__] == level) {
Packit Service c5cf8c
            switches =
Packit Service c5cf8c
                (netloc_node_t **) MPL_realloc(switches, sizeof(netloc_node_t *) * i,
Packit Service c5cf8c
                                               MPL_MEM_OTHER);
Packit Service c5cf8c
            switches[i++] = switch_node;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    if (switches != NULL) {
Packit Service c5cf8c
        MPL_free(switches);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (switch_nodes != NULL) {
Packit Service c5cf8c
        MPL_free(switch_nodes);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    *switches_at_level = switches;
Packit Service c5cf8c
    *switch_count = i;
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#endif