GitLab maintenance scheduled form Friday, 2021-06-18 5:00pm to Satursday, 2021-06-19 10:00pm CT - Services will be unavailable during this time.

connection-manager.h 18.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
#ifndef CONNECTION_MANAGER_H
#define CONNECTION_MANAGER_H

/**
 * connection-manager.h -- Simple, Readable, Connection management interface
 * Neil McGlohon
 *
 * Copyright (c) 2018 Rensselaer Polytechnic Institute
 */
#include <map>
#include <vector>
12
#include <set>
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
#include "codes/codes.h"
#include "codes/model-net.h"


using namespace std;

/**
 * @brief Enum differentiating local router connection types from global.
 * Local connections will have router IDs ranging from [0,num_router_per_group)
 * whereas global connections will have router IDs ranging from [0,total_routers)
 */
enum ConnectionType
{
    CONN_LOCAL = 1,
    CONN_GLOBAL,
    CONN_TERMINAL
};

/**
 * @brief Struct for connection information.
 */
struct Connection
{
    int port; //port ID of the connection
37 38 39 40 41 42
    int src_lid; //local id of the source
    int src_gid; //global id of the source
    int src_group_id; //group id of the source
    int dest_lid; //local id of the destination
    int dest_gid; //global id of the destination
    int dest_group_id; //group id of the destination
43 44 45
    ConnectionType conn_type; //type of the connection: CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL
};

46 47 48 49 50
inline bool operator<(const Connection& lhs, const Connection& rhs)
{
  return lhs.port < rhs.port;
}

51 52 53 54 55 56 57 58 59 60 61 62
/**
 * @class ConnectionManager
 *
 * @brief
 * This class is meant to make organization of the connections between routers more
 * streamlined. It provides a simple, readable interface which helps reduce
 * semantic errors during development.
 *
 * @note
 * This class was designed with dragonfly type topologies in mind. Certain parts may not
 * make sense for other types of topologies, they might work fine, but no guarantees.
 *
63 64 65 66 67 68
 * @note
 * There is the property intermediateRouterToGroupMap and related methods that are implemented but the
 * logistics to get this information from input file is more complicated than its worth so I have commented
 * them out.
 *
 * @note
69 70 71
 * This class assumes that each router group has the same number of routers in it: _num_routers_per_group.
 */
class ConnectionManager {
72 73 74
    map< int, vector< Connection > > intraGroupConnections; //direct connections within a group - IDs are group local - maps local id to list of connections to it
    map< int, vector< Connection > > globalConnections; //direct connections between routers not in same group - IDs are global router IDs - maps global id to list of connections to it
    map< int, vector< Connection > > terminalConnections; //direct connections between this router and its compute node terminals - maps terminal id to connections to it
75 76 77

    map< int, Connection > _portMap; //Mapper for ports to connections

78 79
    vector< int > _other_groups_i_connect_to;
    set< int > _other_groups_i_connect_to_set;
80

81 82 83 84 85
    // map< int, vector< Connection > > intermediateRouterToGroupMap; //maps group id to list of routers that connect to it.
    //                                                                //ex: intermediateRouterToGroupMap[3] returns a vector
    //                                                                //of connections from this router to routers that have
    //                                                                //direct connections to group 3

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    int _source_id_local; //local id (within group) of owner of this connection manager
    int _source_id_global; //global id (not lp gid) of owner of this connection manager
    int _source_group; //group id of the owner of this connection manager

    int _used_intra_ports; //number of used ports for intra connections
    int _used_inter_ports; //number of used ports for inter connections
    int _used_terminal_ports; //number of used ports for terminal connections

    int _max_intra_ports; //maximum number of ports for intra connecitons
    int _max_inter_ports; //maximum number of ports for inter connections
    int _max_terminal_ports; //maximum number of ports for terminal connections.

    int _num_routers_per_group; //number of routers per group - used for turning global ID into local and back

public:
    ConnectionManager(int src_id_local, int src_id_global, int src_group, int max_intra, int max_inter, int max_term, int num_router_per_group);

    /**
     * @brief Adds a connection to the manager
105
     * @param dest_gid the global ID of the destination router
106 107
     * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL
     */
108
    void add_connection(int dest_gid, ConnectionType type);
109

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    // /**
    //  * @brief adds knowledge of what next hop routers have connections to specific groups
    //  * @param local_intm_id the local intra group id of the router that has the connection to dest_group_id
    //  * @param dest_group_id the id of the group that the connection goes to
    //  */
    // void add_route_to_group(int local_intm_id, int dest_group_id);

    // /**
    //  * @brief returns a vector of connections to routers that have direct connections to the specified group id
    //  * @param dest_group_id the id of the destination group that all connections returned have a direct connection to
    //  */
    // vector< Connection > get_intm_conns_to_group(int dest_group_id);

    // /**
    //  * @brief returns a vector of local router ids that have direct connections to the specified group id
    //  * @param dest_group_id the id of the destination group that all routers returned have a direct connection to
    //  * @note if a router has multiple intra group connections to a single router and that router has a connection
    //  *      to the dest group then that router will appear multiple times in the returned vector.
    //  */
    // vector< int > get_intm_routers_to_group(int dest_group_id)

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
    /**
     * @brief get the source ID of the owner of the manager
     * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL
     */
    int get_source_id(ConnectionType type);

    /**
     * @brief get the port(s) associated with a specific destination ID
     * @param dest_id the ID (local or global depending on type) of the destination
     * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL
     */
    vector<int> get_ports(int dest_id, ConnectionType type);

    /**
     * @brief get the connection associated with a specific port number
     * @param port the enumeration of the port in question
     */
    Connection get_connection_on_port(int port);

    /**
     * @brief returns true if a connection exists in the manager from the source to the specified destination ID BY TYPE
     * @param dest_id the ID of the destination depending on the type
     * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL
     * @note Will not return true if dest_id is within own group and type is CONN_GLOBAL, see is_any_connection_to()
     */
    bool is_connected_to_by_type(int dest_id, ConnectionType type);

    /**
     * @brief returns true if any connection exists in the manager from the soruce to the specified global destination ID
     * @param dest_global_id the global id of the destination
     * @note This is meant to allow for a developer to determine connectivity just from the global ID, even if the two entities
     *       are connected by a local or terminal connection.
     */
    bool is_any_connection_to(int dest_global_id);

    /**
     * @brief returns the total number of used ports by the owner of the manager
     */
    int get_total_used_ports();

    /**
     * @brief returns the number of used ports for a specific connection type
     * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL
     */
    int get_used_ports_for(ConnectionType type);

177 178 179 180 181 182
    /**
     * @brief returns the type of connection associated with said port
     * @param port_num the number of the port in question
     */
    ConnectionType get_port_type(int port_num);

183 184 185 186 187
    /**
     * @brief returns a vector of connections to the destination ID based on the connection type
     * @param dest_id the ID of the destination depending on the type
     * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL
     */
188
    vector< Connection > get_connections_to_gid(int dest_id, ConnectionType type);
189 190 191 192 193 194

    /**
     * @brief returns a vector of connections to the destination group. connections will be of type CONN_GLOBAL
     * @param dest_group_id the id of the destination group
     */
    vector< Connection > get_connections_to_group(int dest_group_id);
195

196 197 198 199 200 201 202
    /**
     * @brief returns a vector of all connections to routers via type specified.
     * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL
     * @note this will return connections to same destination on different ports as individual connections
     */
    vector< Connection > get_connections_by_type(ConnectionType type);

203 204 205 206 207 208
    /**
     * @brief returns a vector of all group IDs that the router has a global connection to
     * @note this does not include the router's own group as that is a given
     */
    vector< int > get_connected_group_ids();

209 210 211 212 213
    /**
    *
    */
    void solidify_connections();

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    /**
     * @brief prints out the state of the connection manager
     */
    void print_connections();
};


//*******************    BEGIN IMPLEMENTATION ********************************************************

//*******************    Connection Manager Implementation *******************************************
ConnectionManager::ConnectionManager(int src_id_local, int src_id_global, int src_group, int max_intra, int max_inter, int max_term, int num_router_per_group)
{
    _source_id_local = src_id_local;
    _source_id_global = src_id_global;
    _source_group = src_group;

    _used_intra_ports = 0;
    _used_inter_ports = 0;
    _used_terminal_ports = 0;

    _max_intra_ports = max_intra;
    _max_inter_ports = max_inter;
    _max_terminal_ports = max_term;

    _num_routers_per_group = num_router_per_group;
}

241
void ConnectionManager::add_connection(int dest_gid, ConnectionType type)
242 243
{
    Connection conn;
244 245 246
    conn.src_lid = _source_id_local;
    conn.src_gid = _source_id_global;
    conn.src_group_id = _source_group;
247
    conn.conn_type = type;
248 249 250
    conn.dest_lid = dest_gid % _num_routers_per_group;
    conn.dest_gid = dest_gid;
    conn.dest_group_id = dest_gid / _num_routers_per_group;
251 252 253 254 255

    switch (type)
    {
        case CONN_LOCAL:
            conn.port = this->get_used_ports_for(CONN_LOCAL);
256
            intraGroupConnections[conn.dest_lid].push_back(conn);
257 258 259 260 261
            _used_intra_ports++;
            break;

        case CONN_GLOBAL:
            conn.port = _max_intra_ports + this->get_used_ports_for(CONN_GLOBAL);
262
            globalConnections[conn.dest_gid].push_back(conn);
263 264 265 266 267
            _used_inter_ports++;
            break;

        case CONN_TERMINAL:
            conn.port = _max_intra_ports + _max_inter_ports + this->get_used_ports_for(CONN_TERMINAL);
268 269
            conn.dest_group_id = _source_group;
            terminalConnections[conn.dest_gid].push_back(conn);
270 271 272 273 274 275 276 277
            _used_terminal_ports++;
            break;

        default:
            assert(false);
            // TW_ERROR(TW_LOC, "add_connection(dest_id, type): Undefined connection type\n");
    }

278
    if(conn.dest_group_id != conn.src_group_id)
279
        _other_groups_i_connect_to_set.insert(conn.dest_group_id);
280

281 282 283
    _portMap[conn.port] = conn;
}

284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
// void ConnectionManager::add_route_to_group(Connection conn, int dest_group_id)
// {
//     intermediateRouterToGroupMap[dest_group_id].push_back(conn);
// }

// vector< Connection > ConnectionManager::get_intm_conns_to_group(int dest_group_id)
// {
//     return intermediateRouterToGroupMap[dest_group_id];
// }

// vector< int > ConnectionManager::get_intm_routers_to_group(int dest_group_id)
// {
//     vector< Connection > intm_router_conns = get_intm_conns_to_group(dest_group_id);

//     vector< int > loc_intm_router_ids;
//     vector< Connection >::iterator it;
//     for(it = intm_router_conns.begin(); it != intm_router_conns.end(); it++)
//     {
//         loc_intm_router_ids.push_back((*it).other_id);
//     }
//     return loc_intm_router_ids;
// }

307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
int ConnectionManager::get_source_id(ConnectionType type)
{
    switch (type)
    {
        case CONN_LOCAL:
            return _source_id_local;
        case CONN_GLOBAL:
            return _source_id_global;
        default:
            assert(false);
            // TW_ERROR(TW_LOC, "get_source_id(type): Unsupported connection type\n");
    }
}

vector<int> ConnectionManager::get_ports(int dest_id, ConnectionType type)
{
323
    vector< Connection > conns = this->get_connections_to_gid(dest_id, type);
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394

    vector< int > ports_used;
    vector< Connection >::iterator it = conns.begin();
    for(; it != conns.end(); it++) {
        ports_used.push_back((*it).port); //add port from connection list to the used ports list
    }
    return ports_used;
}

Connection ConnectionManager::get_connection_on_port(int port)
{
    return _portMap[port];
}

bool ConnectionManager::is_connected_to_by_type(int dest_id, ConnectionType type)
{
    switch (type)
    {
        case CONN_LOCAL:
            if (intraGroupConnections.find(dest_id) != intraGroupConnections.end())
                return true;
            break;
        case CONN_GLOBAL:
            if (globalConnections.find(dest_id) != globalConnections.end())
                return true;
            break;
        case CONN_TERMINAL:
            if (terminalConnections.find(dest_id) != terminalConnections.end())
                return true;
            break;
        default:
            assert(false);
            // TW_ERROR(TW_LOC, "get_used_ports_for(type): Undefined connection type\n");
    }
    return false;
}

bool ConnectionManager::is_any_connection_to(int dest_global_id)
{
    int local_id = dest_global_id % _num_routers_per_group;
    if (intraGroupConnections.find(local_id) != intraGroupConnections.end())
        return true;
    if (globalConnections.find(dest_global_id) != globalConnections.end())
        return true;
    if (terminalConnections.find(dest_global_id) != terminalConnections.end())
        return true;

    return false;
}

int ConnectionManager::get_total_used_ports()
{
    return _used_intra_ports + _used_inter_ports + _used_terminal_ports;
}

int ConnectionManager::get_used_ports_for(ConnectionType type)
{
    switch (type)
    {
        case CONN_LOCAL:
            return _used_intra_ports;
        case CONN_GLOBAL:
            return _used_inter_ports;
        case CONN_TERMINAL:
            return _used_terminal_ports;
        default:
            assert(false);
            // TW_ERROR(TW_LOC, "get_used_ports_for(type): Undefined connection type\n");
    }
}

395 396 397 398 399 400 401
ConnectionType ConnectionManager::get_port_type(int port_num)
{
    return _portMap[port_num].conn_type;
}


vector< Connection > ConnectionManager::get_connections_to_gid(int dest_gid, ConnectionType type)
402 403 404 405
{
    switch (type)
    {
        case CONN_LOCAL:
406
            return intraGroupConnections[dest_gid%_num_routers_per_group];
407
        case CONN_GLOBAL:
408
            return globalConnections[dest_gid];
409
        case CONN_TERMINAL:
410
            return terminalConnections[dest_gid];
411 412 413 414 415 416
        default:
            assert(false);
            // TW_ERROR(TW_LOC, "get_connections(type): Undefined connection type\n");
    }
}

417 418 419 420 421 422 423 424 425 426
vector< Connection > ConnectionManager::get_connections_to_group(int dest_group_id)
{
    vector< Connection > conns_to_group;

    map< int, vector< Connection > >::iterator it = globalConnections.begin();
    for(; it != globalConnections.end(); it++) //iterate over each router that is connected to source
    {
        vector< Connection >::iterator conns_to_router;
        for(conns_to_router = (it->second).begin(); conns_to_router != (it->second).end(); conns_to_router++) //iterate over each connection to a specific router
        {
427
            if ((*conns_to_router).dest_group_id == dest_group_id) {
428 429 430 431 432 433 434
                conns_to_group.push_back(*conns_to_router);
            }
        }
    }
    return conns_to_group;
}

435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
vector< Connection > ConnectionManager::get_connections_by_type(ConnectionType type)
{
    map< int, vector< Connection > > theMap;
    switch (type)
    {
        case CONN_LOCAL:
            theMap = intraGroupConnections;
            break;
        case CONN_GLOBAL:
            theMap = globalConnections;
            break;
        case CONN_TERMINAL:
            theMap = terminalConnections;
            break;
    }

    vector< Connection > retVec;
    map< int, vector< Connection > >::iterator it;
    for(it = theMap.begin(); it != theMap.end(); it++)
    {
        retVec.insert(retVec.end(), (*it).second.begin(), (*it).second.end());
    }

    return retVec;
}

461 462
vector< int > ConnectionManager::get_connected_group_ids()
{
463 464 465 466 467
    return _other_groups_i_connect_to;
}

void ConnectionManager::solidify_connections()
{
468
    set< int >::iterator it;
469
    for(it = _other_groups_i_connect_to_set.begin(); it != _other_groups_i_connect_to_set.end(); it++)
470
    {
471
        _other_groups_i_connect_to.push_back(*it);
472 473
    }
}
474

475

476 477 478 479 480 481 482 483
void ConnectionManager::print_connections()
{
    printf("Connections for Router: %d ---------------------------------------\n",_source_id_global);

    int ports_printed = 0;
    map<int,Connection>::iterator it = _portMap.begin();
    for(; it != _portMap.end(); it++)
    {
484
        if ( (ports_printed == 0) && (_used_intra_ports > 0) )
485 486 487 488
        {
            printf(" -- Intra-Group Connections -- \n");
            printf("  Port  |  Dest_ID  |  Group\n");
        }
489
        if ( (ports_printed == _used_intra_ports) && (_used_inter_ports > 0) )
490 491 492 493
        {
            printf(" -- Inter-Group Connections -- \n");
            printf("  Port  |  Dest_ID  |  Group\n");
        }
494
        if ( (ports_printed == _used_intra_ports + _used_inter_ports) && (_used_terminal_ports > 0) )
495 496 497 498 499
        {
            printf(" -- Terminal Connections -- \n");
            printf("  Port  |  Dest_ID  |  Group\n");
        }

500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
        int port_num = it->first;
        int group_id = it->second.dest_group_id;

        int id,gid;
        if( get_port_type(port_num) == CONN_LOCAL )
        {
            id = it->second.dest_lid;
            gid = it->second.dest_gid;
            printf("  %d   ->   (%d,%d)        :  %d  \n", port_num, id, gid, group_id);

        }
            
        else {
            id = it->second.dest_gid;
            printf("  %d   ->   %d        :  %d  \n", port_num, id, group_id);

        }
            
518 519 520 521
        ports_printed++;
    }
}

522 523


524
#endif /* end of include guard:*/