connection-manager.h 20.5 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
#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,
27 28
    CONN_GLOBAL = 2,
    CONN_TERMINAL = 3
29 30 31 32 33 34 35 36
};

/**
 * @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
    map< int, vector< Connection > > _connections_to_groups_map; //maps group ID to connections to said group
82
    map< int, vector< Connection > > _all_conns_by_type_map;
83

84 85 86 87 88
    // 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

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
    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
108
     * @param dest_gid the global ID of the destination router
109 110
     * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL
     */
111
    void add_connection(int dest_gid, ConnectionType type);
112

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    // /**
    //  * @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)

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 177 178 179
    /**
     * @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);

180 181 182 183 184 185
    /**
     * @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);

186 187 188 189 190
    /**
     * @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
     */
191
    vector< Connection > get_connections_to_gid(int dest_id, ConnectionType type);
192 193 194 195 196 197

    /**
     * @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);
198

199 200 201 202 203 204 205
    /**
     * @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);

206 207 208 209 210 211
    /**
     * @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();

212 213 214 215 216
    /**
    *
    */
    void solidify_connections();

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
    /**
     * @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;
}

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

    switch (type)
    {
        case CONN_LOCAL:
258 259 260 261 262 263 264
            if (intraGroupConnections.size() < _max_intra_ports) {
                conn.port = this->get_used_ports_for(CONN_LOCAL);
                intraGroupConnections[conn.dest_lid].push_back(conn);
                _used_intra_ports++;
            }
            else
                tw_error(TW_LOC,"Attempting to add too many local connections per router - exceeding configuration value: %d",_max_intra_ports);
265 266 267
            break;

        case CONN_GLOBAL:
268 269 270 271 272 273 274
            if(globalConnections.size() < _max_inter_ports) {
                conn.port = _max_intra_ports + this->get_used_ports_for(CONN_GLOBAL);
                globalConnections[conn.dest_gid].push_back(conn);
                _used_inter_ports++;
            }
            else
                tw_error(TW_LOC,"Attempting to add too many global connections per router - exceeding configuration value: %d",_max_inter_ports);
275 276 277
            break;

        case CONN_TERMINAL:
278 279 280 281 282 283 284 285
            if(terminalConnections.size() < _max_terminal_ports){
                conn.port = _max_intra_ports + _max_inter_ports + this->get_used_ports_for(CONN_TERMINAL);
                conn.dest_group_id = _source_group;
                terminalConnections[conn.dest_gid].push_back(conn);
                _used_terminal_ports++;
            }
            else
                tw_error(TW_LOC,"Attempting to add too many terminal connections per router - exceeding configuration value: %d",_max_terminal_ports);
286 287 288 289 290 291 292
            break;

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

293
    if(conn.dest_group_id != conn.src_group_id)
294
        _other_groups_i_connect_to_set.insert(conn.dest_group_id);
295

296 297 298
    _portMap[conn.port] = conn;
}

299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
// 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;
// }

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
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)
{
338
    vector< Connection > conns = this->get_connections_to_gid(dest_id, type);
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 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409

    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");
    }
}

410 411 412 413 414 415 416
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)
417 418 419 420
{
    switch (type)
    {
        case CONN_LOCAL:
421
            return intraGroupConnections[dest_gid%_num_routers_per_group];
422
        case CONN_GLOBAL:
423
            return globalConnections[dest_gid];
424
        case CONN_TERMINAL:
425
            return terminalConnections[dest_gid];
426 427 428 429 430 431
        default:
            assert(false);
            // TW_ERROR(TW_LOC, "get_connections(type): Undefined connection type\n");
    }
}

432 433
vector< Connection > ConnectionManager::get_connections_to_group(int dest_group_id)
{
434
    return _connections_to_groups_map[dest_group_id];
435 436
}

437 438 439
vector< Connection > ConnectionManager::get_connections_by_type(ConnectionType type)
{
    switch (type)
440 441 442 443 444 445 446 447 448 449 450 451 452
        {
            case CONN_LOCAL:
                return _all_conns_by_type_map[CONN_LOCAL];
                break;
            case CONN_GLOBAL:
                return _all_conns_by_type_map[CONN_GLOBAL];
                break;
            case CONN_TERMINAL:
                return _all_conns_by_type_map[CONN_TERMINAL];
                break;
            default:
                tw_error(TW_LOC, "Bad enum type\n");
        }
453 454
}

455 456
vector< int > ConnectionManager::get_connected_group_ids()
{
457 458 459 460 461
    return _other_groups_i_connect_to;
}

void ConnectionManager::solidify_connections()
{
462
    //-- other groups connect to
463
    set< int >::iterator it;
464
    for(it = _other_groups_i_connect_to_set.begin(); it != _other_groups_i_connect_to_set.end(); it++)
465
    {
466
        _other_groups_i_connect_to.push_back(*it);
467
    }
468

469
    //--connections to group
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
    for(it = _other_groups_i_connect_to_set.begin(); it != _other_groups_i_connect_to_set.end(); it++)
    {
        int dest_group_id = *it;

        vector< Connection > conns_to_group;
        map< int, vector< Connection > >::iterator itg = globalConnections.begin();
        for(; itg != globalConnections.end(); itg++) //iterate over each router that is connected to source
        {
            vector< Connection >::iterator conns_to_router;
            for(conns_to_router = (itg->second).begin(); conns_to_router != (itg->second).end(); conns_to_router++) //iterate over each connection to a specific router
            {
                if ((*conns_to_router).dest_group_id == dest_group_id) {
                    conns_to_group.push_back(*conns_to_router);
                }
            }
        }

        _connections_to_groups_map[dest_group_id] = conns_to_group;
    }
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517

    //--get connections by type

    map< int, vector< Connection > > theMap;
    for ( int enum_int = CONN_LOCAL; enum_int != CONN_TERMINAL + 1; enum_int++ )
    {
        switch (enum_int)
        {
            case CONN_LOCAL:
                theMap = intraGroupConnections;
                break;
            case CONN_GLOBAL:
                theMap = globalConnections;
                break;
            case CONN_TERMINAL:
                theMap = terminalConnections;
                break;
            default:
                tw_error(TW_LOC, "Bad enum type\n");
        }

        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());
        }
        _all_conns_by_type_map[enum_int] = retVec;
    }    
518
}
519

520

521 522 523 524 525 526 527 528
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++)
    {
529
        if ( (ports_printed == 0) && (_used_intra_ports > 0) )
530 531 532 533
        {
            printf(" -- Intra-Group Connections -- \n");
            printf("  Port  |  Dest_ID  |  Group\n");
        }
534
        if ( (ports_printed == _used_intra_ports) && (_used_inter_ports > 0) )
535 536 537 538
        {
            printf(" -- Inter-Group Connections -- \n");
            printf("  Port  |  Dest_ID  |  Group\n");
        }
539
        if ( (ports_printed == _used_intra_ports + _used_inter_ports) && (_used_terminal_ports > 0) )
540 541 542 543 544
        {
            printf(" -- Terminal Connections -- \n");
            printf("  Port  |  Dest_ID  |  Group\n");
        }

545 546 547 548
        int port_num = it->first;
        int group_id = it->second.dest_group_id;

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

554 555 556 557
        } 
        else if (get_port_type(port_num) == CONN_GLOBAL) {
            id = it->second.dest_gid;
            printf("  %d   ->   %d        :  %d     -  GLOBAL\n", port_num, id, group_id);
558
        }
559
        else if (get_port_type(port_num) == CONN_TERMINAL) {
560
            id = it->second.dest_gid;
561
            printf("  %d   ->   %d        :  %d     -  TERMINAL\n", port_num, id, group_id);
562 563
        }
            
564 565 566 567
        ports_printed++;
    }
}

568 569


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